java线程notify(), wait()的使用

回顾一个比较经典的线程间协做的问题:启动三个线程,每一个线程相应的打印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()被调用以后,才能再次进入就绪状态,等待调度。

相关文章
相关标签/搜索