本文已参与「新人创作礼」活动, 一起开启掘金创作之路。
Java并发修改异常:java.util.ConcurrentModificationExpection
vector线程安全但是是JDK1.0诞生
arrayList线程不安全但是是JDK 1.2诞生
Collection是一个接口
Collections是一个辅助工具类
目前两种解决方案:new vector<>();
collctions.synchronizedList(new ArrayList<>());
还有改错思路思想
//list线程不安全问题,已经举一个不安全的例子
import java.util.*;
public class ContainerNotSafe {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
//1.方案一
//List<String> list = new Vector<>();
//2.方案二
//List<String> list = Collections.synchronizedList(new ArrayList<>());
//List<Integer> list = Arrays.asList(1, 2, 3);
//list.forEach(System.out::println);
for (int i = 0; i < 3; i++) {
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,8));
System.out.println(list);
},String.valueOf(i)).start();
}
}
}
第三种方法 使用new CopyOnWriteArrayList<>();可以保证线程安全
创建:CopyOnWriteArrayList() 添加元素:即add(E)方法 获取单个对象:即get(int)方法 删除对象:即remove(E)方法 遍历所有对象:即iterator(),在实际中更常用的是增强型的for循环去做遍历 注:CopyOnWriteArrayList是一个线程安全,读操作时无锁的ArrayList。
List list = new CopyOnWriteArrayList();
-
CopyOnWriteArrayList(写数组的拷贝)是ArrayList的一个线程安全的变体,CopyOnWriteArrayList和CopyOnWriteSet都是线程安全的集合,其中所有可变操作(add、set等等)都是通过对底层数组进行一次新的复制来实现的。
-
它绝对不会抛出ConcurrentModificationException的异常。因为该列表(CopyOnWriteArrayList)在遍历时将不会被做任何的修改。
-
CopyOnWriteArrayList适合用在“读多,写少”的“并发”应用中,换句话说,它适合使用在读操作远远大于写操作的场景里,比如缓存。它不存在“扩容”的概念,每次写操作(add or remove)都要copy一个副本,在副本的基础上修改后改变array引用,所以称为“CopyOnWrite”,因此在写操作是加锁,并且对整个list的copy操作时相当耗时的,过多的写操作不推荐使用该存储结构。
-
CopyOnWriteArrayList的功能是是创建一个列表,有三种构造方法:
(1)CopyOnWriteArrayList ()创建一个空列表。
(2)CopyOnWriteArrayList (Collection<? extendsE> c)
创建一个按 collection的迭代器返回元素的顺序包含指定 collection元素的列表。
(3)CopyOnWriteArrayList(E[] toCopyIn)
创建一个保存给定数组的副本的列表
复制后前面指针作废,并且再最后加上元素
这是add的源码:
笔记,排错后的操作
什么是写时复制
第三种方式小demo
//list线程不安全问题,已经举一个不安全的例子
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
public class ContainerNotSafe {
public static void main(String[] args) {
//List<String> list = new ArrayList<>();
//1.方案一
//List<String> list = new Vector<>();
//2.方案二
//List<String> list = Collections.synchronizedList(new ArrayList<>());
//3.方案三
List<String> list = new CopyOnWriteArrayList<>();
//List<Integer> list = Arrays.asList(1, 2, 3);
//list.forEach(System.out::println);
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();
}
}
}
Set多线程并发不安全问题
hashset底层是hashmap
value恒定present常量
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArraySet;
public class setNotSafe {
public static void main(String[] args) {
HashSet<String> set = new HashSet<>();
//方案一
//Set<Object> set = Collections.synchronizedSet(new HashSet<>());
//方案二
//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();
}
}
}
Map集合多线程并发不安全问题,依然还是那两种方法
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
public class mapNotSafe {
public static void main(String[] args) {
//HashMap<String,String> map = new HashMap<>();
//方案一
Map<String,String> map = Collections.synchronizedMap(new HashMap<>());
//方案二
//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();
}
}
}