JUC并发编程之集合类线程安全问题

在并发条件下,由于多数集合没有同步控制所以这些集合具有线程不安全性

线程不安全的集合

JUC并发编程之集合类线程安全问题_第1张图片

线程不安全用例(ArrayList为例)

示例

public class MainTest {
    public static void main(String[] args) {
        ArrayList<String> arrayList = new ArrayList<>();
        for(int i=0; i< 10; i++) {
            new Thread(() -> {
                arrayList.add(UUID.randomUUID().toString());
                System.out.println(arrayList);
            },String.valueOf(i)).start();
        }
    }
}

运行会抛出

java.util.ConcurrentModificationException

并发修改异常
出现该异常的原因是,当某个线程正在执行 add()方法时,被某个线程打断,添加到一半被打断,没有被添加完。

解决ArrayList线程不安全问题

  • 可以使用 Vector 来代替 ArrayList,Vector 是线程安全的 ArrayList,但是由于,并发量太小,被淘汰;
  • 使用 Collections.synchronizedArrayList() 来创建 ArrayList;使用 Collections 工具类来创建 ArrayList 的思路是,在 ArrayList 的外边套了一个synchronized外壳,来使 ArrayList 线程安全;
  • 使用 CopyOnWriteArrayList()来保证 ArrayList 线程安全;

CopyOnWriteArrayList

此类采用了写时复制技术,从读写分离的角度去保证了线程的安全性
CopyWriteArrayList之所以线程安全的原因是在源码里面使用 ReentrantLock,所以保证了某个线程在写的时候不会被打断;

/** The array, accessed only via getArray/setArray. */
    private transient volatile Object[] array;

/** The lock protecting all mutators */
    final transient ReentrantLock lock = new ReentrantLock();

  /**
     * Gets the array.  Non-private so as to also be accessible
     * from CopyOnWriteArraySet class.
     */
    final Object[] getArray() {
        return array;
    }

/**
     * Appends the specified element to the end of this list.
     *
     * @param e element to be appended to this list
     * @return {@code true} (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            newElements[len] = e;
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
    }

可以看到源码开始先是复制了一份数组(因为同一时刻只有一个线程写,其余的线程会读),在复制的数组上边进行写操作,写好以后在返回 true。
这样写的就把读写进行了分离.写好以后因为 array 加了 volatile 关键字,所以该数组是对于其他的线程是可见的,就会读取到最新的值

集合对应线程安全类

List CopyOnWriteArrayList
Set CopyOnWriteArraySet
Map ConcurrentHashMap

ConcurrentHashMap实现线程安全原理与其他不一致
ConcurrentHashMap​

你可能感兴趣的:(JUC并发编程,java,集合,线程安全,多线程,并发编程)