1. CopyOnWriteArrayList
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<String> list = new Vector<>(); 只是在add()方法加了一个synchronized 关键字 ,最早出现的,但不是最优解,效率太低了.
* 2. Collections工具类转化为安全集合 List<String> list = Collections.synchronizedList(new ArrayList<>());
* 3.第三种方案:JUC下的安全集合 new CopyOnWriteArrayList<>(); import java.util.concurrent.CopyOnWriteArrayList;
*
*/
//CopyOnWrite 写入时复制 COW 计算机程序设计领域的一种优化策略;
//多个线程调用的时候,list,读取的时候,固定的,写入(覆盖);
//在写入的时候避免覆盖,造成的数据问题
// 写入复制一个数组写入,写完在插进去
//读写分离 MyCat
//CopyOnWriteArrayList 比 Vector 牛在哪里?
//没有用Synchronized 用的是 Lock锁 效率提高,
List<String> 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 使用写入时复制的机制,通过牺牲写操作的性能来提供读操作的高并发性能,适用于读多写少的场景。
2. CopyOnWriteArraySet
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<String> set = new HashSet<>();
* 解决方案:
* 1. Set<String> set = Collections.synchronizedSet(new HashSet<String>());
* 2. Set<String> set = new CopyOnWriteArraySet<>();
*
*/
Set<String> 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();
}
}
}
2.1 HashSet 底层是什么?
public HashSet() {
map = new HashMap<>();
}
//add set 本质就是 map key 是无法重复的文章来源:https://www.toymoban.com/news/detail-731646.html
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
private static final Object PRESENT = new Object();
它是一个常量,是不变的值文章来源地址https://www.toymoban.com/news/detail-731646.html
3.ConcurrentHashMap
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<String, String> map = new HashMap<>();
* 1. Map<String, String> map = Collections.synchronizedMap(new HashMap<>());
* 2. Set<String> set = new CopyOnWriteArraySet<>();
* 3. Map<String, String> map = new ConcurrentHashMap<>();
*/
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,5));
System.out.println(map);
},String.valueOf(i)).start();
}
}
}
到了这里,关于安全线程的集合的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!