Java 为什么我的notify()不起作用?

Java 为什么我的notify()不起作用?,java,multithreading,wait,synchronized,notify,Java,Multithreading,Wait,Synchronized,Notify,我的notifyAll()方法似乎都不起作用。 露西应该等到鲍勃来了再放。 Bob应该等待Lucy的确认,然后释放。 这两件事似乎都没有发生 有人能让我知道我做错了什么,以及我如何着手解决它吗。 提前谢谢 编辑-我使用灰色建议修改了代码。 异常消失,但notify()方法似乎仍不起作用 import java.util.logging.Level; import java.util.logging.Logger; public class PlayDates { Thread lucy

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

有人能让我知道我做错了什么,以及我如何着手解决它吗。 提前谢谢

编辑-我使用灰色建议修改了代码。 异常消失,但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 我已经按照格雷斯的建议修改了代码。 HasArrimit现在是易变的,并且在playDates运行方法中。 在班内男孩跑步方法中,它变为真。 输出没有改变,问题似乎是相同的。 还有什么建议吗

更新代码:

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);
        }
    }
}

在初始化
bob
字段之前,您正在启动
Girl
线程,以便获得NPE。您应该在
Girl
之前初始化
bob
字段,并将其传递到该线程中。您的程序可能在某些情况下工作,但存在不可预测的竞争条件。如果线程启动速度足够快,它可能会工作,但您应该在启动
Girl
线程之前初始化
bob

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

编辑:


问题在变,所以我会努力跟上。我建议不要在
Boy
构造函数中将
hasarimited
设置为true。我认为应该将其设置为volatile,并在
run()
方法中设置。您希望启动
Girl
线程,运行一点,然后看到
Boy
不可用,并且
wait()
。因此,
Boy
线程应该稍后启动,并在
sleep()之后的
run()
方法中将
hasarimited
设置为
true
,然后在初始化
bob
字段之前启动
Girl
线程,这样您将获得NPE。您应该在
Girl
之前初始化
bob
字段,并将其传递到该线程中。您的程序可能在某些情况下工作,但存在不可预测的竞争条件。如果线程启动速度足够快,它可能会工作,但您应该在启动
Girl
线程之前初始化
bob

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

编辑:



问题在变,所以我会努力跟上。我建议不要在
Boy
构造函数中将
hasarimited
设置为true。我认为应该将其设置为volatile,并在
run()
方法中设置。您希望启动
Girl
线程,运行一点,然后看到
Boy
不可用,并且
wait()
。因此,
Boy
线程应该稍后启动,并在
sleep()之后的
run()
方法中将
hasarimited
设置为
true
,我希望我的Girl字段等待Bob字段。我已经使用您的建议修改了我的代码,这样NPE就不会再被抛出,但notify方法似乎仍然不起作用。您只需要在调用
start()之前构造
Bob
在你的
Girl
thread@James上。我的回答的第二部分可能有助于解决你的同步问题@James。谢谢你的建议。我已尝试按照您的建议编辑代码。不幸的是,错误没有改变。我错过了什么?你不是说
!已经到了
?您需要在代码中跟踪它,或者学习如何使用调试器。我想让我的女朋友菲尔德等鲍勃·菲尔德。我已经使用您的建议修改了我的代码,这样NPE就不会再被抛出,但notify方法似乎仍然不起作用。您只需要在调用
start()之前构造
Bob
在你的
Girl
thread@James上。我的回答的第二部分可能有助于解决你的同步问题@James。谢谢你的建议。我已尝试按照您的建议编辑代码。不幸的是,错误没有改变。我错过了什么?你不是说
!已经到了
?您需要在代码中跟踪它,或者学习如何使用调试器。如果你一直在编辑这个问题,很难回答@James。它使我们的答案无效。“这不应该是一个论坛。”格雷,对不起,我是新来的。将来,我应该用修改后的代码问一个新问题吗?你可以编辑你的答案,并在末尾添加一个新的部分。@Gray好的,这就是我将来要做的。对不起,伙计。我已经用附加信息编辑了我的答案。如果你一直在编辑它,很难回答这个问题@James。它使我们的答案无效。“这不应该是一个论坛。”格雷,对不起,我是新来的。将来,我是否应该就修订后的守则提出一个新问题