NotSafeDemo
需求线程不安全的错误原理解决方案
例子ListNotSafe()SetNotSafe()MapNotSafe()
需求
请举例说明集合类是不安全的
线程不安全的错误
java.util.ConcurrentModificationException
ArrayList在迭代的时候如果同时对其进行修改就会抛出并发修改异常.
原理
看ArrayList的源码
public boolean add(E e
){
ensureCapacityInternal(size
+1);
Increments modCount
!!elementData
[size
++]=e
;
return true;
}
解决方案
1、Vector
List
<String> list
= new Vector<>();
看Vector的源码
public synchronized boolean add(E e
){
modCount
++;ensureCapacityHelper(elementCount
+1);
elementData
[elementCount
++]=e
;
return true;
}
2、Collections
List
<String> list
= Collections
.synchronizedList(new ArrayList<>());
Collections提供了方法synchronizedList保证list是同步线程安全的
3、写时复制
List
<String> list
= new CopyOnWriteArrayList<>();
看看源码:
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容器也是一种读写分离的思想,读和写不同的容器。
例子
ListNotSafe()
package cduck
.cn
;
import java
.util
.*
;
import java
.util
.concurrent
.ConcurrentHashMap
;
import java
.util
.concurrent
.CopyOnWriteArrayList
;
import java
.util
.concurrent
.CopyOnWriteArraySet
;
public class NotSafeDemo {
public static void main(String
[] args
) {
public static void ListNotSafe() {
List
<String> list
= new CopyOnWriteArrayList();
for (int i
=0;i
<30;i
++){
new Thread(()->{
list
.add(UUID
.randomUUID().toString().substring(0,8));
System
.out
.println(list
);
},String
.valueOf(i
)).start();
}
}
}
SetNotSafe()
public static void SetNotSafe() {
Set
<String> set
=new CopyOnWriteArraySet<>();
for (int i
=0;i
<30;i
++){
new Thread(()->{
set
.add(UUID
.randomUUID().toString().substring(0,8));
System
.out
.println(set
);
},String
.valueOf(i
)).start();
}
}
MapNotSafe()
public static void MapNotSafe() {
Map
<String,String> map
=new ConcurrentHashMap<>();
for (int i
=0;i
<30;i
++){
new Thread(()->{
map
.put(Thread
.currentThread().getName(), UUID
.randomUUID().toString().substring(0,8));
System
.out
.println(map
);
},String
.valueOf(i
)).start();
}
}