1、ArrayList线程不安全
代码:
创建30个线程,向ArrayList集合添加元素
public class ContainerNotSafeTest {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
for(int i = 0; i < 30; i++){
int tempInt = i;
new Thread(()->{
list.add(tempInt);
System.out.println(list);
}).start();
}
}
}
结果:
出现ConcurrentModificationException,因为并发争抢修改,导致并发修改异常
2、Vector线程安全
把ArrayList改成Vector
List<String> list = new Vector<>();
Vector、ArrayList都是以类似数组的形式存储在内存中,Vector和ArrayList提供的方法是差不多相同的,但Vector每个方法都是同步方法,添加元素的方法,多线程情况下,只允许一个线程进入,所以不会出现并发修改异常
Vector的add方法是同步方法:
Vector的get方法是同步方法:
3、Collections的synchronizedList方法
使用Collections的synchronizedList,得到一个SynchronizedList,Collections内部类有SynchronizedList
List<String> list = Collections.synchronizedList(new ArrayList<>());
Collections的synchronizedList方法:
SynchronizedList的add方法与remove方法:
4、CopyOnWriteArrayList
CopyOnWriteArrayList写时复制
List<String> list = new CopyOnWriteArrayList<>();
CopyOnWrite容器即写时复制的容器,往一个容器添加元素的时候,不直接往当前容器Object[]添加,而是先将当前容器Object[]进行复制,复制出一个新的容器Object[] newElements,然后新的容器Objet[] newElements里面添加元素,添加完元素之后,再将原容器的引用指向新的setArray(newElements);这样做的好处是可以对CopyOnWrite容器进行并发的读,是不需要加锁的,所有CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器
CopyOnWriteArrayList的add方法:
CopyOnWriteArrayList的get方法:
HashSet与HashMap
对于HashSet:
Set<String> set1 = new HashSet<>(); //底层new HashMap<>()
Set<String> set2 = Collections.synchronizedSet(new HashSet<>());
Set<String> set3 = new CopyOnWriteArraySet<>(); //底层CopyOnWriteArrayList
对于HashMap:
Map<String, String> map1 = new HashMap<>();
Map<String, String> map2= Collections.synchronizedMap(new HashMap<>());
Map<String, String> map3 = new ConcurrentHashMap<>();