java 多线程简述(二)

2014-11-24 02:35:59 · 作者: · 浏览: 1
ong delay,long period)安排指定的任务在指定的延迟后开始进行重复的固定速率执行.

public class EggTimer {  
    private final Timer timer = new Timer();
    private final int minutes;
    public EggTimer(int minutes) {
       this.minutes = minutes;
    }
    public void start() {
       timer.schedule(new TimerTask() {
           public void run() {
               playSound();
              // timer.cancel();
            }
           private void playSound() {
               System.out.println("Your egg is ready!");
                // Start a new thread to play a sound...
            }
       }, 0,minutes * 60 * 1000);//几分钟执行一次
    }
   public static void main(String[] args) {
       EggTimer eggTimer = new EggTimer(2);
       eggTimer.start();
    }
}


同步代码块

为了保证线程能正常的执行原子操作,java引入了同步机制,在代码原子操作的程序代码前加上synchronized标记 ,这样,任何时刻只允许一个线程拥有这把锁,

这样当加了同步标记后,其他待进入线程放到Stack对象锁池中,线程进入阻塞状态。加锁方式如下:

Public synchronized String pop(){…}

也可以写作

Public String pop(){

Synchronized(this){…}

}

下面看一个消费者,创造者的例子

public class SyncTest {
    public static void main(String[] args) {
       Stack stack =new Stack("stack");
       Producer producer1=new Producer(stack,"producer1");
       Consumer consumer1=new Consumer(stack,"consumer");
    }
}
class Producer extends Thread{
       private Stack theStack;
       public Producer(Stacks,String name){
          super(name);
          theStack = s;
          start();
       }
       public void run(){
          String goods;
          for(int i=0;i<20;i++){
              goods="goods"+(theStack.getPoint()+1);
              theStack.push(goods);
              System.out.println(getName()+": push "+goods+" to "+theStack.getName());
              yield();
          }
       }
}
class Consumer extends Thread{
       private Stack theStack;
       public Consumer(Stacks,String name)
       {
          super(name);
          theStack=s;
          start();
       }
       public void run(){
          String goods;
          for(int i =0;i<20;i++){
              goods=theStack.pop();
              System.out.println(getName()+":pop "+goods+" from "+theStack.getName());
              yield();
          }
       }
}
    class Stack{
       private  String name;
       private String[] buffer=new String[100];
       int point = -1;
       public Stack(String name){this.name=name;}
       public String getName(){return name;}
       public int getPoint(){return point;}
       public synchronized String pop(){
           String goods=buffer[point];
           buffer[point]=null;
           Thread.yield();
           point --;
           return goods;
       }
       public synchronized void push(String goods){
           point ++;
           Thread.yield();
           buffer[point] =goods;
       }
    }


同步和并发问题

同步锁解决资源共享资源竞争的有效手段,当一个线程已经操作共享资源,其他线程只有等待,只有当已经在操作共享资源的线程执行完毕后才能同步代码块,其他线程才能有机会共享。

以打水为例子,10个去打水,每人要打10桶,使用同步方式为,一个人打完10桶后,其他人才有机会打水,,当一个人打水,其他人必须等待,显然不合理。

public class Person extends Thread{
private Well well;
public Person (Well well){
    this.well=well;
    start();
}
public void run(){
    synchronized(well){
       for(int i=0;i<10;i++){
           well.withdraw();
           yield();
       }
      
    }
}
    /**
     * @param args
     */
    public static void main(String[] args) {
       Well well=new Well();
       Person persons[]=new Person[10];
       for(int i=0;i<10;i++){
           persons[i]=new Person(well);
       }
 
    }
 
}
class Well{
    private int water=100;
    public void withdraw(){
       water --;
       System.out.println(Thread.currentThread().getName()+": water left:"+water);
    }
}


则我们把同步锁加在withdraw(),则可以解决问题,例:

public class Person extends Thread{
private Well well;
public Person (Well well){
    this.well=well;
    start();
}
public void run(){
   
       for(int i=0;i<10;i++){
           well.withdraw();
           yield();
       }
}
    public static void main(String[] args) {
       Well well=new Well();
       Person persons[]=new Person[10];
       for(int i=0;i<10;i++){
           persons[i]=new Person(well);
       }
    }
}
class Well{
    private int water=100;
    public synchronized void withdraw(){
       water --;
       System.out.println(Thread.currentThread().getName()+": water left:"+water);
    }
}


线程安全类

一个线程安全类必须满足以下条件:

1、 这个类可以同时被多个线程安全访问。

2、 每个线程都能正常执行原子操作,得到正确结果。

3、 原子操作万仇,对象处于逻辑是合理状态。

如上我们使用的Stack类就是可变类,point和buffer都可以发生变化,会造成共享资源的竞争。

线程之间的通信

不同线程之间执行不同的任务,如果任务有某种联系,必须实现通信功能,协调完成工作。

Java.lang.object类提供了用于线程通信的方法:

1、 wait(),该方式的线程释放对象锁,虚拟机把该对象放到等待池中,等待其他线程唤醒。

2、 notify(),该方法唤醒在等待池中的线程,虚拟机从等待池中随机选择一个线程.

3、 notifyAll()方法用于把对象池中所有的线程都转到对象锁池中。

例t1线程和t2线程可用wait和notify进行通信。

编程的方式控制线程

实际编程中,一般是在受控的线程中定义一个标志量,其他线程通过改变标准变量的值,来控制线程的暂停、恢复运行已经自然终止,jdk1.2开始一些废弃了一些停止线程的方法

suspend() 使线程暂停;

resume() 暂停的线程恢复运行;

stop() 终止线程;

废弃的原因大概由于以上几个方法容易导致死锁等。

ThreadLocal类

java.lang.ThreaLocal一般用来存放线程的局部变量,每个线程一般都有单独的局部变量,彼此 之间不会共享,该类主要有三个方法:

1、 public T get() 返回巨变线程的变量。

2、 protected T initialValue() 返回局部变量的初始值;

3、 public void set(T value) 设置当前线程的局部变量;

其实看看TheadLocal的源码,我们可以发现他的思路,在类中有一个Map缓存,用于存储每个线程的局部变量,例:

package com.bin.duoxiancheng;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public class ThradLocal
  
    {
  private Map
   
     values= Collections.synchronizedMap(new HashMap
    
     ()); public T get(){ Thread cuThread = Thread.currentThread(); T o=values.get(cuThread); if(o ==null && !values.containsKey(cuThread)){ o=initValue(); values.put(cuThread, o); } return o; } public void set(T newValue){ values.put(Thread.currentThread(), newValue); } protected T initValue(){ return null; } } 
    
   
  


以上程序仅仅实现了总体思路,细节上ThreadLocal类实现的更健壮,还保证了线程结束后,从Map缓存中删除这个线程的局部变量的引用。