集合
我们知道ArrayList类是线程不安全的,如果运行以下代码:
public class un_list {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
for (int i = 0; i < 100; i++) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0, 5));
System.out.println(list);
}).start();
}
}
}
会有ConcurrentModificationException
。
Vector
则是线程安全的:
public class un_list {
public static void main(String[] args) {
// ArrayList<String> list = new ArrayList<>();
Vector<String> list = new Vector<>();
for (int i = 0; i < 100; i++) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0, 5));
System.out.println(list);
}).start();
}
}
}
这是由于vector
的方法是加了synchronized
的
还可以用Collections.synchronizedList(new ArrayList<>()) :
public class un_list {
public static void main(String[] args) {
// ArrayList<String> list = new ArrayList<>();
// Vector<String> list = new Vector<>();
List<String> list = Collections.synchronizedList(new ArrayList<>());
for (int i = 0; i < 100; i++) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0, 5));
System.out.println(list);
}).start();
}
}
}
还有一种方法,就是使用CopyOnWriteArrayList
public class un_list {
public static void main(String[] args) {
// ArrayList<String> list = new ArrayList<>();
// Vector<String> list = new Vector<>();
// List<String> list = Collections.synchronizedList(new ArrayList<>());
List<String> list = new CopyOnWriteArrayList<>();
for (int i = 0; i < 100; i++) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0, 5));
System.out.println(list);
}).start();
}
}
}
CopyOnWriteArrayList 是通过 Copy-On-Write(COW),即写时复制的思想来通过延时更新的策略实现数据的最终一致性,并且能够保证读线程间不阻塞。当然,这要牺牲数据的实时性。
通俗的讲,CopyOnWrite 就是当我们往一个容器添加元素的时候,不直接往容器中添加,而是先复制出一个新的容器,然后在新的容器里添加元素,添加完之后,再将原容器的引用指向新的容器。多个线程在读的时候,不需要加锁,因为当前容器不会添加任何元素。
如何实现的?点进源码看看:
transient volatile
是啥?那先放到一边吧,总之就是用这个实现了并发安全呗。
那为什么要用CopyOnWriteArrayList
不用vector
呢?上面我们展示了vector
的add
方法,下面看看CopyOnWriteArrayList
的读写:
写通过同步代码块保证并发,读则没有加锁。所以读的性能非常高。