2016-09-02 10 views
0

I持って、次のコードのJavaスレッド同期方法

import java.util.concurrent.*; 
public class dsd { 

private static boolean stopRequested; 
private static void requestStop() { 
    stopRequested = true; 
} 
private static synchronized boolean stopRequested() { 
    return stopRequested; 
} 
public static void main(String[] args) 
throws InterruptedException { 
    Thread backgroundThread = new Thread(new Runnable() { 
    public void run() { 
    int i = 0; 
    while (!stopRequested()) 
    i++; 
    } 
    }); 
    backgroundThread.start(); 
    TimeUnit.SECONDS.sleep(1); 
    requestStop(); 
} 
} 

それはrequestStop()が同期されていない場合でも動作しますなぜ質問はありますか?私がstopRequested()に同じことをしようとすると、もう動作しません。その変数のスレッドの並行性に問題はないのはなぜですか?私は、同期によって、変数が他のスレッドによって一貫した状態で表示されることがわかります。しかし、ここで変数は同期されておらず、それは効果がないようです。

+2

_...なぜ動作するのですか..._あなたが「働く」ことを意味すると助けになるでしょう。これは必ずしも明白ではありません。特に、あなたのようなプログラムでは出力が出ません。私は、「働く」とは、1秒後にすぐにプログラムが停止することを意味していると思っています。 –

+0

あなたは必要な振る舞いを保証するために同期化(または揮発性)が必要ですが、持っていなければ幸運であればそれを得ることができます(このような小さなプログラムは運が楽になります)。言い換えれば、「あなたが保証されているわけではありません.X」は、「あなたがXではないことを保証しています」とは異なります。 – yshavit

+0

_ stopRequested()に同じことをしようとすると... _同じことをしようとするとどうなりますか?あなたがしたことは何ですか?あなたは何をしましたか? 'stopRequested()'の宣言に 'synchronized'を追加すると言っていますか? –

答えて

1

​​はリエントラントですが、同期ブロックのロックを取得した同じスレッドは、ロックをまだ所有している場合は次に取得しようとすると保証されますが、これは事実stopRequested以上の変更が同期ブロックの外で行われていてもコードが機能していれば、あなたのコードには実際の状況の下で競合状態が残っている可能性があります。

レッツは、実行NでスレッドがstopRequested()によって条件出会うのために終了しなければならないと同時にrequestStop()が呼ばれ、変数stopRequestedは排他ロックによって保護されていないため、スレッドがN+1で終端することを保証していないことを言いますアクセサメソッドのいずれも、変数にはvolatileの修飾子がありません。これは、競争条件のために、あなたがコードについて持っている正確さの感覚が部分的に間違っていることを意味します。

+0

で同期を捨てるように言いましたので、同期なしでは正しくありませんか? – User124235

+0

'糸の安全性'の下では、完全には正しくありません。それは状態の破損があるかもしれない、それは@yshavitが言ったように。 'このような小さなプログラムは、幸運になることを容易にします。エラーの兆候を示さない長い時間の実行が可能になりますが、いつかは表示されます。 – xhamr

+0

それは私には奇妙に思えるので、なぜそれが動作しますか? – User124235

1

Java Lanaguage仕様では、このプログラムが終了するかどうか、終了するかどうかは示されません。

あなただけ両方方法、requestStop()stopRequested()が、同期している場合、それは約1秒後に終了することを確認することができます。

いずれかが同期されていない場合、またはいずれも同期されていない場合、プログラムは1秒後または5秒後に終了することも、終了しないこともあります。異なるJava実行時環境では異なる動作をする可能性があります。異なるハードウェア上で動作が異なる可能性があります。それは、週の異なる曜日に異なって動作する可能性があります。

両方の方法が​​でなければ、その動作は未定義です。

1

ディオンAlmaerによって引用があります:

most Java programs are so rife with concurrency bugs that they work only “by accident” 

これは、それらの一つですが。 Java言語仕様では、更新されたフラグが表示されるとは限りません。ルールに従わないと、あなたのスレッドがあなたのフラグの新しい値を見ているかどうかに関して、JVM実装の慈悲にかかっています。 JVMの実装によっては、他のものよりも寛容であるものもあれば、キャッシュする方法についてより積極的になるものもあります。

1

​​ブロックには、Javaで追加のセマンティクスがあります。それらはコードブロックの排他的な実行を提供するだけでなく、スレッド間のすべての操作の結果の可視性を保証するメモリバリアと呼ばれるものを放出します。

したがって、synchronized stopRequested()メソッドを呼び出すと、すべての変更が現在のスレッドに表示されます。このメソッドから​​を削除すると、バリアも削除され、JVMはメインスレッドで設定したフラグがバックグラウンドスレッドで表示されることを保証しません。そのため、​​がないと問題が発生します。