在多线程的状况下,因为同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题。Java语言提供了专门机制以解决这种冲突,有效避免了同一个数据对象被多个线程同时访问。java
wait与notify是java同步机制中重要的组成部分。结合与synchronized关键字使用,能够创建不少优秀的同步模型。
synchronized(this){ }等价于publicsynchronized void method(){.....}
同步分为类级别和对象级别,分别对应着类锁和对象锁。类锁是每一个类只有一个,若是static的方法被synchronized关键字修饰,则在这个方法被执行前必须得到类锁;对象锁类同。
首先,调用一个Object的wait与notify/notifyAll的时候,必须保证调用代码对该Object是同步的,也就是说必须在做用等同于synchronized(obj){......}的内部才可以去调用obj的wait与notify/notifyAll三个方法,不然就会报错:
java.lang.IllegalMonitorStateException:current thread not owner
在调用wait的时候,线程自动释放其占有的对象锁,同时不会去申请对象锁。当线程被唤醒的时候,它才再次得到了去得到对象锁的权利。
因此,notify与notifyAll没有太多的区别,只是notify仅唤醒一个线程并容许它去得到锁,notifyAll是唤醒全部等待这个对象的线程并容许它们去得到对象锁,只要是在synchronied块中的代码,没有对象锁是步履维艰的。其实唤醒一个线程就是从新容许这个线程去得到对象锁并向下运行。多线程
notifyAll,虽然是对每一个wait的对象都调用一次notify,可是这个仍是有顺序的,每一个对象都保存这一个等待对象链,调用的顺序就是这个链的顺序。其实启动等待对象链中各个线程的也是一个线程,在具体应用的时候,须要注意一下。oracle
wait(),notify(),notifyAll()不属于Thread类,而是属于Object基础类,也就是说每一个对像都有wait(),notify(),notifyAll()的功能。由于都个对像都有锁,锁是每一个对像的基础,固然操做锁的方法也是最基础了。this
wait():spa
等待对象的同步锁,须要得到该对象的同步锁才能够调用这个方法,不然编译能够经过,但运行时会收到一个异常:IllegalMonitorStateException。.net
调用任意对象的 wait() 方法致使该线程阻塞,该线程不可继续执行,而且该对象上的锁被释放。线程
notify():对象
唤醒在等待该对象同步锁的线程(只唤醒一个,若是有多个在等待),注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM肯定唤醒哪一个线程,并且不是按优先级。blog
调用任意对象的notify()方法则致使因调用该对象的 wait()方法而阻塞的线程中随机选择的一个解除阻塞(但要等到得到锁后才真正可执行)。进程
notifyAll():
唤醒全部等待的线程,注意唤醒的是notify以前wait的线程,对于notify以后的wait线程是没有效果的。
一般,多线程之间须要协调工做:若是条件不知足,则等待;当条件知足时,等待该条件的线程将被唤醒。在Java中,这个机制的实现依赖于wait/notify。等待机制与锁机制是密切关联的。
例如:
synchronized(obj) {
while(!condition) {
obj.wait();
}
obj.doSomething();
}
当线程A得到了obj锁后,发现条件condition不知足,没法继续下一处理,因而线程A就wait()。
在另外一线程B中,若是B更改了某些条件,使得线程A的condition条件知足了,就能够唤醒线程A :
synchronized(obj) {
condition = true;
obj.notify();
}
须要注意的概念是:
# 调用obj的wait(), notify()方法前,必须得到obj锁,也就是必须写在synchronized(obj){...} 代码段内。
# 调用obj.wait()后,线程A就释放了obj的锁,不然线程B没法得到obj锁,也就没法在synchronized(obj){...} 代码段内唤醒A。
# 当obj.wait()方法返回后,线程A须要再次得到obj锁,才能继续执行。
#若是A1,A2,A3都在obj.wait(),则B调用obj.notify()只能唤醒A1,A2,A3中的一个(具体哪个由JVM决定)。
#obj.notifyAll()则能所有唤醒A1,A2,A3,可是要继续执行obj.wait()的下一条语句,必须得到obj锁,所以,A1,A2,A3只有一个有机会得到锁继续执行,例如A1,其他的须要等待A1释放obj锁以后才能继续执行。
# 当B调用obj.notify/notifyAll的时候,B正持有obj锁,所以,A1,A2,A3虽被唤醒,可是仍没法得到obj锁。直到B退出synchronized块,释放obj锁后,A1,A2,A3中的一个才有机会得到锁继续执行。
谈一下synchronized和wait()、notify()等的关系:
1.有synchronized的地方不必定有wait,notify
2.有wait,notify的地方必有synchronized.这是由于wait和notify不是属于线程类,而是每个对象都具备的方法,并且,这两个方法都和对象锁有关,有锁的地方,必有synchronized。
另外,注意一点:若是要把notify和wait方法放在一块儿用的话,必须先调用notify后调用wait,由于若是调用完wait,该线程就已经不是currentthread了。
本文转自http://blog.csdn.net/oracle_microsoft/article/details/6863662