线程以及数据对象的wait()和notifyAll()方法
正在运行的程序称作一个进程,一个进程可以包含多个线程,这些线程可以共享进程的资源,它们共用一块存储空间。那么,各个线程在访问同一个数据对象的同时,可能引起冲突,以生产者、消费者为例,就会出现队列中没有产品的情况下,消费者扔到队列中去拿产品,与现实世界中逻辑不相符合。使用synchronized关键字可以确保线程的安全运行。
synchronized(obj){
.......
obj.wait()/notifyAll();//是数据对象而不是线程调用wait和notifyAll方法
}
当给一个线程(比如A线程)的run方法体内加入上述代码时,说明A线程必须首先获得该数据对象的锁,才能对这个对象进行操作。A线程拿到这个obj数据对象的锁以后,在它释放以前任何其它线程都不能够操作此对象了,之所以这样,我们可以认为其它线程没有这把锁的钥匙。A线程执行obj.wait()方法后,它将释放其所占有的对象锁,A线程进入阻塞状态,同时A也就不具有了获得obj对象所的权力,这样其它线程就可以拿到这把锁了。obj.notifyAll()可以唤醒因obj对象而阻塞的所有线程,并允许它们有获得对象所的权力,obj.notify()是唤醒因obj对象而阻塞的任意一个线程。
下面的程序模仿生产者和消费者:
public class WaitAndNotify { private static List<Double> queue; public WaitAndNotify(){ queue = new ArrayList<Double>(); } public void begin(){ Thread producer = new Thread(){ public void run(){ while(true){ synchronized(queue){ double time = 1.0d; long startTime = System.currentTimeMillis(); if(System.currentTimeMillis()-startTime>=time){ startTime =System.currentTimeMillis(); for(int i=0;i<10;i++){ queue.add((Math.random()*10000)); } queue.notifyAll(); } } } } }; producer.start(); Thread consumer = new Thread(){ public void run(){ while(true){ synchronized(queue){ while(queue.isEmpty()){ System.out.println("队列的长度为:"+queue.size()); try { queue.wait(); } catch (InterruptedException ex) { Logger.getLogger(WaitAndNotify.class.getName()).log(Level.SEVERE, null, ex); } } double result = queue.remove(0); System.out.println("成功从队列中取到数据!"+result); } } } }; consumer.start(); } public static void main(String[] args){ WaitAndNotify obj = new WaitAndNotify(); queue.add(0.1231d); obj.begin(); } }
producer线程向queue中放入数据,并掉调用queue.notifyAll()来唤醒所有阻塞的线程,consumer线程从queue中取数据,当没有数据时该线程就会进入阻塞状态,等待呗唤醒。