次のリンクを参照してください http://docs.oracle.com/javase/tutorial/essential/concurrency/QandE/answers.html次 の例は、キーステートメント1がキーステートメント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);
}
}
ソリューションには、メッセージへのすべての変更がメインスレッドに表示されることを保証できる2つの方法があります。
- メインスレッドで、CorrectorThreadインスタンスへの参照を保持します。次に、メッセージを参照する前に、そのインスタンスでjoinを呼び出します
- 同期されたメソッドを使用してメッセージをオブジェクトにカプセル化します。これらの方法を除いて、メッセージを参照しないでください。
これらの手法は両方とも、必要な発生前の関係を確立し、メッセージへの変更を可視化します。
joinを使用する最初のソリューションがキーステートメント1を「happen-before」キーステートメント2にする方法を理解しています。しかし、2番目のソリューションでは、同期メソッド(getMessage()やsetMessage()など)を使用してこの関係を確立する方法を理解できません。修飾キーステートメント2(System.out.println(getMessage())が修飾キーステートメント1(setMessage( "Mares do eat oats"))の後に実行されるという保証は何ですか。キーステートメント2はロックを取得する可能性がありますスレッドのスケジュール方法に応じて、キーステートメント1の前のメッセージまたはその逆。
また、message = "Mares do eatoats"の前にmessage="Mares do not eat oats"を実行するようにコードを変更する方法はありますか?私が考えることができる1つの方法は、共有状態変数を保持し、message = "Mares do eat oats"が実行された後に設定することですが、message = "Mares do eat oats"はwhile(!stateVariable){のように保護されたブロックにある必要があります。 wait();}そしてメッセージを更新します。そうですか?
ありがとう。