目录
控制台输出的Concurrent(并发)Modification(更改)Exception异常信息
解决方案二、java.util.Collections.synchronizedXXX();
解决方案三(主角)、new CopyOnWriteArrayList<>();
众所周知,ArrayList,HashMap,HashSet...是不安全的,本文章主要拿ArrayLisy做演示,同时也会提到其他的集合类如何创建。
模拟出异常
public static void main(String[] args) {
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();
}
}
控制台输出的Concurrent(并发)Modification(更改)Exception异常信息
[64ecee, 217e9b, 21a8d4, 73978f, a30e8e, 5643ed, 4af994, b8ff61, 89d4ab, 8fa982, 87a8d2, 5311c0, ebdebb, 696d1c, cc089f, 4c258b, 2d573f, 4d8b43, 070db7]
Exception in thread "4" Exception in thread "3" Exception in thread "2" Exception in thread "1" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
at java.util.ArrayList$Itr.next(ArrayList.java:859)
at java.util.AbstractCollection.toString(AbstractCollection.java:461)
at java.lang.String.valueOf(String.java:2994)
at java.io.PrintStream.println(PrintStream.java:821)
at cr.example.demo.Test.lambda$main$0(Test.java:17)
at java.lang.Thread.run(Thread.java:748)
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
解决方案一、new Vector<>();
上代码
public static void main(String[] args) {
List<String> list = new Vector<>();
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();
}
}
控制台输出(达到线程安全目的)
为什么呢?
点进去源码看,原来Vector的add方法时加了锁的(synchronized),所以证明是线程安全的。
解决方案二、java.util.Collections.synchronizedXXX();
上代码
public static void main(String[] args) {
List<String> list = Collections.synchronizedList(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();
}
}
控制台输出(达到线程安全目的)
为什么?
一层一层点进源码,可以看出来增删改查方法都加上了synchronized
举一反三
除了有Collections.synchronizedList肯定也有Collections.synchronizedMap,Collections.synchronizedSet。。。如下图
解决方案三(主角)、new CopyOnWriteArrayList<>();
上代码
public static void main(String[] args) {
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();
}
控制台输出(达到线程安全目的)
为什么?
进去源码里面瞧一瞧
首先可以看到他的add方法是加了锁的,最厉害的是CopyOnWriteArrayList用了读写分离的理念,请跟着我下面的注释思路
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return {@code true} (as specified by {@link Collection#add})
*/
public boolean add(E e) {
final ReentrantLock lock = this.lock;
//1、添加锁
lock.lock();
try {
//2、获取到“当前数组”
Object[] elements = getArray();
//3、获取到“当前数组”的长度
int len = elements.length;
//4、拷贝出一个比“当前数据”长度+1的“新数组”
Object[] newElements = Arrays.copyOf(elements, len + 1);
//5、在“新数组”的最后位置添加上元素,所以插入数据是在“新数组”,查看数据是在“当前数组”
newElements[len] = e;
//6、然后将更改好的“新数组”替换为“当前数组”
setArray(newElements);
return true;
} finally {
//7、解锁
lock.unlock();
}
}
举一反三
new CopyOnWriteArrayList<>(),new CopyOnWriteArraySet<>(),
new ConcurrentHashMap<>() 。。。