- package com.kuang.unsafe;
-
- import java.util.*;
- import java.util.concurrent.CopyOnWriteArrayList;
-
- //java.util.ConcurrentModificationException 并发修改异常! 因为List集合线程不安全!
- public class ListTest {
- public static void main(String[] args) {
- //并发下 ArrayList 不安全的!
- /**
- * 解决方案:
- * 1. List
list = new Vector<>(); 只是在add()方法加了一个synchronized 关键字 ,最早出现的,但不是最优解,效率太低了. - * 2. Collections工具类转化为安全集合 List
list = Collections.synchronizedList(new ArrayList<>()); - * 3.第三种方案:JUC下的安全集合 new CopyOnWriteArrayList<>(); import java.util.concurrent.CopyOnWriteArrayList;
- *
- */
- //CopyOnWrite 写入时复制 COW 计算机程序设计领域的一种优化策略;
- //多个线程调用的时候,list,读取的时候,固定的,写入(覆盖);
- //在写入的时候避免覆盖,造成的数据问题
- // 写入复制一个数组写入,写完在插进去
- //读写分离 MyCat
-
- //CopyOnWriteArrayList 比 Vector 牛在哪里?
- //没有用Synchronized 用的是 Lock锁 效率提高,
-
- List
list =new CopyOnWriteArrayList<>(); -
- for (int i = 0; i < 10; i++) {
- new Thread(()->{
- list.add(UUID.randomUUID().toString().substring(0,5));
- System.out.println(list);
- },String.valueOf(i)).start();
- }
-
-
- }
- }
方法推荐1.先会用2.货比三家,寻找其他解决方案 3.看源码
CopyOnWriteArrayList 是 Java 中的一个线程安全的集合类,它的设计目的是在读操作非常频繁,而写操作相对较少的情况下提供高效的并发访问。
CopyOnWriteArrayList 使用写入时复制(Copy-On-Write)的机制来实现线程安全。当有写操作(例如添加、修改或删除元素)时,它会创建一个新的副本(即复制原有的数组),并在副本上执行写操作,而不是直接在原有数组上进行操作。这样可以保证读操作不会被阻塞,因为读操作始终在原有的数组上进行。
使用写入时复制的主要优点是避免了读写冲突,从而提供了较好的并发性能。在多线程环境下,多个线程可以同时读取 CopyOnWriteArrayList 的内容,而不需要进行额外的同步操作。这对于读操作非常频繁的场景非常有效。
然而,写操作会导致创建新的副本,因此会消耗额外的内存,并且对于频繁的写操作可能会影响性能。因此,CopyOnWriteArrayList 适用于读多写少的场景,例如读取频率远远高于写入频率的缓存或事件监听器列表。
总结来说,CopyOnWriteArrayList 使用写入时复制的机制,通过牺牲写操作的性能来提供读操作的高并发性能,适用于读多写少的场景。
- package com.kuang.unsafe;
-
- import java.util.Collections;
- import java.util.HashSet;
- import java.util.Set;
- import java.util.UUID;
- import java.util.concurrent.CopyOnWriteArraySet;
- //java.util.ConcurrentModificationException 并发下出现这个问题 :并发修改异常
-
- public class SetTest {
- public static void main(String[] args) {
-
- /**
- * 注意synchronizedSet在用迭代器循环时,另外一个线程试图修改数据,也会发生并发修改异常!!
- * HashSet
set = new HashSet<>(); - * 解决方案:
- * 1. Set
set = Collections.synchronizedSet(new HashSet()); - * 2. Set
set = new CopyOnWriteArraySet<>(); - *
- */
- Set
set = new CopyOnWriteArraySet<>(); -
- for (int i = 0; i < 30; i++) {
- new Thread(()->{
- set.add(UUID.randomUUID().toString().substring(0,5));
- System.out.println(set);
- }).start();
- }
-
-
-
- }
- }
- public HashSet() {
- map = new HashMap<>();
- }
//add set 本质就是 map key 是无法重复的
- public boolean add(E e) {
- return map.put(e, PRESENT)==null;
- }
private static final Object PRESENT = new Object();
它是一个常量,是不变的值
- package com.kuang.unsafe;
-
- import java.util.Collections;
- import java.util.HashMap;
- import java.util.Map;
- import java.util.UUID;
- import java.util.concurrent.ConcurrentHashMap;
-
- //java.util.ConcurrentModificationException
- public class MapTest {
- public static void main(String[] args) {
- //map 是这样用的吗? 不是,工作里不用HashMap
- //默认等价于什么? new HashMap<>(16,0.75);
- /**
- * 解决方案: Map
map = new HashMap<>(); - * 1. Map
map = Collections.synchronizedMap(new HashMap<>()); - * 2. Set
set = new CopyOnWriteArraySet<>(); - * 3. Map
map = new ConcurrentHashMap<>(); - */
-
- Map
map = new ConcurrentHashMap<>(); -
- for (int i = 0; i < 30; i++) {
- new Thread(()->{
- map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0,5));
- System.out.println(map);
- },String.valueOf(i)).start();
- }
- }
- }