第二季:4我们知道ArrayList是线程不安全,请编码写一个不安全的案例并给出解决方案
说明
本文目录前是相关视频的名字和具体视频中思维导图的名字
题目
4我们知道ArrayList是线程不安全,请编码写一个不安全的案例并给出解决方案
20 集合类不安全之并发修改异常
不安全的案例
package arraylist4;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
/**
* 集合类不安全的问题
* ArrayList
*/
public class ContainerNotSafeDemo {
public static void main(String[] args) {
// List<String> list= Arrays.asList("a","b","c");
// list.forEach(System.out::println);
List<String> list=new ArrayList<>();
// list.add("a");
// list.add("b");
// list.add("c");
//
// for (String element:list) {
// System.out.println(element);
// }
//forthread10
for (int i = 1; i <= 30; i++) {
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,8));
System.out.println(list);
},String.valueOf(i)).start();
}
//java.util.ConcurrentModificationException
}
}
解决方案1
package arraylist4;
import java.util.*;
/**
* 集合类不安全的问题
* ArrayList
*/
public class ContainerNotSafeDemo {
public static void main(String[] args) {
//List<String> list=new ArrayList<>();
List<String> list=Collections.synchronizedList(new ArrayList<>());
for (int i = 1; i <= 30; i++) {
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,8));
System.out.println(list);
},String.valueOf(i)).start();
}
//java.util.ConcurrentModificationException
/*
* 1 故障现象
* java.util.ConcurrentModificationException
* 2 导致原因
*
* 3 解决方案
* 3.1 List<String> list=new Vector<>();
* 3.2 List<String> list=Collections.synchronizedList(new ArrayList<>());
* 3.3 ???
*
* 4 优化建议(同样的错误不犯第2次)
*/
}
}
21 集合类不安全之写时复制
限制不可以用Vector和lICollections工具类解决方案2
package arraylist4;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* 集合类不安全的问题
* ArrayList
*/
public class ContainerNotSafeDemo {
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,8));
System.out.println(list);
},String.valueOf(i)).start();
}
//java.util.ConcurrentModificationException
/*
* 1 故障现象
* java.util.ConcurrentModificationException
* 2 导致原因
*
* 3 解决方案
* 3.1 List<String> list=new Vector<>();
* 3.2 List<String> list=Collections.synchronizedList(new ArrayList<>());
* 3.3 List<String> list=new CopyOnWriteArrayList<>();
*
* 4 优化建议(同样的错误不犯第2次)
*/
}
}
CopyOnWriteArrayList:写时复制,主要是一种读写分离的思想
写时复制,CopyOnWrite容器即写时复制的容器,往一个容器中添加元素的时候,不直接往当前容器Object[]添加,而是先将Object[]进行copy,复制出一个新的容器object[] newElements,然后新的容器Object[] newElements里添加原始,添加元素完后,在将原容器的引用指向新的容器 setArray(newElements);这样做的好处是可以对copyOnWrite容器进行并发的读 ,而不需要加锁,因为当前容器不需要添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器
就是写的时候,把ArrayList扩容一个出来,然后把值填写上去,在通知其他的线程,ArrayList的引用指向扩容后的
查看底层add方法源码
/**
* 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;
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();
}
}
首先需要加锁
final ReentrantLock lock = this.lock;
lock.lock();
然后在末尾扩容一个单位
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
然后在把扩容后的空间,填写上需要add的内容
newElements[len] = e;
最后把内容set到Array中
setArray(newElements);
package arraylist4;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* 集合类不安全的问题
* ArrayList
*/
public class ContainerNotSafeDemo {
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,8));
System.out.println(list);
},String.valueOf(i)).start();
}
//java.util.ConcurrentModificationException
/*
不用只是会用,会用只不过是一个API调用工程师
底层原理??
* 1 故障现象
* java.util.ConcurrentModificationException
* 2 导致原因
* 并发争抢导致,参考我们的花名册前面情况。
* 一个人正在写入,另外一个同学过来抢夺,导致数据不一致异常。并发修改异常。
* 3 解决方案
* 3.1 List<String> list=new Vector<>();
* 3.2 List<String> list=Collections.synchronizedList(new ArrayList<>());
* 3.3 List<String> list=new CopyOnWriteArrayList<>();
*
* 4 优化建议(同样的错误不犯第2次)
*/
}
}
22 集合类不安全之Set
public static void main(String[] args) {
// Set<String> set =new HashSet<>(); java.util.ConcurrentModificationException
// Set<String> set =Collections.synchronizedSet(new HashSet<>());
Set<String> set = new CopyOnWriteArraySet<>();//底层CopyOnWriteArrayList
for (int i = 1; i <= 30; i++) {
new Thread(()->{
set.add(UUID.randomUUID().toString().substring(0,8));
System.out.println(set);
},String.valueOf(i)).start();
}
new HashSet<>().add("a");//底层HashMap(16,0.75). put -> map.put(e, PRESENT) PRESENT-> private static final Object PRESENT = new Object();
}
public static void listNotSafe() {
//...
}
}
23 集合类不安全之Map
public static void main(String[] args) {
// Map<String,String> map =new HashMap<>(); //java.util.ConcurrentModificationException
// Map<String,String> map =Collections.synchronizedMap(new HashMap<>());
Map<String,String> map =new ConcurrentHashMap<>();
for (int i = 1; i <= 30; i++) {
new Thread(()->{
map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0,8));
System.out.println(map);
},String.valueOf(i)).start();
}
}
public static void setNotSafe() {
//1
}
}