回顾一个比较经典的线程间协做的问题:启动三个线程,每一个线程相应的打印10遍A,10遍B,10遍C。要求三个线程交替执行,输处10遍ABC。java
用Object类的notify(), wait()方法可实现上述要求。ide
Object.notify()能够唤醒一个线程,使之进入就绪状态,等待获取对象锁后运行。this
Object.wait()方法可使一个线程进入阻塞状态,而后释放对象锁,等待被notify()方法唤醒。spa
由于notify()和wait()方法都跟对象锁相关,因此必须在同步块里面被调用才有效。即都是以下形式:线程
synchronized(Obj){ try{ Obj.wait(); } catch (Exception e){ ... } Obj.notify; }
回看题目自己。要交替打印A,B,C,创建须要三个线程,三个对象。单个打印时,线程须要获得两个对象锁。code
public class WatiNotifyTest { public static void main(String[] args) { Object obj1 = new Object(); Object obj2 = new Object(); Object obj3 = new Object(); MyThread myThread1 = new MyThread("A", obj1, obj2); MyThread myThread2 = new MyThread("B", obj3, obj1); MyThread myThread3 = new MyThread("C", obj2, obj3); myThread1.start(); myThread2.start(); myThread3.start(); } } class MyThread extends Thread { private String name; private Object a; private Object b; public MyThread(String name, Object a, Object b){ this.name = name; this.a = a; this.b = b; } @Override public void run() { int count = 10; while(count > 0){ synchronized(a){ synchronized (b) { System.out.println(name);//print "A" or "B" or "C". count--; /****************/ try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } /****************/ b.notify();//wake up the thread which is waiting for the lock of "b". } try { a.wait();//let current thread release the lock on a. } catch (InterruptedException e) { e.printStackTrace(); } } } } }
线程对象MyThread的run方法会执行10次循环,每次循环都打印出当前线程的name(A或B或C)。而两个synchronized块是实现交替打印的关键。对象
从main方法入手。创建三个对象,obj1,ojb2,obj3,共有三把对象锁。线程myThread1启动,执行myThread1的run方法。同理,myThread2,myThread3启动,执行各自的run方法。对于myThread1来讲,a就是obj1,b就是obj2。同理,对于myThread2来讲,a就是obj3,b就是obj1。以下是程序运行步骤:资源
一、myThread1进入while循环,进入synchronized块。myThread1得到了obj1和obj2两个对象锁。而后输出"A",sleep 10毫秒。调用obj2.notify(),唤醒在等待obj2的线程;调用obj1.wait(),释放obj1的锁。同步
二、在上述myThread1执行的过程当中,myThread2进入while循环,然而它暂时只能进入第一个synchronized块,由于它须要obj1的锁才能进入第二个synchronized块,而此时obj1的锁在myThread1手中。当myThread1调用obj1.wait()以后,myThread2进入第二个synchronized块,得到obj3和obj1两个对象锁,而后输出"B",sleep 10毫秒,调用obj1.notify(),唤醒在等待obj1的线程;调用obj3.wait(),释放obj3的锁.it
三、在myThread1执行完obj2.notify()并退出第二个synchronized块的时候,myThread3获得了obj2的对象锁,进入第一个synchronized块。当myThread2执行完obj3.wait()以后,得到obj3的对象锁,进入第二个synchronized块。而后输出"C",sleep 10毫秒。调用obj3.notify(),唤醒在等待obj3的线程;调用obj2.wait(),释放obj2的锁。
四、myThread1在第一次循环执行完后进入waiting状态,等待的是obj1的锁,以便进入第一个synchronized块。而当myThread2执行完毕的时候,调用了obj1.notify(),此时myThread1再次进入第一个synchronized块。等待myThread3执行完obj2.wait()释放obj2的锁以后,myThread1进入第二个synchronized块。而后重复1,2,3,4的步骤。
代码中/*****/之间的部分很重要,它保证了三个线程的执行顺序不受JVM随机调度的影响。
从上面例子能够看出,wait()和notify()方法,主要是控制对象的使用权的。notify()至关于告诉在waiting状态的线程说,某某资源我已经用完了,你能够来使用了。wait()方法至关于自动让出资源的使用权,进入阻塞状态(相似sleep,可是sleep会保留对象锁)。
注意wait()和notify()通常是一块儿使用的。在调用了Object.wait()的线程,只有在Object.notify()被调用以后,才能再次进入就绪状态,等待调度。