Java多线程之集合类(浅析线程安全和不安全)
本文目录:
-
1.线程不安全之
ArrayList
,HashSet
,HashMap
和线程安全之CopyOnWriteArrayList
,CopyOnWriteArraySet
,ConcurrentHashMap
-
2. 小结
-
3.解析CopyOnWrite容器
1.线程不安全之ArrayList
和线程安全之CopyOnWriteArrayList
测试代码:
- 多个线程往一个集合中添加内容。
实现:
public static void listNotSafe() {
List<String> list = new ArrayList<>();
for (int i = 1; i <= 30 ; i++) {
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,6));
System.out.println(list);
},String.valueOf(i)).start();
}
编译结果:
解决办法:
使用如下:
public static void listNotSafe() {
List<String> list = new CopyOnWriteArrayList<>();
for (int i = 1; i <= 30 ; i++) {
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,6));
System.out.println(list);
},String.valueOf(i)).start();
}
编译结果:
小结:
3.解析CopyOnWrite容器
源码部分如下
其中的add(E e)
方法
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();
}
}
可以知道:
- 都是有线程锁的,所以是线程安全的
CopyOnWrite容器
即写时复制的容器。往一个容器添加元素的时候,不直接往当前容器Object[ ]添加,而是先将当前容器Object[ ]进行Copy,复制出一个新的容器Object[] newElements,然后往新的容器Object[ ] newElements里添加元素,添加完元素之后,再将原容器的引用指向新的容器 setArray(newElements)。- 好处是可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器
扩展小知识:
- HashSet底层是HashMap
- 你可能会想,HashSet是一个参数,而HashMap是键值对存在的。那是因为HashSet只用了HashMap是键,它的值是一个固定的Object对象。