根据wikipedia:“导致虚假唤醒的竞争条件应被视为罕见”。
但是,当我运行这段代码时,它向我展示了虚假唤醒经常发生。
这实际上是伪造的唤醒,还是我的代码中只有偷偷摸摸的竞态条件?
import java.util.Random;
public class Main {
public static void main(String[] args) throws Exception {
// Message message = new SafeMessage();
Message message = new SpuriousMessage();
String[] producerNames = { "p01", "p02", "p03", "p04", "p05", "p06", "p07", "p08", "p09" };
for (String producerName : producerNames) {
Producer producer = new Producer(producerName, message);
new Thread(producer).start();
}
String[] consumerNames = { "c-01", "c-02", "c-03", "c-04" };
for (String consumerName : consumerNames) {
Consumer consumer = new Consumer(consumerName, message);
new Thread(consumer).start();
}
}
}
abstract class Message {
protected String message;
protected boolean empty = true;
public abstract String getMessage() throws InterruptedException;
public abstract void setMessage(String message) throws InterruptedException;
protected static String avoidNull(String obj) {
return obj != null ? obj : "Default message";
}
}
class SpuriousMessage extends Message {
@Override
public synchronized String getMessage() throws InterruptedException {
wait();
empty = true;
String temp = message;
message = "---------------------------------------- Spurious wakeup";
return temp;
}
@Override
public synchronized void setMessage(String message) throws InterruptedException {
this.message = avoidNull(message);
this.empty = false;
notifyAll();
}
}
class SafeMessage extends Message {
@Override
public synchronized String getMessage() throws InterruptedException {
while (empty) {
wait();
}
empty = true;
notifyAll();
String temp = message;
message = "---------------------------------------- Spurious wakeup";
return temp;
}
@Override
public synchronized void setMessage(String message) throws InterruptedException {
while (!empty) {
wait();
}
this.message = avoidNull(message);
this.empty = false;
notifyAll();
}
}
class Producer implements Runnable {
private static final Random RANDOM = new Random();
private String producerName = "Default";
private Message message;
public Producer(String producerName, Message message) {
this.producerName = producerName;
this.message = message;
}
@Override
public void run() {
while (true) {
try {
message.setMessage(producerName + " :: " + randomMessage());
rest(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private static String randomMessage() {
final String[] messageArray = { "Alfa", "Bravo", "Charlie", "Delta", "Echo", "Foxtrot",
"Golf", "Hotel", "India", "Juliet", "Kilo", "Lima", "Mike", "November", "Oscar",
"Papa", "Quebec", "Romeo", "Sierra", "Tango", "Uniform", "Victor", "Whiskey",
"Xray", "Yankee", "Zulu" };
return messageArray[RANDOM.nextInt(messageArray.length)];
}
private void rest(long millis) {
try {
Thread.sleep(millis);
} catch (Exception e) {
e.printStackTrace();
}
}
}
class Consumer implements Runnable {
private final long TIMEOUT = 5;
private String consumerName = "Default";
private Message message;
public Consumer(String consumerName, Message message) {
this.consumerName = consumerName;
this.message = message;
}
@Override
public void run() {
while (true) {
try {
System.out.println(consumerName + " :: " + message.getMessage());
rest(TIMEOUT);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void rest(long millis) {
try {
Thread.sleep(millis);
} catch (Exception e) {
e.printStackTrace();
}
}
}
最佳答案
发生虚假唤醒时,尽管尚未调用wait()
,但notify/notifyAll
退出。在您的情况下,您从生产者处调用notifyAll
,因此wait
退出是正常的...
要观察虚假的唤醒,您只需要运行使用者。如果他们打印出“虚假唤醒”消息,那将是一次真正的虚假唤醒,因为它不再由notify/All
引起。但是,它可能永远不会发生。
另请参阅:Do spurious wakeups actually happen?。
关于java - 这是虚假的唤醒还是仅仅是时髦的(非虚假的)比赛条件?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/26499850/