[英]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.