我的notifyAll()方法似乎都不起作用。
露西应该等到鲍勃到来再释放。
鲍勃(Bob)应该等待露西(Lucy)的确认,然后释放。
这些事情似乎都没有发生。

有人可以让我知道我在做什么错以及如何解决它。
提前致谢。

编辑-我使用Grays建议修改了我的代码。
异常消失,但notify()方法仍然似乎不起作用。

import java.util.logging.Level;
import java.util.logging.Logger;

public class PlayDates {
    Thread lucyThread;
    Girl lucy;
    Thread bobThread;
    Boy bob;

    public static void main(String[] args) {
        PlayDates playDates = new PlayDates();
        playDates.run();
    }
    public void run() {
        lucy = new Girl();
        lucyThread = new Thread(lucy);

        bob = new Boy();
        bobThread = new Thread(bob);

        lucyThread.start();
        threadSleep(500);
        bobThread.start();
    }

    public class Girl implements Runnable {
        @Override
        public void run() {
            synchronized(PlayDates.this){
                System.out.println("Girl synchronized hit");
                if(!bob.hasArrived()) {     // Doesnt seem to get past here?
                    System.out.println("Lucy has fallen asleep waiting for Bob");
                    try {
                        PlayDates.this.wait();  // Wait for Bob
                        System.out.println("Lucy has woken up");
                        PlayDates.this.notifyAll();     // Acknowledge Bobs arrival
                    } catch (InterruptedException ex) {
                        Logger.getLogger(PlayDates.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            }
        }
    }

    public class Boy implements Runnable {
        private boolean hasArrived;

        @Override
        public void run() {
            synchronized(PlayDates.this){
                System.out.println("Bob has arrived to play");
                PlayDates.this.notifyAll();
                try {
                    PlayDates.this.wait();  // Wait for Lucy to acknowledge Bobs arrival
                } catch (InterruptedException ex) {
                    Logger.getLogger(PlayDates.class.getName()).log(Level.SEVERE, null, ex);
                }

                System.out.println("Bob and Lucy are playing");
            }
        }

        public Boy() {
            hasArrived = true;
        }

        public boolean hasArrived() {
            return hasArrived;
        }
    }

    public void threadSleep(int milli) {
        try {
            Thread.sleep(milli);
        } catch (InterruptedException ex) {
            Logger.getLogger(PlayDates.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}


电流输出

Girl synchronized hit
Bob has arrived to play




编辑2
我已经按照Grays的建议修改了我的代码。
hasArrived现在是可变的,并且在playDates运行方法中。
内部类Boys run方法中将其更改为true。
输出未更改,问题似乎相同。
还有其他建议吗?

更新的代码:

import java.util.logging.Level;
import java.util.logging.Logger;

public class PlayDates {
    Thread lucyThread;
    Girl lucy;
    Thread bobThread;
    Boy bob;
    volatile boolean hasArrived;

    public static void main(String[] args) {
        PlayDates playDates = new PlayDates();
        playDates.run();
    }
    public void run() {
        hasArrived = false;
        lucy = new Girl();
        lucyThread = new Thread(lucy);

        bob = new Boy();
        bobThread = new Thread(bob);

        lucyThread.start();
        threadSleep(500);
        bobThread.start();
    }

    public class Girl implements Runnable {
        @Override
        public void run() {
            synchronized(PlayDates.this){
                System.out.println("Girl synchronized hit");
                if(hasArrived) {     // Doesnt seem to get past here?
                    System.out.println("Lucy has fallen asleep waiting for Bob");
                    try {
                        PlayDates.this.wait();  // Wait for Bob
                        System.out.println("Lucy has woken up");
                        PlayDates.this.notifyAll();     // Acknowledge Bobs arrival
                    } catch (InterruptedException ex) {
                        Logger.getLogger(PlayDates.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            }
        }
    }

    public class Boy implements Runnable {
        @Override
        public void run() {
            threadSleep(1000);
            synchronized(PlayDates.this){
                System.out.println("Bob has arrived to play");
                hasArrived = true;
                PlayDates.this.notifyAll();
                try {
                    PlayDates.this.wait();  // Wait for Lucy to acknowledge Bobs arrival
                } catch (InterruptedException ex) {
                    Logger.getLogger(PlayDates.class.getName()).log(Level.SEVERE, null, ex);
                }
                System.out.println("Bob and Lucy are playing");
            }
        }
    }

    public void threadSleep(int milli) {
        try {
            Thread.sleep(milli);
        } catch (InterruptedException ex) {
            Logger.getLogger(PlayDates.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

最佳答案

在初始化Girl字段之前,您正在启动bob线程,这样您将获得NPE。您应该在bob之前初始化Girl字段,并将其传递到该线程中。您的程序可能在某些情况下可以工作,但是存在无法预测的竞争状况。如果线程启动足够快,它可能会起作用,但是您应该在启动bob线程之前初始化Girl

您也有一些memory synchronization issues。例如,尽管您正在PlayDates.this上进行同步,但是当Boy线程调用Girl时,bob.hasArrived()类可能尚未初始化和同步。每当在多个线程中访问一个字段时,您都需要确保两个线程都看到正确同步的值。您可以通过将hasArrived设置为AtomicBoolean或将hasArrived标记为volatile来确保这一点。

编辑:

问题正在改变,所以我会努力跟上。我建议不要在hasArrived构造函数中将Boy设置为true。我认为您应该将其设置为volatile并在run()方法中进行设置。您希望Girl线程启动,运行一点,然后查看Boy不可用和wait()。因此,Boy线程应稍后启动,并在hasArrived之后的true方法中将run()设置为sleep()

10-04 14:01