2013-02-25 13 views
12
class MyClass 
{ 
     private static volatile Resource resource; 

     public static Resource getInstance() 
     { 
      if(resource == null) 
        resource = new Resource(); 
      return resource; 
     } 
} 

揮発性の安全な発行が行われると(つまり、参照が別のスレッドから参照できるようになるとすぐに、データも利用可能です)、実際にはJavaの同時実行性に従います。だから私はここでそれを使うことができますか?しかし、それが正しければ、今度はthread1が "リソース"をチェックし、それがヌルなので、オブジェクトの作成を開始するとします。スレッド1がobjetを作成している間に別のスレッド、すなわちthread2が来て、 "resource"の値のチェックを開始し、thread2がそれをnullとして見つけます( "resource"オブジェクトの作成はかなりの時間がかかります)。安全なパブリケーションがスレッド2に利用できないために発生していない)、オブジェクトの作成も開始されますか?そうであれば、クラス不変のブレーク。私は正しいですか?この特別な揮発性の使用をここで理解するのを助けてください。シングルトンが揮発性である場合

+2

シングルトンでは「volatile」は使用しません。 *定義によると、シングルトン内のプライベートインスタンスは変更されません。つまり、スレッドが古い値をキャッシュする危険はありません。これはあなたの 'getInstance'が同期されていないため、スレッドセーフではない実装を現在持っています。 Javaでシングルトンを作成するには、 'enum'を使います。 –

+0

http://jeremymanson.blogspot.com/2008/11/what-volatile-means-in-java.html – happybuddha

+1

ほぼすべての用途で、クラスローディングが遅れて行われるため、初期化式を使用することもできます。おそらくこのインスタンスを使用せずに(他の何らかの理由で)クラスを使用している場合、静的なクラスを入れ子にしてもうまくいくでしょう。 –

答えて

11

volatileが1つの問題visibility issueです。 1つの変数に書き込む場合は、volatileと宣言されていますその値はすぐに他のスレッドに表示されます。私たちが知っているように、L1、L2、L3では異なるレベルのキャッシュがあり、あるスレッドの変数に書き込む場合、他のスレッドから見えることは保証されていないので、volatileを使うと直接メモリに書き込み、他の人に。しかし、volatileはアトミック性の問題を解決しません。つまり、int a; a++;は安全ではありません。これに関連する3つの機械命令があるためです。

15

正しいですが、複数のスレッドがリソースオブジェクトを作成しようとする可能性があります。揮発性は、あるスレッドが参照を更新すると、他のすべてのスレッドに新しい参照が表示され、キャッシュされた参照は表示されません。これは遅くなりますが、より安全です。

あなたは遅延ロードされ、単一のリソースを必要とする場合、あなたはこのような何かを実行する必要があります読んで、その変数への書き込み

class MyClass 
{ 
     private static volatile Resource resource; 
     private static final Object LOCK = new Object(); 

     public static Resource getInstance() 
     { 
      if(resource == null) { 
       synchronized(LOCK) { // Add a synch block 
        if(resource == null) { // verify some other synch block didn't 
              // write a resource yet... 
         resource = new Resource(); 
        } 
       } 
      } 
      return resource; 
     } 
} 
+0

ロックオブジェクトを使用したいと思います。http://docs.oracle.com/javase/チュートリアル/必須/同時実行性/ newlocks.html – ssedano

+1

@corsiKa URにお返事ありがとうございます。私はそれをこのように置くことができますか?volatileは可視性問題を起こる前のイディオムに適合させるだけで解決しますが、ここでは可視性とアトミック性、つまり条件をチェックしてオブジェクト(リソース)を初期化する必要があります。必要とされている"。私が間違っているなら、私を修正してください。 – Trying

+0

@ user2109070私はそれが十分な要約だと思います。もし私がコードのコードレビューをしていたら、それは合理的な声明になります。 – corsiKa

0

volatileキーワード保証はアトミックです。揮発性変数への書き込みが は、後続との関係、前に起こる確立するため、揮発性変数を使用tutorial

Reads and writes are atomic for all variables declared volatile 

によれば

は、同じ の読み出し、メモリ一貫 エラーのリスクを低減します変数。これは、揮発性変数への変更が常に が他のスレッドから見えることを意味します。さらに、 スレッドが揮発性変数を読み取ったときに、揮発性の最新の変更である だけでなく、 の変更の原因となったコードの副作用も認識します。

0

分野に適用される、Javaの揮発性の保証:

あなたがダブルチェックロッキングパターンを使用することができ、より良いパフォーマンスを得るために

  1. (Javaの全バージョン) の読み取りではグローバルオーダーがあり、揮発性変数に書き込みます。これは、すべてのスレッド が揮発性フィールドにアクセスすると、キャッシュされた値を使用する代わりに、 が続行される前に現在の値を読み取ることを意味します。 (ただし、 揮発性読み取りの相対的な順序については保証がありません 通常の読み取りと書き込みで書き込みます。つまり、一般に有用なスレッド構造ではありません。つまり、 です。)揮発性の読み取りと多くの取得と ミューテックスを解放するように、 は事前発生関係を確立書き込み

  2. ()は、Java 5以降では。

もっとinfo

+2

しかし、私は私の質問に答えなかった。 :) – Trying

0

この場合、リソースは、あなたが説明するレースのために2回構築されることがあります。 Java 5以降でシングルトン(明示的なロックなし)を実装する場合は、What is an efficient way to implement a singleton pattern in Java?の回答に記載されているようにenumシングルトンを使用します。

7

あなたはより良い解決策を求めているわけではありませんが、怠惰なシングルトン解決策を探しているなら、これは絶対に価値があります。

シングルトンを読み込むためにプライベート静的クラスを使用します。クラスは呼び出されるまでロードされないため、クラスが参照されるまで参照はロードされません。実装によるクラスのロードはスレッドセーフであり、オーバーヘッドはほとんどありません(反復的な揮発性の負荷[安価かもしれません]の場合、初期の構築後に常にこの通常の負荷がロードされます)。

class MyClass { 
    public static Resource getInstance() { 
     return ResourceLoader.RESOURCE; 
    } 

    private static final class ResourceLoader { 
     private static final Resource RESOURCE = new Resource(); 
    } 
} 
0

まず、このようにシングルトンを使用すると、本質的にグローバルオブジェクトを作成することになりますが、これは悪い習慣です。代わりにEnumを使うと思う。

+3

しかしEnumもグローバルです。 –

0

揮発性を追加する私の提案はここに&一緒に同期化されます。

注:まだ確認する必要はありません。

public class MySingleton { 
    private static volatile MySingleton instance; 
    private MySingleton() {} 

    synchronized private static void newInstance() { 
     if(instance == null) { 
      instance = new MySingleton(); 
     } 
    } 

    public static MySingleton get() { 
     if(instance == null) { 
      newInstance(); 
     } 
     return instance; 
    } 
}