エントリから高度な(6)までのマルチスレッド-マルチスレッド環境での安全クラスの設定-設定

1. HashSetスレッドは安全ですか?

HashSetの最下層はHashMapです。前の記事から、HashMapはスレッドセーフではないことがわかっているため、HashSetもスレッドセーフではありません。たとえば、次のコードを確認できます。

public class HashSetDemo {
    
    
    public static void main(String[] args) {
    
    
        Set<Integer> set = new HashSet<>();
        for (int i = 0; i < 30; i++) {
    
    
            final int temp = i;
            new Thread(() -> {
    
    
                set.add(temp);
                System.out.println(set);
            },String.valueOf(temp)).start();
        }
    }
}

画像-20210316105612607

ConcurrentModificationExceptionも報告されます。HashSetもスレッドセーフではないことがわかります。同様に、HashSetのスレッドセーフの問題を解決するにはどうすればよいですか。

二、同期セット

Listとmapがスレッドセーフを解決する方法と同様に、CollectionsクラスもSynchronizedSetクラスであるスレッドセーフセットを提供します。SynchronizedSetクラスはSynchronizedListルーチンと一貫性があり、のさまざまなメソッドでもあります。着信HashSet。同期ロックを増やす

3、CopyOnWriteArraySet

非反復リストとして設定すると、リストにはCopyOnWriteArrayListがあり、CopyOnWriteArraySetになるために少し変更するだけで済み、CopyOnWriteArraySetはまさにこれを行います。

public class CopyOnWriteArraySet<E> extends AbstractSet<E>
        implements java.io.Serializable {
    
    
    private static final long serialVersionUID = 5457747651344034263L;

    private final CopyOnWriteArrayList<E> al;

CopyOnWriteArraySetの基礎となるデータ構造はCopyOnWriteArrayListであることがわかります。CopyOnWriteArrayListは、コピーオンライトと読み取り/書き込みの分離の概念を採用しています。したがって、CopyOnWriteArraySetには、書き込みが少ない読み取りである特定のシナリオで高いパフォーマンスが得られるという利点もあります。もっと

CopyOnWriteArraySetのaddメソッドを見てください

public boolean add(E e) {
    
    
    return al.addIfAbsent(e);
}
private boolean addIfAbsent(E e, Object[] snapshot) {
    
    
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
    
    
        Object[] current = getArray();
        int len = current.length;
        if (snapshot != current) {
    
    
            // Optimize for lost race to another addXXX operation
            int common = Math.min(snapshot.length, len);
            for (int i = 0; i < common; i++)
                if (current[i] != snapshot[i] && eq(e, current[i]))
                    return false;
            if (indexOf(e, current, common, len) >= 0)
                return false;
        }
        Object[] newElements = Arrays.copyOf(current, len + 1);
        newElements[len] = e;
        setArray(newElements);
        return true;
    } finally {
    
    
        lock.unlock();
    }
}

このコードも理解しやすいです。まず、元の配列に追加する要素があるかどうかを確認します。ある場合は、再度追加しないでください。そうでない場合は、新しい配列を作成し、前の配列要素をコピーして、新しい要素を追加します。

次に、removeメソッドを確認します。これは、CopyOnWriteArrayListのremoveメソッドへの直接呼び出しでもあります。

public boolean remove(Object o) {
    
    
    return al.remove(o);
}

おすすめ

転載: blog.csdn.net/weixin_44706647/article/details/114880848