参考下面的链接 http://docs.oracle.com/javase/tutorial/essential/concurrency/QandE/answers.html 下面的例子显示了Key Statement 1不保证在key Statement 2之前执行
public class BadThreads {
static String message;
private static class CorrectorThread
extends Thread {
public void run() {
try {
sleep(1000);
} catch (InterruptedException e) {}
// Key statement 1:
message = "Mares do eat oats.";
}
}
public static void main(String args[])
throws InterruptedException {
(new CorrectorThread()).start();
message = "Mares do not eat oats.";
Thread.sleep(2000);
// Key statement 2:
System.out.println(message);
}
}
解决方案状态有两种方法可以保证对消息的所有更改对主线程可见:
- 在主线程中,保留对 CorrectorThread 实例的引用。然后在引用消息之前在该实例上调用 join
- 使用同步方法将消息封装在对象中。除非通过这些方法,否则永远不要引用消息。
这两种技术都建立了必要的先发生关系,使对消息的更改可见。
我了解使用 join 的第一个解决方案如何使关键语句 1“发生在之前”关键语句 2。但是对于第二个解决方案,我无法理解使用同步方法(例如 getMessage() 和 setMessage())如何建立这种关系。什么是修改后的关键语句 2 (System.out.println(getMessage()) 将在修改后的关键语句 1 (setMessage("Mares do eat oats")) 之后执行的保证。关键语句 2 可能会锁定关键语句 1 之前的消息,反之亦然,具体取决于线程的调度方式。
另外,有没有办法修改代码以使 message="Mares do not eat oats" 在 message="Mares do eat oats" 之前执行?我能想到的一种方法是保留一个共享状态变量并在 message="Mares do not eat oats" 执行后设置它,而 message="Mares do eat oats" 应该在一个像 while(!stateVariable){ wait();} 然后更新消息。那正确吗?
谢谢。