Java多线程:wait()和notify()方法详解
通过前面的内容我们知道,当一个线程正在执行某个对象中被synchronized关键字修饰的方法时,这个对象锁上,其他线程必须等到当前线程执行完后才能访问。
这个整个过程可以用下图来表示
一个正在运行的线程想要执行synchronized方法,必须要获得当前对象的锁,如果没有获得则当前对象的锁则会被阻塞在对象锁池当中,直到前一个线程释放了该对象锁,当前线程重新获取到对象锁时,线程恢复到可运行状态,当cpu给它资源时,线程将处于运行状态。
有上图可见,对于多个线程执行一个synchronized方法,我必须在当前线程执行完后,后面的线程才有机会访问该方法。那如果我就是想在前一个线程执行方法过程中停下来,转而让当前线程执行该方法时,该怎么办?
这个时候我们就需要使用 wait() 和 notify() 方法了。
在Object.java中,定义了wait(), notify()和notifyAll()等接口。wait()的作用是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁。而notify()和notifyAll()的作用,则是唤醒当前对象上的等待线程;notify()是唤醒单个线程,而notifyAll()是唤醒所有的线程。
Object类中关于等待/唤醒的API详细信息如下:
notify() -- 唤醒在此对象监视器上等待的单个线程。
notifyAll() -- 唤醒在此对象监视器上等待的所有线程。
wait() -- 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法”,当前线程被唤醒(进入“就绪状态”)。
wait(long timeout) -- 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量”,当前线程被唤醒(进入“就绪状态”)。如果 timeout 为零,则不考虑实际时间,在获得通知前该线程将一直等待。
wait(long timeout, int nanos) -- 让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量”,当前线程被唤醒(进入“就绪状态”)。
所以上面的整个流程描述如下:
如果当前线程正执行某个synchronized方法时,在synchronized方法内遇到了wait()方法,这时当前线程将阻塞在对象等待池中同时释放掉该对象锁,在对象锁池中等待的线程将争取获得此锁,获得锁的线程将回到Runnable状态。当某个线程调用notify()或者notifyAll方法时()在等待池中的线程将被唤醒,进入到锁池中等待获取锁。(线程调用了notify()或notifyAll()方法时并不会释放锁,并不能让处于wait中的线程立刻执行,只是将其唤醒进入锁池等待获取锁)
先调用notify()方法,然后在调用wait()方法。这时从notify()到wait()方法之间的这一段代码仍会执行,原因就是:虽然调用notify(),但另外的线程没有获得锁,它还在对象锁池中待着,直到当前线程执行wait()方法释放当前锁才会执行它的方法。
wait与notify方法都是定义在Object类中,而且是final的,因此会被所有的Java类所继承并且无法重写。这两个方法要求在调用时线程应该已经获得了对象的锁,因此对这两个方法的调用需要放在synchronized方法或块当中。当线程执行了wait方法时,它会释放掉对象的锁。
另一个会导致线程暂停的方法就是Thread类的sleep方法,它会导致线程睡眠指定的毫秒数,但线程在睡眠的过程中是不会释放掉对象的锁的。
看一个例子
1 public class Sample 2 { 3 private int number; 4 5 public synchronized void increase() 6 { 7 while (0 != number) 8 { 9 try 10 { 11 wait(); 12 } 13 catch (InterruptedException e) 14 { 15 e.printStackTrace(); 16 } 17 } 18 19 number++; 20 21 System.out.println(number); 22 23 notify(); 24 } 25 26 public synchronized void decrease() 27 { 28 while (0 == number) 29 { 30 try 31 { 32 wait(); 33 } 34 catch (InterruptedException e) 35 { 36 e.printStackTrace(); 37 } 38 } 39 40 number--; 41 42 System.out.println(number); 43 44 notify(); 45 } 46 }
1 public class MainTest 2 { 3 public static void main(String[] args) 4 { 5 Sample sample = new Sample(); 6 7 Thread t1 = new IncreaseThread(sample); 8 Thread t2 = new DecreaseThread(sample); 9 10 Thread t3 = new IncreaseThread(sample); 11 Thread t4 = new DecreaseThread(sample); 12 13 t1.start(); 14 t2.start(); 15 t3.start(); 16 t4.start(); 17 } 18 }
打印结果为0/1交替出现。
posted on 2016-04-19 15:39 Traveling_Light_CC 阅读(354) 评论(0) 编辑 收藏 举报