序言:每一个java对象都有一个lock状态,synchronized method 获取的就是 this对象的object lock(权威)
________________________________________________________________________________________________
等待_通知机制的工作意义:
某个线程(thread1)的run()方法的方法体运行中需要等待一个特定条件(信号量)的出现(或信号量条件的激活),并假设有其他的线程(thread2,3,...)会在其run()方法中创建该条件(设定激活该信号量),那么当另外的一个线程(thread2,3...)创建(创造)该条件(激活了该信号量)时,它会通知前面正在等待该条件的那个thread1。Java语言系统中通过这种等待_通知机制实现了线程之间的通信.
Can the wait-and-notify mechanism be used to replace the synchronized mechanism? Actually, the answer is no; wait-and-notify does not solve the race condition problem that the synchronized mechanism solves. As a matter of fact, wait-and-notify must be used in conjunction with the synchronized lock to prevent a race condition in the wait-and-notify mechanism itself.
等待和通知机制可以用来取代同步机制吗?事实上,答案是否定的;wait and notify不能解决同步机制解决的竞争条件问题。事实上,wait and notify必须与同步锁一起使用,以防止wait and notify机制本身出现竞争情况。
______________________________________________________________________________________________________________________________________________________
wait(),notify()与Object类
Java系统中的每一个对象都有两个成员方法wait()与notify(),这两个方法来自于超类Object,又因为Object类是所有Java 对象的超级祖类(Java系统中的所有对象都直接或者间接地继承自Object类,所以所有Java对象也都是Object类的一个instance)所以自然而然的所有Java 对象都会继承这两个来自其祖类的成员方法wait()和notify().
________________________________________________________________________________________________________________________________________________
等待-通知机制使用的目的为何?它又是如何运作的呢?
答案:等待与通知机制(wait-and-notify)它是一个用于同步的机制,同时,它更是一个通信机制(好好理解这句话!),为什么这么说呢?因为wait-and-notify能够使某个线程(thread1)和其他线程(thread2,thread3,..)在特定条件被符合(激活)(在特定条件符合时)(特定信号被激活时)进行相互通信.更有意思的是这个"等待与通知"机制并没有明确指定具体特定的条件(信号)(信号量)到底是什么(具体是什么)!(通读理解)(只是定义了一个信号而已)
等待和通知机制的目的是什么?它是如何工作的?等待和通知机制是一种同步机制。然而,它更像是一种通信机制:它允许一个线程与另一个线程进行通信,说明发生了特定情况。等待和通知机制没有指定具体情况。
_____________________________________________________________________________________________________________________________________________________
wait()方法的功能:
在某一个线程thread1中的run()方法中间接调用wait()方法则会使该thread1处于等待状态,这种等待状态现象是:调用了wait()方法的那个方法(method)会被阻塞(block)住,直到和该thread1具有竞争关系的同进程中的其他线程如thread2或threadn在其run()方法中间接显示调用了一个notify()方法,且该thread1真正接受到了该notify()方法所私下发送的“通知”信号量为止,该thread1中的那个被阻塞(blocked)住的那个方法(method)才能可以有够可以被继续执行的能力!(权威)
______________________________________________________________________________________________________________
wait()方法剖析:
直接写wait();来调用wait方法其实是个省略的写法,本质上其实是this.wait();这个wait()方法来自于超类Object。注意:wait()方法只能出现在synchronized method的方法体中,或者是synchronized(xxx){wait();或this.wait();} 块中,或者是利用 Lock interface所显示定义的同步代码块中(就是这么个固定死的用法),wait()方法的使用目的就是释放其所绑定的对象的lock(即同步锁),并阻塞掉调用该wait();方法的那个同步代码块(或同步方法synchronized methods)(或同步代码段)!(权威)!!并让其他的和调用了本同步方法(同步代码段,同步代码块)的那个thread1有竞争关系的thread2..threadn等其他线程有机会获得该前文提到的对象lock(对象锁)(同步互斥锁权)(同步锁),以使得该得到了前文提到的该lock(互斥锁)(同步锁)的那个thread2或threadn"可以有机会执行"其相对应的该被同步代码块(或同步方法 synchronized methods)(或同步代码段)!(权威),当且仅当thread2到threadn中某个抢到系统资源的那个threadx(一定不会是thread1(被阻塞的那个线程))中的run()方法中显示的调用了notify();(同一时刻互相竞争的thread中的run()方法中仅仅会有一个notify()方法会被成功调用,因此notify()方法必须被写在某同步代码块(或某同步方法synchronized methods)(或某同步代码段)之中),在其他线程thread2或threadn中的某个线程成功调用了notify();方法后,thread1会在一个不定的时间内获得一个"重新激活的一个隐式信号量"(这个不定时间取决于它能不能够抢到系统资源了以及其他thread之间的race condition问题),并且在wait()方法中被返回(调用wait()方法处返回),同时解除了对调用了该wait();方法的那个同步代码段(或同步方法)(或同步代码块)的阻塞!使之可以有机会被继续运行(从而达到解除对线程thread1阻塞的目的)(权威),同时得到该"激活通知信号量"的该thread1将重新获得前文所提到的那个在调用wait()方法时释放掉的lock(同步锁),从而使得原本调用了前文提到的那个wait()方法的同步代码块(或同步方法)(或同步代码段)由重新因具有了该同步锁(得到该同步互斥锁)而显现出那个原本被wait()方法阻塞了的同步代码段(或同步方法)(或同步代码块)继续独霸该同步锁权的被同步的功能效果!(权威)
____________________________________________________________________________________________________________
notify()方法剖析:notify()方法的功能是使与其相对应的wait()方法得到返回,并使得得该wait()方法所在的同步代码段重新获得该wait()所释放掉的那个同步互斥锁(lock)状态标记,且使得该wait方法在返回后不再阻塞调用了该wait()方法的那个同步程序代码段的执行!注意:当没有其他线程在其run()方法中调用过一个同步代码段程序中调用了wait()方法时,即wait()方法在其它线程中不存在时,在某一个thread(线程内)就漫无目的的调用notify()方法纯是白扯!因为基于wait-notify的等待-通知机制并不知道(也没有规定)关于所发生通知的条件,该机制会假设在没有其他线程中调用wait()方法的情况下,在另一个线程中调用notify()方法是无效的!即通知信号量是不会被任何线程所收到的!(权威)换言之:
如果在一个线程中调用了notify()方法,而没有其他的任何线程在该notify()方法被调用之前调用了wait()方法(即该notify()方法没有一个与之对应的(在其它线程中)调用的wait()方法相对应存在)则该notify()方法就是个形式它没有任何实际功效,它就只是做了一个返回void的空操作且通知的信号会遗失掉!而在其调用后却所在其它线程中调用了的"后置"wait()方法根本不会(不可能)接收到该(前置)notify()方法所发送的通知信号量.(权威)
______________________________________________________________________________________________________________________
总结:wait();方法会释放掉LOCK,wait();在接受到notify()方法所发送的信号量后会返回,在wait()方法返回之前它会重新获得该wait()方法之前所释放掉的那个lock标记(权威),
一个线程thread1被调用了wait()方法,则与该wait()方法所对应的notify()方法必须在其他threadx中调用而不能在相同的那个thread1中去调用,因为wait()方法会阻塞线程的继续执行(权威+通读理解),等待wait-通知notify机制更容易使用在大多数以信号为基础的同步范例上,且是很实用的!
__________________________________________________________________________________________________________________________________________
关于notifyAll()方法:
notifyall()方法也必须写在同步程序代码块(synchronized块中)(或者同步方法)(或者明确的同步代码段中)去使用,notifyAll()方法的作用是通知所有前置调用了wait()方法的其它线程,让其在其所调用wait()方法处,在该被"通知"的线程获得到了notifyAll()方法所发送的"再激活信号量"时让该wait()方法被返回,并重新获得该wait()方法所释放掉的原同步锁(lock),并且不再阻塞该线程的运行.即notifyAll()方法的作用是唤醒其他被阻塞的线程(使再次被激活!)
_____________________________________________________________________________________________________________________________________________________
是否notifyAll()方法真正地唤醒了其他所有调用了"前置"wait()方法的所有thread(线程)?答案:“不是”,你得辩证着理解且得好好的看准各种锁对象的获取与竞争资源的获得条件来判断!,首先所有调用了"前置"wait()方法的那些thread(线程)们都有权利等待notifyAll()方法所发送的"再次激活'信号量,至于哪些或是说哪个线程会得到"通知信号量"且会被唤醒(再次激活)那就不好说了,它是由多种因素决定的!比如说该得到了通知的线程,是否能够马上获得其所调用的wait()方法所释放掉的同步锁,该线程是否能够马上获取(竞争到)系统资源等,都是问题,因此不能确定该可能被再次唤醒的线程具体被唤醒的特定时间,因为这完全是个对资源的竞争问题,这就要看这个线程自己的命(本事)了!,所以我们无法控制哪个具体线程会得马上得到通知信号,因无法确定哪个线程会马上被再次激活并继续执行!所以对于这种情况系统会继续执行哪个被唤醒了的线程完全是不确定的事情!
_________________________________________
Condition 接口(条件变量接口):
在Java中,条件型对象变量是实现了Condition这个接口的对象,Condition这个接口(interface)是绑定在Lock这个接口(interface)上的,就好像等待(wait)-通知(notify)机制是绑定在同步锁对象机制上一样的!
——————————————————————————————————————————————————————————————————————————————
利用Lock类型对象获得Condition类型对象的范例代码:
Lock lockVar = new ReentrantLock();
Condition condVar=lockVar.newCondition();
Condition 类型对象的使用与等待(wait)-通知(notify)的使用方式与目的是类似的,就是以Condition类型对象的await()方法与signal()方法的调用分别代替wait()方法与notify()方法!即我们使用条件变量(Condition类型对象变量)的运行机制来修改程序以取代等待(wait)-通知(notify)机制以达到同样的目的(线程间的通过信号量的通信功能效果)
_____________________________________________________________________________________________________________________________________________________________
总结:基本上,Condition 接口所提供的API方法都是复制了等待(wait)-通知(notify)机制的功能,Condition所提供的少数便利的API方法更加细致,如能让开发者避免中断情况,或者能以相对或绝对时间来指定通知获取的时限。
比如说:Condition 所提供的 void awaitUninterruptibly()方法的调用就是不可能在其执行过程中被中断掉的,而boolean awaitUntil(Date deadline)方法就是指定在特定的时间点前在调用该awaitUntil()方法处还没有等到通知信号量,则该awaitUntil()方法将被返回,且返回值为false;
——————————————————————————————
void wait(long timeout, int nanos) Waits for a condition to occur. However, if the notification has not occurred in timeout milliseconds and nanos nanoseconds, it returns anyway. This method must be called from a synchronized method or block. Note that, just like the sleep() method, implementations of this method do not actually support nanosecond resolution. |
void notify() Notifies a thread that is waiting that the condition has occurred. This method must be called from within a synchronized method or block. |