简体   繁体   English

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

[英]Why does my notify() not work?

None of my notifyAll() methods appear to be working. 我的notifyAll()方法似乎都不起作用。 Lucy is suppose to wait until Bob arrives and then release. 露西应该等到鲍勃到来再释放。 Bob is suppose to wait for acknowledgement Lucy and then release. 鲍勃应该等待露西的确认,然后释放。 Neither of these things seem to be happening. 这些事情似乎都没有发生。

Can someone let me know what I'm doing wrong and how I can go about fixing it. 有人可以让我知道我在做什么错以及如何解决它。 Thanks in advance. 提前致谢。

Edit - I amended my code using Grays advice. 编辑-我使用Grays建议修改了我的代码。 The exception disappears but the notify() method still doesn't appear to be working. 异常消失,但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);
        }
    }
}

Current Output 电流输出

Girl synchronized hit
Bob has arrived to play

Edit 2 I've adapted my code as Grays advice suggests. 编辑2我已经按照Grays的建议修改了我的代码。 hasArrived is now volatile and in the playDates run method. hasArrived现在是可变的,并且在playDates运行方法中。 It's changed to true within the inner class Boys run method. 内部类Boys run方法中将其更改为true。 The output hasn't changed and the problem appears to be the same. 输出未更改,问题似乎相同。 Any further advice? 还有其他建议吗?

Updated code: 更新的代码:

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

You are starting the Girl thread before you initialize the bob field so you will get a NPE. 在初始化bob字段之前,您正在启动Girl线程,这样您将获得NPE。 You should initialize your bob field before Girl and should pass it into that thread. 您应该 Girl 之前初始化bob字段并将其传递到该线程中。 You program might work in certain situations but there is a race condition that is unpredictable. 您的程序可能在某些情况下可以工作,但是存在无法预测的竞争条件。 If the thread starts fast enough, it may work but you should initialize bob before starting the Girl thread. 如果线程启动得足够快,它可能会起作用,但是您应该启动Girl线程之前初始化bob

You also have some memory synchronization issues . 您还存在一些内存同步问题 For example, although you are synchronizing on PlayDates.this , the Boy class may not have been initialized and synchronized when the Girl thread calls bob.hasArrived() . 例如,尽管您正在PlayDates.this上进行同步,但是当Girl线程调用bob.hasArrived()时, Boy类可能尚未初始化和同步。 Whenever a field is accessed in multiple threads, you need to make sure that both threads are seeing a properly synchronized value. 每当在多个线程中访问一个字段时,您都需要确保两个线程都看到正确同步的值。 You can ensure this by making hasArrived be an AtomicBoolean or by marking hasArrived as being volatile . 您可以通过将hasArrived设置为AtomicBoolean或将hasArrived标记为volatile来确保这一点。

Edit: 编辑:

The question is changing so I'll try to keep up. 问题正在改变,所以我会努力跟上。 What I would recommend is not to set hasArrived to be true in the Boy constructor. 我建议不要Boy构造函数中将hasArrived设置为true。 I think you should make it volatile and set in in the run() method. 我认为您应该使其volatile并在run()方法中进行设置。 You want the Girl thread to start, run a bit, and then see that Boy is not available and wait() . 您希望Girl线程启动,运行一点,然后看到Boy不可用,并wait() So the Boy thread should start later and set hasArrived to be true in it's run() method after a sleep() . 因此, Boy线程应稍后启动,并在sleep()之后在其run()方法中将hasArrived设置为true

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM