2017-11-19 21 views
0

私は並行プログラミングの初心者です。私はsleep(1)で にコメントしたときにこのプログラムが終了しない理由を正確に理解したいと思います。 )Mainスレッドに戻って手を差し伸べます。おそらく、Busy waitingと何か関係がありますか?並行プログラミング、スレッド間で値を共有

public class Rdv<V> { 
    private V value; 

    public void set(V value) { 
    Objects.requireNonNull(value); 
    this.value = value; 
    } 

    public V get() throws InterruptedException { 
    while(value == null) { 
     Thread.sleep(1); // then comment this line ! 
    } 
    return value; 
    } 

    public static void main(String[] args) throws InterruptedException { 
    Rdv<String> rendezVous = new Rdv<>(); 
    new Thread(() -> { 
     try { 
     Thread.sleep(5000); 
     } catch (InterruptedException e) { 
     throw new AssertionError(e); 
     } 
     rendezVous.set("hello"); 
    }).start(); 

    System.out.println(rendezVous.get()); 
    } 
} 
+0

関連:https://stackoverflow.com/questions/42676751/thread-sleep-makes-compiler-read-value-every-time – shmosel

答えて

2

最初に、このプログラムは大きく壊れています。それが睡眠中であっても終了するという保証はありません。おそらくそうだろうが、そうではないかもしれない。

値フィールドがvolatileではなく、値を取得または設定するときにsynchronizedまたは他のロックを使用しないという問題があります。つまり、あるスレッドが別のスレッドの変更を確認する保証はありません。プログラムを停止するはずの値への書き込みは、待機中のスレッドからは見えないことがあります。 Javaがインタプリタモードで動作しているため、スリープ状態になると正常に動作します。睡眠がなければ、ちょうどコンパイラがコードを取り込んで最適化する時間がありました。 whileループは、同じことをするはるかに効率的なバージョンに書き直すことができます:永遠にループします。それはそれがしていることです。

最も簡単な修正は、値フィールドをvolatileとして宣言することです。 Javaは、それが変更される可能性があることを認識し、読み取りの最適化を回避します。

Javaメモリモデルがよく分からない限り、スレッド間で共有されるデータへのアクセスは常に同期されます。転ばぬ先の杖!

+0

もちろん、このプログラムは安全ではありませんが、ちょうどコンパイラとVMで何が起こるかを理解するための奇妙な例 – Unconnu

関連する問題