2016-09-26 2 views
0

ArrayListはスレッドセーフではなく、VectorListです。私は、ArrayListではなく、VectorListで同期して操作が実行されていることを示すプログラムを作成したかったのです。唯一の問題は、私は直面している方法ですか?どのような操作ですか?
例: - リストのいずれかに値を追加すると、プログラムは単に値を追加します。
私は1つを作ろうとしましたが、私のプログラムはArrayListやVectorListではなく、変数jに依存しています。arraylist javaの非同期性を表示するにはどうすればよいですか?

public class ArrayDemo implements Runnable { 

    private static ArrayList<Integer> al = new ArrayList<Integer>(); 
    Random random = new Random(); 
    int j = 0; 
    public void run() { 
     while (j < 10) { 
      int i = random.nextInt(10); 
      al.add(i); 
      System.out.println(i + " "+ Thread.currentThread().getName()); 
      j++; 
      //System.out.println(al.remove(0)); 
     } 

    } 

    public static void main(String[] args) { 
     ArrayDemo ad = new ArrayDemo(); 
     Thread t = new Thread(ad); 
     Thread t1 = new Thread(ad); 
     t.start();t1.start(); 
    } 

} 
+0

ちょっと私はそれを探してみましたが、それは別の、より便利な話題ではない、このような基本的な例に私を取って続けています。 –

+1

スレッド(un)の安全性をテストする場合は、複数のスレッドで同じコレクションにアクセス/変更する必要があります。今度は、2つのベクトルを作成し、それぞれに1つのスレッドでアクセスします。 – Ma3x

+0

申し訳ありませんが、私の間違いは私に修正して見せてください。 –

答えて

1

小テストプログラム:

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個の値。スレッドの

  • スリーがadd()への呼び出しでArrayIndexOutOfBoundsExceptionで死ぬ:ArrayList

    は、次の2つの異なる障害を参照してください。

  • 追加する前に、3つの失敗したスレッドが直ちに終了したとしても、残りの7つのスレッドはそれぞれ10000の値を合計して合計で70000の値になりますが、リストには32507の値しか含まれません。失われた

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つの並行実装ConcurrentLinkedDequeLinkedBlockingDequeは正常に動作します。でもあなたはArrayListは、より多くのループの反復を行うことでスレッドセーフされていないことを示すことができ、あなたの簡単なプログラムで

+0

偉大な答え、分かりやすい。私は実装したコレクションの半分を使用していません。もう1つ、ArrayDequeについて言及した "失われた価値"の症状について説明できますか? –

+1

@SaurabhGuptaこれは 'ArrayList'にも見られる第2の弾です。私は単にこれを参照しようとしていました。 – Andreas

1

(10は十分ではないかもしれません)とArrayListの操作を遅くする他のコード、System.outなど特にIOコードを減らします。

RandomSystem.outを削除して元のコードを修正しました。私はループの最後にただ一つのSystem.out.printlnを追加して、終了の可能性があることを示しました。

ただし、このコードは完全には実行されません。代わりに例外がスローされます。

Exception in thread "Thread-1" java.lang.ArrayIndexOutOfBoundsException: ... 

これは、類似したコードであってもタイミングが正しくない場合、スレッドセーフティの問題にならないことがあります。これは、スレッド関連のバグが見つからず、実際にプログラムをクラッシュさせる前に、コード内に潜んでいる可能性があることを示しています。ここで

が変更されたコードです:

import java.util.*; 

public class ArrayDemo implements Runnable { 

    private static ArrayList<Integer> al = new ArrayList<Integer>(); 

    int j = 0; 
    public void run() { 
     while (j < 10000) { 
      al.add(new Integer(1)); 
      j++; 
     } 
     System.out.println("Array size: " + al.size()); 
    } 

    public static void main(String[] args) { 
     ArrayDemo ad = new ArrayDemo(); 
     Thread t = new Thread(ad); 
     Thread t1 = new Thread(ad); 
     t.start(); 
     t1.start(); 
    } 

}