我的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()
。