2011-12-16 8 views
3

Javaのvolatile文について質問があります。Java:クラスをスレッドセーフにするのに十分な揮発性?

class Master { 
    // Foo is a class with thread-safe methods 
    public volatile Foo foo; 
} 

class Worker1 implements Runnable { 
    protected Master master 

    void run() { ... }; 
} 

class Worker2 implements Runnable { 
    protected Master master 

    void run() { ... }; 
} 

これは、同時に実行されるクラスのクラスのオブジェクトへの参照を保持する2つのワーカースレッドを持っています。作業中は、どちらもmaster.fooのメソッドにアクセスする必要があります。ある時点で、マスタのFooオブジェクトはワーカースレッドの1つによって変更されます。今私の質問:揮発性の使用は全体のスレッドを安全にしますか?

  • 読み込みと書き込みが参照変数のアトミックです[...]
Java tutorial from Oracleにそれは

しかし、アトミックで指定できるアクションがあると言うので、私はこれを求めています

アトミックアクションはインターリーブできないため、スレッドの干渉を恐れずに使用できます。

私はこれを正しく理解していることを確認したいと思います。事前に

感謝:)

+0

「変更されました」とはどういう意味ですか? 1. 'Foo'の新しいインスタンスが作成されます。2.' Foo'の状態は変更されますか? – home

+0

不明確な文をお詫び申し上げます。これは、オブジェクト自体ではなく、参照を変更することです。 – tbolender

答えて

9

参照の読み取りと書き込みはJavaでは常にアトミックなので、参照を半分更新した状態で見るなどの危険はありません。これが「スレッドセーフ」である場合、操作はキーワードの有無に関係なくスレッドセーフです。

しかし、volatileは、アトミック性ではなく、スレッドがローカルに書き込みをキャッシュできるかどうかに影響します。 volatileは、書き込みがメインメモリに書き戻され、他のスレッドから見えるようにします。スレッドセーフであれば、このキーワードが必要です。

volatile自体は、fooのメソッド呼び出しで他のスレッドを除外するかどうかには影響しません。それが​​と別の場所で使用することを意味する場合は、

+0

ありがとうございました:)私が気にしているのは、2番目のケースです。 – tbolender

+0

驚くべき答え!わかりやすい! –

1

あなたが唯一のものは、はい、揮発性が十分にあるよりも、この変数を設定している場合。コメントに指摘されているように、変更を表示するには揮発性が必要です(ただし、長いか長いかのように、揮発性のない破損した更新はありません。

デフォルトでは、参照変数(オブジェクトへの参照)の読み書きは、ほとんどのプリミティブ型(longとdoubleを除く)への読み書きと同様にアトミックです。

volatileを使用すると、long型とdouble型の変数への読み書きもアトミックであることを確認できます。この場合、この場合は必要ありません。

はい、この例では十分です。ただし、より複雑なメッセージを送信する予定がある場合は、java.util.concurrentのツールを使用することを検討してください。*

+0

volatileは必須ではありません(単純なセッター/ゲッターはスレッドセーフではありません/可視です) –

+2

volatileキーワードを使用しないと、変更は他のスレッドから見えないことがあります。これは矛盾を引き起こすわけではありませんが、おそらく望ましい動作ではありません。 –

+2

volatileは操作のアトミック性にのみ影響しません。また、価値の可視性にも影響します。これを不揮発にすると、プログラムはスレッドセーフではなくなります。 –

4

volatile変数を読み取るスレッドは、この変数に新しい値が設定されていることを確認します。プロセッサキャッシュに保存されている無効な値は表示されません。

プログラム全体をスレッドセーフにするかどうかは、プログラムの機能、変数の使用方法、Fooクラスの設計方法によって異なります。

+0

ありがとう:)これも私の質問に答えます:) – tbolender

+0

あなたが記述した 'volatile'の意味は、Java 1.4までは正しかったです。 1.5からは、追加の役割があります。すなわち、それは_happens-before_ relation(順序付け)を確立します: 'vl'は' volatile'です、 'vl'に書き込む場合、' vl'への書き込みの前に起こる(同じスレッド内の)他のすべての書き込みは、スレッド。そして、 'vl'の読みは、(他の変数の)スレッド内のすべての後続の読み込みが' vl'の読み込み時の値を持つことを保証します。 –

+0

はい、私はvolatileのこの "カスケード"効果を認識しています。 volatileの基本的な機能について説明したかっただけです。 BTWは、このカスケード効果を利用することで、他のメカニズムであるIMOよりも操作が不安定になり、脆弱になってしまいます。 –

3

揮発性では不十分です。スレッド2に

Blammo blammo = new Blammo(); 
blammo.kapow = "zowie"; 
if ((blammo.kapow != null) && (blammo.kapow.isEmpty())) 
{ 
    ... 
} 

コード:スレッド1に

public class Blammo 
{ 
    public String kapow; 
} 

コード:

共有オブジェクト:

私は揮発性が十分でない場合、この例では、ある状況を示しています信じて

blammo.kapow = null; 

スレッド1が実行され、実行されます(blammo.kapow!= null)。
スレッド1がスワップアウトし、スレッド2がスワップインします。
スレッド2が実行されます(blammo.kapow = null)。
スレッド1がスワップアウトされ、スレッド1がスワップインします。
スレッド1は(blammo.kapow.isEmpty())を実行し、nullポインタ例外をスローします。

関連する問題