CopyOnWriteArrayList

HeJin大约 1 分钟JavaJUC并发编程

ArrayList并发修改异常

public class ListTest {
    public static void main(String[] args) {
        List<String> list = new ArrayList();

        for (int i = 1; i <= 10; i++) {
            new Thread(() -> {
                list.add(UUID.randomUUID().toString().substring(0,5));
                System.out.println(list);
            },String.valueOf(i)).start();
        }
    }
}

程序报错(多运行几次,也有不报错的):

[74b29, 086cd, 944b4]
[74b29, 086cd, 944b4, 98fb1, c9918, 3068b]
[74b29, 086cd, 944b4, 98fb1, c9918, 3068b, 928f0, 5f0d6, 0dd3f]
[74b29, 086cd, 944b4, 98fb1, c9918]
[74b29, 086cd, 944b4, 98fb1]
[74b29, 086cd, 944b4]
[74b29, 086cd, 944b4, 98fb1, c9918, 3068b, 928f0, 5f0d6]
[74b29, 086cd, 944b4, 98fb1, c9918, 3068b, 928f0]
Exception in thread "3" Exception in thread "1" java.util.ConcurrentModificationException

java.util.ConcurrentModificationException 并发修改异常。

并发下,ArrayList是不安全的。

解决办法

1、使用线程安全集合Vector

List<String> list = new Vector<>();
[324d5, c50d1]
[324d5, c50d1, 7dcc0, 6381a, dfd0d, 9e06f, b9e1c, 26a1b, b95c0, 7b0fb]
[324d5, c50d1, 7dcc0, 6381a, dfd0d, 9e06f, b9e1c, 26a1b, b95c0]
[324d5, c50d1, 7dcc0, 6381a, dfd0d, 9e06f, b9e1c, 26a1b]
[324d5, c50d1, 7dcc0, 6381a, dfd0d, 9e06f, b9e1c]
[324d5, c50d1, 7dcc0, 6381a, dfd0d, 9e06f, b9e1c]
[324d5, c50d1, 7dcc0, 6381a, dfd0d, 9e06f]
[324d5, c50d1, 7dcc0, 6381a, dfd0d]
[324d5, c50d1, 7dcc0, 6381a]
[324d5, c50d1, 7dcc0]

Process finished with exit code 0

2、使用集合工具类Collections.synchronizedList

List<String> list = Collections.synchronizedList(new ArrayList<>());

3、JUC包下的CopyOnWriteArrayList类

List<String> list = new CopyOnWriteArrayList<>();
image-20210311170337561
image-20210311170337561

CopyOnWrite写入时复制

COW:计算机程序设计领域的一种优化策略。

多个线程调用的时候,读取的时候list是固定的。写入的时候可能会存在覆盖操作。在写入的时候,避免覆盖造成数据问题。

读写分离。

CopyOnWriteArrayList的优势

Vector直接在方法上使用synchronized加了锁,性能较低。

image-20210311171002010
image-20210311171002010

CopyOnWriteArrayList使用的是Lock锁。性能更好。

image-20210311171108049
image-20210311171108049