Java Notify似乎正在唤醒多个线程
我正在使用Java Notify似乎正在唤醒多个线程,java,multithreading,wait,notify,Java,Multithreading,Wait,Notify,我正在使用wait()和notify()执行一个示例程序,但是当调用notify()时,会唤醒多个线程而不是一个线程 代码是: public class MyQueue<T> { Object[] entryArr; private volatile int addIndex; private volatile int pending = -1; private final Object lock = new Object(); priv
wait()
和notify()
执行一个示例程序,但是当调用notify()
时,会唤醒多个线程而不是一个线程
代码是:
public class MyQueue<T> {
Object[] entryArr;
private volatile int addIndex;
private volatile int pending = -1;
private final Object lock = new Object();
private volatile long notifiedThreadId;
private int capacity;
public MyQueue(int capacity) {
entryArr = new Object[capacity];
this.capacity = capacity;
}
public void add(T t) {
synchronized (lock) {
if (pending >= 0) {
try {
pending++;
lock.wait();
System.out.println(notifiedThreadId + ":" + Thread.currentThread().getId());
} catch (InterruptedException e) {
e.printStackTrace();
}
} else if (pending == -1) {
pending++;
}
}
if (addIndex == capacity) { // its ok to replace existing value
addIndex = 0;
}
try {
entryArr[addIndex] = t;
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("ARRAYException:" + Thread.currentThread().getId() + ":" + pending + ":" + addIndex);
e.printStackTrace();
}
addIndex++;
synchronized (lock) {
if (pending > 0) {
pending--;
notifiedThreadId = Thread.currentThread().getId();
lock.notify();
} else if (pending == 0) {
pending--;
}
}
}
}
public class TestMyQueue {
public static void main(String args[]) {
final MyQueue<String> queue = new MyQueue<>(2);
for (int i = 0; i < 200; i++) {
Runnable r = new Runnable() {
@Override
public void run() {
for (int i = 0; i < Integer.MAX_VALUE; i++) {
queue.add(Thread.currentThread().getName() + ":" + i);
}
}
};
Thread t = new Thread(r);
t.start();
}
}
}
这里我看到115个线程通知了两个线程,84个线程通知了两个线程;因此,我们看到了ArrayIndexOutOfBoundsException
115:84
115:111
84:203
84:200
ARRAYException:200:199:3
ARRAYException:203:199:3
节目中的问题是什么
节目中的问题是什么
您的代码中有几个问题可能导致这种行为。首先,正如@Holder所评论的,有很多代码段可以由多个线程同时运行,应该使用synchronized
块来保护它们
例如:
if (addIndex == capacity) {
addIndex = 0;
}
如果多个线程运行此操作,则多个线程可能会看到addIndex==capacity
,并且多个线程将覆盖第0个索引。另一个例子是:
addIndex++;
如果两个线程试图同时执行此语句,则这是一个典型的争用条件。如果addIndex
之前为0,则在两个线程执行此语句后,addIndex
的值可能为1或2,具体取决于竞争条件
任何可以由多个线程同时执行的语句都必须在synchronized
块中正确锁定或以其他方式保护。即使您有volatile
字段,仍然可能存在竞争条件,因为有多个操作正在执行
另外,一个典型的错误是在检查数组上的溢出或不足流时使用
if
语句。它们应该是while
语句,以确保您没有类消费者-生产者竞争条件。查看或查看相关的SO问题:您似乎错过了synchronized
的实际用途。它是为了保护对共享资源的访问,而不是在访问完全不受保护的共享资源时执行等待和通知。此外,您应该认真阅读的文档,尤其是“…虚假唤醒是可能的,并且此方法应始终在循环中使用”部分。感谢您的快速回复。我知道我们可以使用并发锁。但我的任务是使用wait()和notify()创建锁。因此,在任何时候,只有一个线程应该在同步块之间执行代码?synchronized
块必须跨越整个操作,包括对共享数据结构的每次访问,而不仅仅是执行wait
或notify
的部分。您正在访问entryArr
和addIndex
块之外的synchronized
块,并将addIndex
声明为volatile
没有帮助,因为它不会使更新原子化。
addIndex++;