2013-06-06 5 views
9

私は、Javaの揮発性変数を理解するのが少し難しいです。揮発性変数には同期アクセスが必要ですか?

私はそうのような揮発性の変数を含むパラメータ化クラスを持っている:

public class MyClass<T> { 

    private volatile T lastValue; 

    // ... other code ... 

} 

は、私がget-値-IF--nullでないなど、lastValueに対して一定の基本的な操作を実装する必要があります。

これらの操作を同期させる必要がありますか?次の方法をやってもらえますか?

public void doSomething() { 
    String someString; 
    ... 
    if (lastValue != null) { 
     someString += lastValue.toString(); 
    } 
} 

同期されたブロックにヌルチェックを付ける必要がありますか?

public void doSomething() { 
    String someString; 
    ... 

    synchronized(this) { 
     if (lastValue != null) { 
      someString += lastValue.toString(); 
     } 
    } 
} 

私が取得し、セットのようなアトミック操作のために、私は同期適用せずに[OK]でなければならないことを知っている(例えば。public T getValue() { return lastValue; })。しかし、私は非原子操作についてはわかりませんでした。

+0

;' 'のようにsomeString + =( "" + lastValue);' 'あなたは完全にチェックNULL'を取り除くことができます:上

詳細。 – dasblinkenlight

+4

@dasblinkenlight、trueですが、lastValueがnullの場合、結果の文字列に "null"という単語が表示されても問題ない場合に限ります。 –

+0

@IanMcLairdああ、そうです、Javaはそれを忘れています(それは.NETでありません)。 – dasblinkenlight

答えて

13

volatileは、可視性を保証します(あるスレッドの変更は他のスレッドに見られます)が、複数の操作のアトミック性は保証されません。

そうです、lastValueif (lastValue != null)someString += lastValue.toString();nullになる可能性があり、あなたのコードはNullPointerExceptionを投げることができました。

あなたは同期を追加するか(ただし、すべての書き込みは、変数へのアクセスを同期する必要があります)、またはその簡単なユースケースのために、あなたはローカル変数を使用することができます。

public void doSomething() { 
    String someString; 
    T lastValueCopy = lastValue; 
    if (lastValueCopy != null) { 
     someString += lastValueCopy.toString(); 
    } 
} 
+0

なぜnullチェックに同期を追加するには、揮発性変数に対するアトミック操作の同期を追加する必要がありますか? –

+0

ある時点で同期化されている場合を除いて、スレッドの「前」と「後」という概念はないことを正しく理解していますか?スレッドセマンティクスは、別のスレッドがそれを更新した後、スレッドが古い変数値を見ることを可能にするか? – kutschkem

+0

@RoddyoftheFrozenPeasそうです、すべての書き込み操作を同期するだけです。相互排除のためにここでは 'synchronized'が使用されています。つまり、スレッドがそれらの2行の間で変数を変更しないようにするためです。これは、変数への書き込みを試みるすべてのスレッドがそのロックを取得する必要がある場合にのみ機能します。 – assylias

2

これは、に大きく依存します最も簡単な場合、Tは不変型です。つまり、あなたが読んだTの値であっても、後でその内部状態を変更することはありません。この場合、同期は必要ありません。参照をローカル変数に読み込んで、必要なだけ実行してください。

Tが変更可能なタイプの場合は、作業中にインスタンスの状態を変更する必要があります。この場合、Tのインスタンスがそのインスタンスによって保護されていることを特に保証する同期が必要です。 の同期化は一般的に、Tの状態を他の場所から変更することを止めません。特定のTの適切なロックは、ルールによって定義されている必要があります(また、それらのルールを破らないようにする言語要素はありません)。

特別なケースでは、Tが変更可能で、このを適切なロックと定義した場合、同期が必要ですが、もはや揮発性は必要ありません。

これは、同期との結合で揮発性の使用が疑わしいと言いました。

+0

@lokiオブジェクトが不変でない場合、オブジェクトが可視になると、オブジェクトの一部のフィールドが適切に構築され、オブジェクトの一部のフィールドが正しく表示されている可能性があります。デフォルト値(false、0、null)。 – assylias

関連する問題