Collections.synchronizedListの使用方法

3713 ワード

ArrayList
ArrayListは非スレッドで安全であることはよく知られているが、マルチスレッドの場合、リストにデータを挿入する場合、データが失われるおそれがある.一方のスレッドがListを巡回する、他方のスレッドがListを修正すると、ConcurrentModificationException(同時修正異常)エラーが報告される.
Vector
Vectorはスレッドの安全なリストであるが、そのスレッドの安全な実現方式はすべての操作にsynchronizedキーワードを加えたものであり、効率に深刻な影響を及ぼす.従って、Vectorの使用は推奨する.
Collections.synchronizedList(List list)
リストのスレッドセキュリティを実現するにはCollectionsを使用します.synchronizedList、まずその使い方を見てみましょう.
使用方法
List list = Collections.synchronizedList(new ArrayList());
list.add("1");
list.add("2");
list.add("3");

synchronized (list) {
    Iterator i = list.iterator(); // Must be in synchronized block
    while (i.hasNext()) {
        //foo(i.next());
        System.out.println(i.next());
    }
}

なぜadd()はsynchronizedを必要とせず、遍歴するときにsynchronizedを追加する必要があるのですか?
まずCollectionsを見てみましょうsynchronizedListのソースコード
Collections.synchronizedListのソースコード
public static  List synchronizedList(List list) {
    return (list instanceof RandomAccess ?
            new SynchronizedRandomAccessList<>(list) :
            new SynchronizedList<>(list));
}

この方法は、あなたが入力したListがRandomAccessというインタフェースを実装するかどうかによって返されるSynchronizedRandomAccessListかSynchronizedListかを返します.
次にSynchronizedListのソースコードを見てみましょう
SynchronizedListソースコード
static class SynchronizedList
    extends SynchronizedCollection
    implements List {
    private static final long serialVersionUID = -7754090372962971524L;

    final List list;

    SynchronizedList(List list) {
        super(list);
        this.list = list;
    }
    SynchronizedList(List list, Object mutex) {
        super(list, mutex);
        this.list = list;
    }

    public boolean equals(Object o) {
        if (this == o)
            return true;
        synchronized (mutex) {return list.equals(o);}
    }
    public int hashCode() {
        synchronized (mutex) {return list.hashCode();}
    }

    public E get(int index) {
        synchronized (mutex) {return list.get(index);}
    }
    public E set(int index, E element) {
        synchronized (mutex) {return list.set(index, element);}
    }
    public void add(int index, E element) {
        synchronized (mutex) {list.add(index, element);}
    }
    public E remove(int index) {
        synchronized (mutex) {return list.remove(index);}
    }

    public int indexOf(Object o) {
        synchronized (mutex) {return list.indexOf(o);}
    }
    public int lastIndexOf(Object o) {
        synchronized (mutex) {return list.lastIndexOf(o);}
    }

    public boolean addAll(int index, Collection extends E> c) {
        synchronized (mutex) {return list.addAll(index, c);}
    }

    public ListIterator listIterator() {
        return list.listIterator(); // Must be manually synched by user
    }

    public ListIterator listIterator(int index) {
        return list.listIterator(index); // Must be manually synched by user
    }

    public List subList(int fromIndex, int toIndex) {
        synchronized (mutex) {
            return new SynchronizedList<>(list.subList(fromIndex, toIndex),
                                        mutex);
        }
    }

    @Override
    public void replaceAll(UnaryOperator operator) {
        synchronized (mutex) {list.replaceAll(operator);}
    }
    @Override
    public void sort(Comparator super E> c) {
        synchronized (mutex) {list.sort(c);}
    }
    ... ...
}

add()などのメソッドを実行する際にsynchronizedのキーワードが付けられていることがわかるが、listIterator()、iterator()は付けていない.だから使用するときはsynchronizedを加える必要があります.