gpt4 book ai didi

java - Notify 似乎唤醒了多个线程

转载 作者:行者123 更新时间:2023-11-30 06:54:12 26 4
gpt4 key购买 nike

我正在使用 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();
}
}

}

一段时间后,我看到两个线程被单线程唤醒。输出如下:

91:114
114:124
124:198
198:106
106:202
202:121
121:40
40:42
42:83
83:81
81:17
17:189
189:73
73:66
66:95
95:199
199:68
68:201
201:70
70:110
110:204
204:171
171:87
87:64
64:205
205:115

这里我看到115线程通知了两个线程,84线程通知了两个线程;因此,我们看到了ArrayIndexOutOfBoundsException

115:84

115:111

84:203

84:200

ARRAYException:200:199:3

ARRAYException:203:199:3

程序中存在什么问题?

最佳答案

What is the issue in the program?

您的代码存在一些问题,可能会导致此行为。首先,正如 @Holder 评论的那样,有很多代码段可以由多个线程同时运行,应该使用 synchronized block 进行保护。

例如:

if (addIndex == capacity) {
addIndex = 0;
}

如果多个线程运行此命令,则多个线程可能会看到 addIndex ==capacity 并且多个线程将覆盖第 0 个索引。另一个例子是:

addIndex++;

如果 2 个线程尝试同时执行此语句,则这是一个经典的竞争条件。如果 addIndex 事先为 0,则在 2 个线程执行此语句后,addIndex 的值可能为 1 或 2,具体取决于竞争条件。

任何可以由多个线程同时执行的语句都必须在synchronized block 中正确锁定或以其他方式进行保护。即使您有 volatile 字段,仍然可能存在竞争条件,因为正在执行多个操作。

此外,一个典型的错误是在检查阵列上的流量是否过高或过低时使用 if 语句。它们应该是 while 语句,以确保您没有类消费者生产者竞争条件。请参阅my docs here或者看看相关的SO问题:Why does java.util.concurrent.ArrayBlockingQueue use 'while' loops instead of 'if' around calls to await()?

关于java - Notify 似乎唤醒了多个线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42139774/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com