(Java)使用对象wait()和notify()实现线程安全

(Java)使用对象wait()和notify()实现线程安全,java,multithreading,concurrency,Java,Multithreading,Concurrency,我一直在寻找一种方法,让一个线程等待/休眠,直到另一个线程发出某种就绪的信号。等待的线程应该醒来,处理可用的数据,然后返回睡眠状态,直到另一个线程再次发出信号 我能找到的最简单的方法是Object.wait和Object.notify,其行为类似于初始化为值0的信号量。但是,如果notify/wait周围没有同步语句,当线程不是监视器所有者时,Java总是抛出IllegalMonitorStateException。因此,我只是将它们放在如下所示的代码中 线程1:运行无限循环 公共班机{ pri

我一直在寻找一种方法,让一个线程等待/休眠,直到另一个线程发出某种就绪的信号。等待的线程应该醒来,处理可用的数据,然后返回睡眠状态,直到另一个线程再次发出信号

我能找到的最简单的方法是Object.wait和Object.notify,其行为类似于初始化为值0的信号量。但是,如果notify/wait周围没有同步语句,当线程不是监视器所有者时,Java总是抛出IllegalMonitorStateException。因此,我只是将它们放在如下所示的代码中

线程1:运行无限循环

公共班机{ private Handler;//仅一个实例单例模式 公众虚空聆听{ 虽然是真的{ 试一试{ 同步处理程序{ handler.wait; int value=handler.getSize; //做点什么 } }捕捉中断异常e{ // ... } } } } 线程2:其他一些类调用removeItem

公共类处理程序{ //单例模式-仅一个实例 私有ArrayList共享列表; 私人经办人{ sharedList=新的ArrayList; } 公共void additemi{ 同步共享列表{ //添加到列表中 } } 公共无效删除一{ 同步共享列表{ //删除项目 //通知某物已被移除 同步这个{ this.notify;//this==处理程序 } } } 公共整数getSize{ 同步共享列表{ 返回sharedList.size; } } } 它似乎工作得很好,但不确定是否有隐藏的bug。
我的问题是:这安全吗?wait是否释放了handler/this的实例锁,以便notify可以获取锁

同步块是安全的。语句synchronizedbj获取参数obj的锁,因此可以调用wait并通知它。它们都要求当前线程持有对象的锁


在removeItem中锁定两个对象时,必须小心双重锁定。如果需要,必须确保始终以相同的顺序锁定它们,否则可能会造成死锁。

1。是的,wait显式地释放锁,以便其他线程可以显式地使用该类意味着它在文档中的某个地方,我只是没有查找它。Main中有一种隐藏的错误,它在外部使用锁,但是所有处理程序的方法都封装了锁。真奇怪。我将在封装上保持一致,并将listen作为处理程序中的一个方法。我不同意软件工程师的观点。在这方面进行同步是很常见的。有理由不这么做,但也有同样的理由这么做。例如,当您在Main中获得Handler的锁时,有时您需要能够做到这一点是有充分理由的。但是,您应该在同步时对此进行记录,因为它现在基本上是对象的公共API的一部分。此检查必须在同一同步块内进行。如上所述,检查和等待甚至应该在循环中发生,在对条件进行操作之前,仍然保持锁定,否则,无法保证条件仍然保持。因为很难相信你的//do something在只有大小的情况下做了一些有用的事情,所以很可能那里发生的任何事情都被破坏了。Re,[等待并通知…]的行为就像一个信号灯。不一个信号灯记得它发出了信号。等待并通知没有内存。如果某个线程A在没有其他线程等待时调用o.notify,那么notify什么也不做。如果其他线程B随后调用o.wait,那么它将等到下次其他线程调用o.notify时再调用。我没有注意到OP同时锁定了this和sharedList。这是个好机会。只要在读取或写入sharedList时始终保持此状态,就不需要同时锁定sharedList。这把锁足够了。