0

我的 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 现在是 volatile 并且在 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);
        }
    }
}
4

1 回答 1

3

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

您还有一些内存同步问题。例如,虽然您在 上进行同步,但线程调用时PlayDates.thisBoy该类可能尚未初始化和同步。每当在多个线程中访问一个字段时,您需要确保两个线程都看到正确同步的值。您可以通过设置为 be或标记为be来确保这一点。Girlbob.hasArrived()hasArrivedAtomicBooleanhasArrivedvolatile

编辑:

问题正在改变,所以我会努力跟上。我建议不要在构造函数中设置hasArrived为 true 。Boy我认为你应该做到volatile并在run()方法中设置。您希望Girl线程启动、运行一点,然后看到它Boy不可用并且wait(). 所以Boy线程应该稍后开始hasArrived,并true在.run()sleep()

于 2013-04-20T17:58:22.377 回答