翻译自jls8.pdf的17.2节,原文文档http://download.csdn.net/detail/admiral_dota/9387074
17.2 Wait Sets and Notification
每个对象,除了有一个关联的监视器之外,还有一个关联的wait集合。这个集合是一个线程的集合。
当一个线程初始创建的时候,它的wait集合是空的。把线程加入集合和把线程从集合中删除的基本操作是原子的。wait集合只有通过Object.wait,Object.notify,Object.nofifyAll方法来操作。
wait集合的操作也会被线程的中断状态和Thread类处理中断的类方法影响。另外,Thread类的sleep和join方法有由wait和notify动作影响的属性(the
Thread class's methods for sleeping and joining other threads have properties derived from those of wait and notification actions,括号中为原文)。
17.2.1 Wait
wait动作在wait(),wait(long millisecs) 或者wait(long millisecs,int nanosecs)方法调用时发生。
wait(long millisecs)在参数为0或wait(long millisecs,int nanosecs)在两个参数为0时,等价于调用wait()
wait返回时没有抛出InterruptedException时,线程会从wait正常返回。
假设线程t是在object m上执行wait方法的线程,n是线程t在m上执行的没有被unlock的lock操作的个数,会发生下面的结果:
如果n是0(也就是线程t没有对m执行lock操作),那么会抛出IllegalMonitorStateException
如果是带时间的wait方法,并且nanosecs参数不在0-999999之间或者millisecs为负数,那么会抛出IllegalArgumentException
如果线程t被中断,那么抛出InterruptedException,并且设置中断状态为false。
否则,下面的动作按顺序发生:
1.线程t被添加到object m的wait集合,并且线程t在m上执行n个unlock动作
2.直到线程t被从m 的wait集合移除前,线程t不会执行任何进一步的指令。以下的任何一种情况可能会导致线程从wait集合中被移除,并在之后的某个时候恢复:
-在t被选中移除的m上的一个notify动作被执行。
-m上的一个notifyAll动作被执行。
-线程t被中断
-如果是带time的wait,从wait发生开始,经过millisecs毫秒加nanosecs微秒后,t会被从m的wait集合中移除。
-一个内部实现。虽然不鼓励,但是允许这种实现来执行"伪造的唤醒",也就是从wait集合中移除线程并恢复执行而不需要显示的指令。
注意,这使得java代码必须在循环中使用wait直到线程等待的逻辑条件发生
每个线程必须确定一个会导致它被从wait集合中移除的时间的顺序。这个顺序不必和其它顺序一致,但是这个线程必须表现出那些事件是按照确定的顺序发生的。
例如,如果线程t在m的wait集合中,线程t的中断和m的notify都发生了,这些事件必须有一个顺序。如果中断先发生的,那么t会返回并抛出InterruptedException,并且m的wait集合中的其它的线程(如果有的话)必须受到这个notify。如果notify动作先发生,那个t会从wait中正常返回并且中断保持挂起
3.线程t在m上执行n个lock动作
4.如果线程t在步骤2中因为中断导致从m的wait集合中移除,那么t的中断状态被设置为false,并且wait方法抛出InterruptedException
17.2.2 Notification
通知在notify或者notifyAll方法调用的时候发生。
假设线程t是在object m上执行notify或者notifyAll的线程,n是线程t在m上的没有被unlock的lock操作的次数。下面的操作之一会发生:
-如果n为0,会抛出IllegalMonitorStateException。这种情况是线程t还没有获得m的锁。
-如果n大于0并且这是一个notify操作,那么m的wait集合不为空,m的wait集合中的一个线程u会被选中从wait集合中移除。
对于wait集合中的哪个进程会被选中,没有任何的保证。从wait集合中把u移除会使u从等待状态恢复执行。但是注意直到t完全从m上unlock之前,u的lock动作都不会成功。
-如果n大于0并且是notifyAll操作,那么所有的线程都会从m的wait集合中移除并恢复。
注意,在从wait恢复时,这些线程中同时只有能获取监视器上的锁。
17.2.3 Interruptions
Thread.interrupt以及ThreadGroup.interrupt方法调用的时候发生中断。
假设t调用线程u的u.interrupt,t和u可以是同一个线程。这个操作会导致u的中断状态设置为true。
另外,如果存在一个object m,它的wait集合中包括u,那么u被从m的wait集合中移除。这使u从wait状态中恢复执行,这种情况下wait在重新lockm的监视器后,会抛出InterruptedException(action, in which case this wait will, after re-locking m's monitor, throw InterruptedException)。
调用Thread.isInterrupted可以检查一个线程的中断状态。静态方法Thread.interrupted可以被一个线程调用用来观察并清除它自己的中断状态。
17.2.4 Interactions of Waits, Notification, and Interruption
以上部分允许我们检测几个与waits,notification,interruption交互相关的性。
如果一个线程在中断的时候被notify和interrupt,会发生下面的之一:
-从wait中正常返回,interrupt继续保持(也就是说,Thread.interrupted会返回true)
-从wait返回,并抛出InterruptedException
这个线程可能不会重置它的中断状态并从wait中正常返回。
类似的,由于中断,notify不会丢失。假设一个object m的wait集合s中有一些线程,其它线程在m上执行了一个notify操作,下面的两者之一会发生:
-s中至少有一个线程会正常从wait中返回,否则
-s中的所有线程退出wait并抛出InterruptedException
注意如果一个线程同时被中断和通过notify唤醒,并且这个线程从wait返回时抛出InterruptedException,那么wait集合中一定要有其它线程能被notifed