2016-08-25 13 views
0

私は静的な値の危険な初期化を持っているライブラリを持っています(この例ではクラスは最小限にされています):はFindBugs 'JLM_JSR166_UTILCONCURRENT_MONITORENTER'はこの場合無視してください

public TheirBaseClass { 
    public static String PathToUse = null; 

    public BaseClass(){ 
     PathToUse = "Configured"; 

     // ... 
     // do some other stuff with other side effects 
     // ... 
    } 
} 

値をConfigValueから読み込み、クラスのインスタンスを作成せずに(一部の副作用を避けるため)、私はそのケースがあります。

Paths.get(TheirBaseClass.PathToUse).toFile().... 

これは、静的にアクセスするとき、私はこのクラスを使用するために必要ですので、私はそれを継承し、その初期化を確実にするために行動を取るしようとしているよNullPointerException

が行われた原因となります。

MyBaseClass.Initialize(); 
Paths.get(MyBaseClass.PathToUse).toFile().... 

に私を可能に

public MyBaseClass extends TheirBaseClass{ 

    private static final AtomicBoolean isInitialized = new AtomicBoolean(false); 

    static { 
     MyBaseClass.Initialize(); 
    } 

    public static void Initialize(){ 
     // FindBugs does not like me synchronizing on a concurrent object 
     synchronized(isInitialized){ 
      if(isInitialized.get()){ 
       return; 
      } 
      new TheirBaseClass(); 
      isInitialized.set(true); 
     } 
    } 

    public MyBaseClass(){ 
     super(); 
    } 

} 

は、この合理的にうまく機能しているようだ(と私たちが持ってきたいくつかの他のファントムの欠陥を解決します)。それはTheirBaseClassが自然に機能することを可能にしますが、私が必要とするかもしれない2つのケースでは初期化を安全に強制することができます。

しかし、このコードに対してFindBugsを実行すると、JLM_JSR166_UTILCONCURRENT_MONITORENTERとなります。説明を読んだ後、私は

  1. が、私はこのケースでは無視してその安全を考える(ただし、疑問を持っている)...他の誰かが値を変更する可能性があるためAtomicBooleanの使用は危険なことができることを同意するが、
  2. 私は通常、無視マーカーを置くよりもコードを書き直すほうがいいです

私は実際に何か危険なことをしています(それは見えません)?これを行うより良い方法はありますか?

残念ながら、別のTheirBaseClassを使用することはできません。

あなたはそれが簡単に適応するかもしれません

答えて

1

関連lazy holder idiom:これは、クラスのロードが一度だけ起こると同期しているという事実を使用しています

public MyBaseClass { 
    private static class Initializer { 
    static { 
     new TheirBaseClass(); 
    } 

    // Doesn't actually do anything; merely provides an expression 
    // to cause the Initializer class to be loaded. 
    private static void ensureInitialized() {} 
    } 

    { 
    Initializer.ensureInitialized(); 
    } 

    // Rest of the class. 
} 

(単一のクラスローダー内で)。 MyBaseClassをインスタンス化した場合にのみ発生します。

+0

私は私の例で大失敗したと思う:私は 'TheirBaseClass'を拡張しなかった –

+0

私はこれを熟考しなければならなかった。私はすでに 'lazy holder'を実装しています。あなたの答えは正しいですが、混乱はブール値の周りに発生しているように見えます。それはまったく必要ありません。私はそれを特定のケースで導入しましたが、そのケースはますますリファクタリングがなくなったようです。 –

+0

ブール値は必要ありません*私は初期化子をプライベートにする場合* –

関連する問題