日期:2014-05-20  浏览次数:20743 次

notifyAll之后???
对notifyAll有一个概念模糊的地方,请高人指教。
        项目来源于一个聊天室程序:在服务器端有一个静态的发言板(String类型),诸多用户连线后调用一个法(其中有一个synchronized块,用“发言板”做同步锁)进行发言(即同一时刻只能有一个用户发言),进入该方法后先wait(),然后把发言内容写到发言板上。
        服务器针对每个用户都有两个线程,一个是上述的听取用户发言的线程,另外一个线程用一个方法(其中有一个synchronized块,用“发言板”做同步锁)将目前发言板上的内容发送给每个用户,然后notifyAll()。
        这两个线程在逻辑上是完美的,保证了每个用户发言前都要等待,当服务器把目前发言板上的内容发送给用户后再唤醒用户的发言线程。

        问题在于notifyAll()后的线程调度机制,假设现在有5个用户在等待发言,他们都被同一把同步锁牵制。当其中一个用户发言,然后notifyAll()之后,原则上5个用户会被依次唤醒,并接收发言板上的内容。

        可是,若在3个用户接收发言板上的内容之后,这时新加进来一个用户,他刷新了发言板上的内容,那么剩下的两个用户不就丢失了之前发言板上的内容了吗?

        说到这里,我找到了我概念上的模糊之处。notifyAll()之后,5个被“发言板”这把锁牵制的线程是按照甚么顺序苏醒的呢?按照进入wait()的顺序?还是随机抽取一个?假如是后者的话,那么若在全部的等待队列苏醒前,如果有新的线程进入等待,那么它可能会先于剩余的线程而苏醒,这就会产生我上面担忧的问题。

------解决方案--------------------
看了你的示意代码,和我说的一样,是因为你的notifyAll()的时机不对,要实现你的设计意图,你必须在读取客户端发言到该发言发送给所有客户端这段时间一直持有同步锁。而你的示意代码却在接收到客户端的发言后马上就执行notifyAll()释放了同步锁,这样你在刷新客户端的时候就变成不可控的了,就会出现你说的问题。
事实上根据操作系统的不同,notifyAll()的唤醒后果是不可知的,他只能保证等待队列中的所有线程都被唤醒,至于谁能得到同步锁是不能保证的。