当前位置 : 主页 > 编程语言 > java >

JUC并发容器1(CopyOnWriteArrayList、CopyOnWriteArraySet、ConcurrentSkipListSet)

来源:互联网 收集:自由互联 发布时间:2022-08-10
CopyOnWriteArrayList ArrayList对应的线程安全的并发容器是CopyOnWriteArrayListHashSet对应的线程安全的并发容器是CopyOnWriteArraySetCopyOnWriteArraySet与CopyOnWriteArrayList类似,CopyOnWriteArraySet底层还是调用

CopyOnWriteArrayList

ArrayList对应的线程安全的并发容器是CopyOnWriteArrayListHashSet对应的线程安全的并发容器是CopyOnWriteArraySetCopyOnWriteArraySet与CopyOnWriteArrayList类似,CopyOnWriteArraySet底层还是调用的CopyOnWriteArrayList的方法。

写操作的步骤

1.先拷贝一份原来的list 为 listNew2.在新的数组listNew上做写操作3.写完后将原来的数组list 指向新的数组listNew这样做的好处是我们可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器是一种读写分离的思想,读和写不同的容器、最终一致性以及使用另外开辟空间的思路,来解决并发冲突的思想。CopyOnWriteArrayList的add操作都是在锁的保护下进行的,避免多线程并发做写操作时复制出多个副本。image.png

读操作

是在原数组上读,不需要拷贝。

缺点

1.由于写操作要拷贝数组,会消耗内存。如果数组比较大,可能会导致young GC或者 full GC。2.不适合于实时读的场景。读的数据可能会是久的,因为步骤123需要花时间。CopyOnWriteArrayList只能做到最终一致性,无法满足实时性。它更适合读多、写少,的场景。代码示例:

/** * @author zjq * @date 2021/08/08 * <p>title: CopyOnWriteArrayList</p> * <p>description:</p> */ @Slf4j @ThreadSafe public class CopyOnWriteArrayListExample { /** * 请求总数 */ public static int clientTotal = 5000; /** * 同时并发执行的线程数 */ public static int threadTotal = 200; public static List<Integer> arrayList = new CopyOnWriteArrayList<>(); public static void main(String[] args) throws Exception { //创建线程池 ExecutorService executorService = Executors.newCachedThreadPool(); //信号量(并发线程数) final Semaphore semaphore = new Semaphore(threadTotal); //计数器 (把请求计数) final CountDownLatch countDownLatch = new CountDownLatch(clientTotal); for (int i = 0; i < clientTotal ; i++) { executorService.execute(() -> { try { //信号量 判断进程是否执行 semaphore.acquire(); add(); semaphore.release(); } catch (Exception e) { log.error("exception", e); } //计数器减1 countDownLatch.countDown(); }); } //当所有请求结束 countDownLatch.await(); executorService.shutdown(); log.info("listSize:{}", arrayList.size()); } private static void add() { arrayList.add(1); } }

控制台输出:

22:00:59.094 [main] INFO com.zjq.concurrency.example.concurrent.CopyOnWriteArrayListExample - listSize:5000

说明是线程安全的

ConcurrentSkipListSet

TreeSet 对应ConcurrentSkipListSet,ConcurrentSkipListSet是jdk6新增的类,和TreeSet一样是支持自然排序的,和其他set一样,ConcurrentSkipListSet是基于map集合的,底层是ConcurrentSkipListMap实现的,在多线程环境下,ConcurrentSkipListSet里面的add,get,remove,都是线程安全的,多个线程可以安全的执行插入,移除,访问操作,但是对于批量操作,比如addAll, removeAll,ContainsAll(),并不能保证以原子方式执行,理由很简单,因为add本身是原子操作,但是当批量操作时,就不能保证原子性了,所以addAll, removeAll,ContainsAll(),批量操作时,需要自己手动加同步操作, 比如加锁,保证同一时间内,只能有一个线程操作,ConcurrentSkipListSet 不允许加入null。

本文内容到此结束了, 如有收获欢迎点赞

上一篇:AQS同步组件-CountDownLatch解析和案例
下一篇:没有了
网友评论