1

スレッドセーフなコレクションがあると仮定すると、次のように入力します。

   Set set = new HashSet();
   for (Map map : maps) {
        set.addAll(doSomeExpensiveProcessing(map.keySet()));
    }

これを同時に実行する最良の方法は何でしょうか? (つまり、各マップはそのキーを同時にセットに追加します。

編集 - HashSet がスレッドセーフではないことは承知していますが、私に関する限り、それは質問の範囲外です。

EDIT2 - この特定のシナリオでは、同時実行によって大きなメリットが得られないことが正しく指摘されましたが、コード例に含まれている追加の手順があります。

4

3 に答える 3

1

@OldCurmudgeon には優れた基本的なアプローチがありますが、より深刻なコードでは、おそらくCallableキーの高価な処理を行い、 new を返すを作成する必要がありますCollection。Executor や CompletionService と組み合わせることができます。最後に並行コレクションも必要ありません。

たとえば、キーが文字列の場合

public class DoesExpensiveProcessing implements Callable<Set<String>> {

   final Set<String> inKeys;

   public DoesExpensiveProcessing(Set<String> keys) {
     this.inKeys = keys;  // make a defensive copy if required...
   }

   public Set<String> call() {
      // do expensive processing on inKeys and returns a Set of Strings
   }
}

この時点では、並列コレクションも必要ありません

List<DoesExpensiveProcessing> doInParallel = new ArrayList<DoesExpensiveProcessing>();
for (Map map : maps) {
   doInParallel.add(new DoesExpensiveProcessing(map.keySet()));
}

Set theResultingSet = new HashSet<String>();
List<Future<Set<String>>> futures = someExecutorService.invokeAll(doInParallel);
for (Future<Set<String>> f : futures) {
  theResultingSet.addAll(f.get());
}
于 2013-05-21T16:32:25.113 に答える
0

そうすれば、同時にはなりませんが、少なくともスレッドセーフです。

Set set = Collections.synchronizedSet(new HashSet());
...
// in some other threads:
for (Map map : maps) {
  set.addAll(map.keySet());
}

または、次のようなものが好きですか。

ConcurrentMap<Object, Boolean> set = new ConcurrentHashMap<Object, Boolean>();
...
// in some other threads:
for (Map map : maps) {
  for (Object o : map.keySet()) {
    set.putIfAbsent(o, true);
  }
}
于 2013-05-21T15:26:05.397 に答える