gpt4 book ai didi

java - Thread.sleep 和 happens-before 有什么关系?

转载 作者:搜寻专家 更新时间:2023-10-31 20:17:33 24 4
gpt4 key购买 nike

我写了一个简单的应用程序,它有主线程(生产者)和多个消费者线程。我想从主线程广播一条消息,所以所有的消费者线程都会收到它。但是,我有麻烦。我试图了解如何 Thread.sleep可能与 Happens-Before 有关.这是我的一段代码:

import java.util.*;

public class PubSub {

public static void main(String[] args) {
List<Consumer> consumers = new ArrayList<>();

for (int i = 0; i < 3; i++ ) {
Consumer consumer = new Consumer(
"Consumer" + i
);
consumer.start();

consumers.add(consumer);
}

Scanner scanner = new Scanner(System.in);

while(true) {
String message = scanner.nextLine();

for (Consumer consumer: consumers) {
consumer.notify(message);
}

}
}

static class Consumer extends Thread {

private Queue<String> queue;

public Consumer(String name) {
super(name);
this.queue = new LinkedList<>();
}

@Override
public void run() {
while(true) {

if (!queue.isEmpty()) {
String message = queue.poll();

System.out.println(
getName() + ": Consuming message: " + message
);
}
}
}

public void notify(String message) {
queue.add(message);
}
}

}

如果我添加 sleep ,消费者将开始接收消息:

@Override
public void run() {
while(true) {

try {
Thread.sleep(0);
} catch (InterruptedException e) {
e.printStackTrace();
}

if (!queue.isEmpty()) {
String message = queue.poll();

System.out.println(
getName() + ": Consuming message: " + message
);
}
}
}

由于 Thread.sleep 是一个本地方法,我想了解它是如何解析 happens-before 的。

我必须指出,修复发生前的真正方法是制作 volatile 关键字:

private volatile Queue<String> queue;

如果您将同步 添加到队列,它也会解决问题:

@Override
public void run() {
synchronized (queue) {
while (true) {

if (!queue.isEmpty()) {
String message = queue.poll();

System.out.println(
getName() + ": Consuming message: " + message
);
}
}
}
}

最佳答案

I'm trying to understand how Thread.sleep may be related to Happens-Before

happens-beforeThread.sleep 之间没有关系。 JLS明确指定 Thread.sleep 没有任何同步语法:

Neither a sleep for a period of zero time nor a yield operation need have observable effects. It is important to note that neither Thread.sleep nor Thread.yield have any synchronization semantics. In particular, the compiler does not have to flush writes cached in registers out to shared memory before a call to sleep or yield, nor does the compiler have to reload values cached in registers after a call to sleep or yield. For example, in the following (broken) code fragment, assume that this.done is a non-volatile boolean field:

while (!this.done)
Thread.sleep(1000);

The compiler is free to read the field this.done just once, and reuse the cached value in each execution of the loop. This would mean that the loop would never terminate, even if another thread changed the value of this.done


在相关说明中,如果在 while 循环之后添加在运行时评估的语句,消费者似乎开始消费消息(在我的机器上)。例如,添加 this.toString() 会导致消费者开始消费消息。

public void run() {
while(true) {
this.toString();

这仍然不能解释该行为,但它进一步证实 Thread.sleep 不一定是 Consumer 突然看到队列更新的原因。

关于java - Thread.sleep 和 happens-before 有什么关系?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42417636/

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