Skip to content

集合线程不安全演示

java
package io.alex.concurrent;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

public class UnsafeListDemo {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                list.add(UUID.randomUUID().toString().substring(0,8));
                System.out.println(list);
            }).start();
        }
    }
}

集合不安全的原因

  • 缺乏同步, ArrayList 中的操作方法(如 add, remove, get 等)并没有内置的同步机制。因此,在并发环境下,多个线程同时修改 ArrayList 可能会导致数据不一致或其它问题。
  • 结构修改时的并发问题:在结构修改(如增删元素)过程中,ArrayList 可能需要调整内部数组的大小或者元素的位置。如果这些操作在没有同步保护的情况下被并发执行,可能会导致数组越界或数据丢失。
  • 解决方法:使用线程安全的集合类,如VectorCollections.synchronizedListCopyOnWriteArrayList等。

Vector 和 ArrayList 的区别

  • Vector 是通过 synchronized 关键字来保证线程安全的,而 ArrayList 是非线程安全的。

Collections.synchronizedList

  • Collections.synchronizedList 方法返回一个线程安全的 List,它通过对 List 的每个方法调用都加上了 synchronized 关键字来实现线程安全。

CopyOnWriteArrayList

  • CopyOnWriteArrayList 是一个线程安全的 List,它通过在修改操作时,对原有数组进行复制来实现线程安全。因此,CopyOnWriteArrayList 适用于读多写少的场景。
  • CopyOnWriteArrayList 的缺点是在写操作时,需要复制一个新的数组,因此写操作的性能较差。
  • CopyOnWriteArrayList 的优点是读操作不需要加锁,因此读操作的性能较好。
  • CopyOnWriteArrayList.add() 的源码:
java
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();
    }
}