java - (Java) 使用 Object wait() 和 notify() 的线程安全
问题描述
我一直在寻找一种方法让一个线程等待/休眠,直到另一个线程发出信号表明某事已准备就绪。等待的线程应该唤醒,处理可用的数据,然后回到睡眠状态,直到另一个线程再次发出信号。
我能找到的最简单的方法是Object.wait()
and Object.notify()
,它的行为类似于初始化为值 0 的信号量。但是,如果没有synchronized
周围的语句notify/wait
,Java 总是IllegalMonitorStateException
在线程不是监视器所有者时抛出。所以我只是把它们放在代码周围,如下所示。
线程1:运行无限循环
public class Main {
private Handler handler; // only one instance (singleton pattern)
public void listen() {
while (true) {
try {
synchronized (handler) {
handler.wait();
int value = handler.getSize();
// do something
}
} catch (InterruptedException e) {
// ...
}
}
}
}
线程 2:其他一些类调用 removeItem
public class Handler {
// SINGLETON PATTERN - ONLY ONE INSTANCE
private ArrayList<Integer> sharedList;
private Handler() {
sharedList = new ArrayList<>();
}
public void addItem(Integer i) {
synchronized (sharedList) {
// add to list
}
}
public void removeItem(int i) {
synchronized (sharedList) {
// remove item
// notify that something is removed
synchronized (this) {
this.notify(); // this == handler
}
}
}
public int getSize() {
synchronized (sharedList) {
return sharedList.size();
}
}
}
它似乎工作得很好,但不确定是否存在隐藏的错误。我的问题是:这安全吗?是否wait
释放实例锁handler/this
以便notify
获取锁?
解决方案
同步块是安全的。该语句synchronized(obj)
获取参数的锁,obj
因此您可以调用它。它们都要求当前线程持有对象上的锁。wait
notify
您必须小心removeItem
锁定两个对象的双重锁定。如果你需要这个,你必须确保你总是以相同的顺序锁定它们,否则,你可能会造成死锁。
推荐阅读
- java - 如何在基于 Spring 会话 Java 的配置中更改 MaxInactiveIntervalInSeconds 值?
- ruby-on-rails - Microsoft Graph API 身份验证 - 范围无效
- javascript - Angular - 无法读取未定义的属性“id”
- python - 在 Python 中生成 Outlook 提及 @
- spring - Shared ApllicationContext 抛出 BeanFactory 未初始化或已关闭
- php - 如何自动播放嵌入谷歌驱动器视频?
- java - 登录系统 JSF - 识别出 SQLException?
- jenkins - Jenkins 环境变量 - 检测拉取请求
- esp8266 - MQTT 失败,状态为 -2
- java - 对我的 int 和 long 代码差异的问题