2016-03-15 5 views
5
public void tSafe(List<Foo> list, Properties status) { 
    if(list == null) return; 
    String key = "COUNT"; 
    AtomicInteger a = new AtomicInteger(Integer.valueOf(status.getProperty(key,"0"))); 
    list.parallelStream().filter(Foo::check). 
      forEach(foo -> {status.setProperty(key, String.valueOf(a.incrementAndGet())); } 
    ); 

} 

private interface Foo { 
    public boolean check(); 
} 

説明:上記の例でメソッド内でローカル変数としてAtomicIntegerを使用し、スレッドの安全性を確保できますか?

、ステータスは、共有の特性であり、それは名前COUNTとキーを含みます。私の目的は、カウントを増やしてプロパティに戻して、実行されたチェックの数を数えることです。 tSafeメソッドが複数のスレッドから呼び出されているとします。最後に正しい数を取得しますか? AtomicIntegerをローカル変数として使用したことに注意してください。

+0

スレッドセーフは、スレッドの安全性をもたらすさまざまなマルチスレッド構成要素の周りに振りかけるものではありません。 – Raedwald

答えて

0

スレッドが1つしかない場合はこれが有効ですが、複数のスレッドでこれを呼び出すと、スレッドセーフな操作がいくつかあります。これは、各スレッドが異なるliststatusオブジェクトで動作する場合は問題ありません。

statusはスレッドセーフなコレクションであり、ロックすることができます。listが別のスレッドで変更されていない場合は、このようになります。

一般に、文字列をスレッドセーフな方法で数値として扱うのは非常に難解です。あなたは値のスレッド、つまりAtomicIntegerを作ることがずっと優れています。

0

これはスレッドの安全を保証しません。 incrementAndGet()自体がアトミックであっても、Propertiesオブジェクトから値を取得して戻すことはできません。

次のシナリオを検討し

  1. スレッド#1をPropertiesオブジェクトから値を取得します。議論のために、それが "100"だとしましょう。
  2. スレッド#2はPropertiesオブジェクトから値を取得します。何も起こっていないので、この値はまだ "100"です。
  3. スレッド#1はAtomicIntegerを作成し、それを増やし、Propertiesオブジェクトに「101」を配置します。
  4. スレッド#2はまったく同じで、期待した102の代わりにPropertiesオブジェクトに「101」を置きます。

EDIT:
より生産性の高いノートで、より良いアプローチは、ちょうどあなたのステータスマップ上AtomicIntegerを格納すること、およびインプレース、それをインクリメントします。そうすれば、あなたは単一のインスタンスを持ち、上記のようにレースについて心配する必要はありません。 PropertiesクラスがHashtable<Object, Object>を拡張したようPropertiesが本当にStringのない値のために意図されていないが、これは技術的には、動作するはずです、そしてあなたは、ConcurrentHashMapなど、近代的なスレッドセーフMap実装とオフはるかに良いと思います。

public void tSafe(List<Foo> list, ConcurrentMap<String, AtomicInteger> status) { 
    if(list == null) { 
     return; 
    } 
    String key = "COUNT"; 
    status.putIfAbsent(key, new AtomicInteger(0));  
    list.parallelStream() 
     .filter(Foo::check) 
     .forEach(foo -> { status.get(ket).incrementAndGet(); }); 
} 
+0

So ..私はAtomicIntegerを静的な最終変数として、代わりにローカル変数として使用する必要がありますか?スレッドセーフティを達成するためにAtomic *を使用するベストプラクティスは何ですか? –

+0

@aravindpogu私はより良いアプローチ(もちろん、IMHO)を記述しようとしました。私の編集された答えを見てください。 – Mureinik

+0

[putIfAbsent](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentMap.html#putIfAbsent(K、%20V))では、最初の引数としてキーが必要です。値は 'statusです。 – Ferrybig

関連する問題