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

网友投稿 546 2022-10-23

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

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

CopyOnWriteArrayList

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

写操作的步骤

读操作

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

缺点

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

/** * @author zjq * @date 2021/08/08 *

title: CopyOnWriteArrayList

*

description:

*/ @Slf4j @ThreadSafe public class CopyOnWriteArrayListExample { /** * 请求总数 */ public static int clientTotal = 5000; /** * 同时并发执行的线程数 */ public static int threadTotal = 200; public static List 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。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Web三大组件之Filter,Listener和Servlet详解
下一篇:Howitzer - 基于ruby的验收测试框架
相关文章

 发表评论

暂时没有评论,来抢沙发吧~