ArrayListとCopyOnWriteArrayListスレッドセキュリティテスト

3565 ワード

ArrayListは非スレッドセキュリティであり、CopyOnWriteArrayListはスレッドセキュリティであり、読み取り操作時にロックされていないArrayListであり、同時アクセスに適している.集合要素数が10000、スレッド数が100の場合に性能テストを行い、要素数とスレッド数の増加に伴い、CopyOnWriteArrayListは要素の増加と削除時の性能低下が著しく、ArrayListよりも性能が低下する.しかし、要素を検索する点ではスレッド数が増えるにつれて、ArrayListよりもパフォーマンスが向上します.
 
したがって、読み書きが少ない同時シーンでは、CopyOnWriteArrayListはArrayListよりも良い選択である.
 
 
次の2つの方法のスレッドを安全にテストします.
 
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

public class ThreadSafeDemo {
    public static int demo(final List list, final int testCount) throws InterruptedException {
        ThreadGroup group = new ThreadGroup(list.getClass().getName() + "@" + list.hashCode()); 
        final Random rand = new Random(); 
        
        Runnable listAppender = new Runnable() {  //  Runnable , run 
            public void run() {
                try {
                    Thread.sleep(rand.nextInt(2));
                } catch (InterruptedException e) {
                    return; 
                } 
                list.add("0"); 
            }
        }; 
        
        for (int i = 0; i < testCount; i++) {
            new Thread(group, listAppender, "InsertList-" + i).start(); 
                             //java.lang.Thread
.Thread(ThreadGroup
 group, Runnable
 target, String
 name)
        
      }
        
        while (group.activeCount() > 0) {
            Thread.sleep(10); 
        }
        
        return list.size(); 
    }
    public static void main(String[] args) throws InterruptedException {
        List unsafeList = new ArrayList(); 
        List safeList = Collections.synchronizedList(new ArrayList()); //  new CopyToWriteArrayList
        final int N = 10000; 
        for (int i = 0; i < 10; i++) {
            unsafeList.clear(); 
            safeList.clear(); 
            int unsafeSize = demo(unsafeList, N); 
            int safeSize = demo(safeList, N); 
            System.out.println("unsafe/safe: " + unsafeSize + "/" + safeSize); 
        }
    }
}

 
テストの結果は次のとおりです.
unsafe/safe: 9992/10000 unsafe/safe: 9996/10000 unsafe/safe: 9990/10000 unsafe/safe: 9992/10000 unsafe/safe: 9997/10000 unsafe/safe: 9997/10000 unsafe/safe: 9993/10000 unsafe/safe: 9995/10000 unsafe/safe: 9993/10000 unsafe/safe: 9995/10000
 
不安全なスレッドlist数が10000未満になる理由は、主に2つあります.
まずArrayListのソースコードを見てみましょう.
 
public boolean add(E e) { ensureCapacity(size + 1);//Increments modCount!! elementData[size++] = e; return true; }
 
主な問題はsize++です.この方法はスレッドが安全ではないため、次の2つの状況が発生する可能性があります.
1)スレッドAはスレッドBと同様にsize=10を取得する、同じ位置10に2回値を挿入した後、いずれもsize++を実行した結果、sizeは12となり、次にスレッドが入ると12の位置で値を挿入し続けるが、11はnullとなり、実験ではやはりそうであったが、list 1の理由は説明できない.sizeの値が減少し、リストにnullの値がある理由しか説明できません.
2)size++この操作は同様にスレッドが安全ではなく、2つのステップに分けられている.第1に、sizeの位置を取り、第2に、sizeの位置を+1とする.これにより、AスレッドとBスレッドが同時にsizeの位置を取り、+1となる可能性がある.これにより、A、Bスレッドがsize++を実行した後、sizeの値は12ではなく11となるため、異なるスレッドが同時に1つの位置に値を付与し、listの数が不足する.