英文:
(Java) Thread safety using Object wait() and notify()
问题
以下是您提供的内容的翻译:
我正在寻找一种方法,使一个线程等待/休眠,直到另一个线程发出信号表示某个东西已经准备好。等待的线程应该唤醒,处理可用的数据,然后再次进入休眠,直到另一个线程再次发出信号。
我找到的最简单的方法是使用Object.wait()
和Object.notify()
,它们的行为类似于一个初始值为0的信号量。然而,在notify/wait
周围没有synchronized
语句的情况下,当线程不是监视器所有者时,Java总是会抛出IllegalMonitorStateException
。因此,我简单地将它们放在像下面展示的代码周围。
线程1:运行无限循环
public class Main {
private Handler handler; // 只有一个实例(单例模式)
public void listen() {
while (true) {
try {
synchronized (handler) {
handler.wait();
int value = handler.getSize();
// 做一些事情
}
} catch (InterruptedException e) {
// ...
}
}
}
}
线程2:其他某个类调用removeItem
public class Handler {
// 单例模式 - 只有一个实例
private ArrayList<Integer> sharedList;
private Handler() {
sharedList = new ArrayList<>();
}
public void addItem(Integer i) {
synchronized (sharedList) {
// 添加到列表
}
}
public void removeItem(int i) {
synchronized (sharedList) {
// 删除项目
// 通知某些内容已被移除
synchronized (this) {
this.notify(); // this == handler
}
}
}
public int getSize() {
synchronized (sharedList) {
return sharedList.size();
}
}
}
它似乎工作得非常好,但不确定是否存在隐藏的错误。
我的问题是:这是安全的吗?wait
会释放handler/this
的实例锁,以便notify
可以获取锁吗?
英文:
I was looking for a way to make one thread wait/sleep until another thread signalled that something was ready. The waiting thread should wake up, process the data that was made available, then go back to sleep until the other thread signalled again.
The simplest method I could find was Object.wait()
and Object.notify()
, which behaved like a semaphore initialised to value 0. However, without the synchronized
statements around notify/wait
, Java always threw IllegalMonitorStateException
when the thread was not the monitor owner. So I simply put them around the code like shown below.
THREAD 1: running infinite loop
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) {
// ...
}
}
}
}
THREAD 2: Some other class calls 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();
}
}
}
It seems to work perfectly fine but not sure if there is a hidden bug.
My question is: Is this safe? Does wait
release the instance lock for handler/this
so notify
can acquire the lock?
答案1
得分: 1
同步块是安全的。语句synchronized(obj)
会获取参数obj
的锁,因此您可以在其上调用wait
和notify
。它们都要求当前线程持有对象的锁。
在removeItem
中存在双重锁定,您必须小心,因为您锁定了两个对象。如果您确实需要这样做,必须确保始终以相同的顺序锁定它们,否则可能会导致死锁。
英文:
Synchronized blocks are safe. The statement synchronized(obj)
acquires the lock of the argument obj
, so you can call wait
and notify
on it. They both require that the current thread holds the lock on the object.
You have to be careful about the double-locking you have in removeItem
where you lock two objects. If you ever need this, you have to make sure that you always lock them in the same order, otherwise, you may create a deadlock.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论