根据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/

10-10 16:45