小テストプログラム:
public class Test extends Thread {
public static void main(String[] args) throws Exception {
test(new Vector<>());
test(new ArrayList<>());
test(Collections.synchronizedList(new ArrayList<>()));
test(new CopyOnWriteArrayList<>());
}
private static void test(final List<Integer> list) throws Exception {
System.gc();
long start = System.currentTimeMillis();
Thread[] threads = new Thread[10];
for (int i = 0; i < threads.length; i++)
threads[i] = new Test(list);
for (Thread thread : threads)
thread.start();
for (Thread thread : threads)
thread.join();
long end = System.currentTimeMillis();
System.out.println(list.size() + " in " + (end - start) + "ms using " + list.getClass().getSimpleName());
}
private final List<Integer> list;
Test(List<Integer> list) {
this.list = list;
}
@Override
public void run() {
try {
for (int i = 0; i < 10000; i++)
this.list.add(i);
} catch (Exception e) {
e.printStackTrace(System.out);
}
}
}
サンプル出力追加した後に予想されるサイズですVector
それが正常に完了し、100000
を返す、と
100000 in 16ms using Vector
java.lang.ArrayIndexOutOfBoundsException: 466
at java.util.ArrayList.add(ArrayList.java:459)
at Test.run(Test.java:36)
java.lang.ArrayIndexOutOfBoundsException: 465
at java.util.ArrayList.add(ArrayList.java:459)
at Test.run(Test.java:36)
java.lang.ArrayIndexOutOfBoundsException: 10
at java.util.ArrayList.add(ArrayList.java:459)
at Test.run(Test.java:36)
32507 in 15ms using ArrayList
100000 in 16ms using SynchronizedRandomAccessList
100000 in 3073ms using CopyOnWriteArrayList
あなたが見ることができるように、 10個の並列スレッド内の10000個の値。スレッドの
Collections.synchronizedList()
を使用する3番目のテストは、Vector
のように機能します。
第4のテストでは、CopyOnWriteArrayList
を同時に使用すると、過剰なコピーによって正しい結果が生成されますが、はるかに遅くなります。ただし、リストが小さく、変更頻度は少ないが頻繁に読み取られる場合は、同期アクセスよりも高速になります。
リストを反復処理する必要がある場合は、およびsynchronizedList()
も、反復処理中にリストが変更された場合はConcurrentModificationException
で失敗し、CopyOnWriteArrayList
はリストのスナップショットを反復するため、特に便利です。好奇心のうち
、私もいくつかのDeque
実装を確認:
test(new ArrayDeque<>());
test(new ConcurrentLinkedDeque<>());
test(new LinkedBlockingDeque<>());
をサンプル出力
34295 in 0ms using ArrayDeque
100000 in 15ms using ConcurrentLinkedDeque
100000 in 16ms using LinkedBlockingDeque
あなたが見ることができるように、非同期のArrayDeque
は "失われた値" を示しただし、例外は発生しません。
2つの並行実装ConcurrentLinkedDeque
とLinkedBlockingDeque
は正常に動作します。でもあなたはArrayList
は、より多くのループの反復を行うことでスレッドセーフされていないことを示すことができ、あなたの簡単なプログラムで
ちょっと私はそれを探してみましたが、それは別の、より便利な話題ではない、このような基本的な例に私を取って続けています。 –
スレッド(un)の安全性をテストする場合は、複数のスレッドで同じコレクションにアクセス/変更する必要があります。今度は、2つのベクトルを作成し、それぞれに1つのスレッドでアクセスします。 – Ma3x
申し訳ありませんが、私の間違いは私に修正して見せてください。 –