并发容器是JDK提供的一个包名:java.util.concurrent

ArrayList -> CopyOnWriteArrayList

CopyOnWriteArrayList是线程安全的,写操作时复制,当有新元素添加到CopyOnWriteArrayList时先从原有的list中拷贝出来,然后在新的list上写操作,写完之后将原来的list指向新的list,整个操作都是在锁的保护下进行的,这样做为了防止多线程下多个add操作时产生多个副本,导致最终的数据不是我们期望的。

CopyOnWriteArrayList有几个缺点:

  1. 由于写操作时需要拷贝数组,因此比较消耗内存。当元素内容比较多时会导致Full GC
  2. 不能用于实时读的场景,拷贝数组需要时间,所以调用一个set操作后,读取到的数据还可能是旧的,虽然能做到最终一致性,但是无法满足实时性要求。因此CopyOnWriteArrayList更适合读多写少的场景。如果不清楚add或者set多少次操作,这个CopyOnWriteArrayList最好慎用。

HashSet、TreeSet->CopyOnWriteArraySet、ConcurrentSkipListSet

CopyOnWriteArraySet同样也是线程安全的,底层实现是CopyOnWriteArrayList,因此CopyOnWriteArraySet适合大小比较小的set集合只读操作大于写操作,因为需要复制基础数组,所以对于可变的操作(add set)的开销大。使用迭代器的迭代速度很快,而且不会有线程安全问题。

ConcurrentSkipListSet与TreeSet用一样,是支持自然排序的,可以在构造时自定义比较器。在多线程情况下ConcurrentSkipListSet里面的contains()、add()、remove()是线程安全的,多个线程可以并发的执行插入移除和访问操作,但是对于批量操作例如addAll(),removeAll(),retainAll()、containsAll()并不能保证以原子方式执行,这些操作可以被其他线程打断,需要额外增加锁才行,因为他们实现方式是分别调用contains()、add()、remove()的。因为并发容器只能保证每一次的contains()、add()、remove()操作时原子性的,而不能保证每一次批量操作都不会被其他线程打断。也就是多个add,多个remove操作时有其他线程进来。

HashMap、TreeMap -> ConcurrentHashMap、ConcurrentSkipListMap

ConcurrentHashMap不允许null,在实际的应用中除了少数的插入操作和删除操作外,绝大部分我们使用map都是使用读取操作,而且读操作大多数都是成功的,基于这个前提,ConcurrentHashMap针对读操作做了大量的优化,因此这个类具有很高的并发性,高并发场景下有很好的表现。

ConcurrentSkipListMap是TreeMap的线程安全版本。内部是使用skipList跳表的结构实现的。ConcurrentHashMap的存取速度是ConcurrentSkipListMap的4倍左右,但是ConcurrentSkipListMap的key是有序的而ConcurrentHashMap是做不到的,ConcurrentSkipListMap支持更高的并发,ConcurrentSkipListMap的存取时间是与线程数无关的,在数据量一定的情况下并发线程数越多ConcurrentSkipListMap越能体现出优势。

在较低并发情况下,可以使用Collections.synchronizedSortedMap()来实现,也可以提供较好的效率。在高并发的情况下可以使用ConcurrentSkipListMap提供更高的并发度。要对键值对进行排序时可以使用ConcurrentSkipListMap。

@Slf4j
@ThreadSafe
public class ConcurrentHashMapExample {// 请求总数public static int clientTotal = 5000;// 同时并发执行的线程数public static int threadTotal = 200;private static Map<Integer, Integer> map = new ConcurrentHashMap<>();public static void main(String[] args) throws InterruptedException {//线程池ExecutorService executorService = Executors.newCachedThreadPool();//定义信号量final Semaphore semaphore = new Semaphore(threadTotal);//定义计数器final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);for(int i = 0; i < clientTotal; i++) {final int count  = i;executorService.execute(() ->{try {semaphore.acquire();update(count);semaphore.release();} catch (InterruptedException e) {log.error("exception", e);}countDownLatch.countDown();});}countDownLatch.await();executorService.shutdown();log.info("size:{}",map.size()) ;}public static void update(int i) {map.put(i,i);}}

输出结果正确。

concurrentSkipListMap:

private static Map<Integer, Integer> map = new ConcurrentSkipListMap<>();

J.U.C

安全共享对象策略 - 总结

  • 线程限制:一个被线程限制的对象,由线程独占,并且只能被占有它的线程修改。
  • 共享只读:一个共享只读的对象,在没有额外同步的情况下,可以被多个线程并发访问,但是任何线程都不能修改它。
  • 线程安全对象:一个线程安全的对象或者容器,在内部通过同步机制来保证线程安全,所以其他线程无需额外的同步就可以通过公共接口随意访问它。
  • 被守护对象:被守护对象只能通过获取特定的锁来访问。

java高并发(十二)并发容器J.U.C相关推荐

  1. 疯狂JAVA讲义---第十二章:Swing编程(五)进度条和滑动条

    http://blog.csdn.net/terryzero/article/details/3797782 疯狂JAVA讲义---第十二章:Swing编程(五)进度条和滑动条 标签: swing编程 ...

  2. Java设计模式(十二) 策略模式

    策略模式介绍 策略模式定义 策略模式(Strategy Pattern),将各种算法封装到具体的类中,作为一个抽象策略类的子类,使得它们可以互换.客户端可以自行决定使用哪种算法. 策略模式类图 策略模 ...

  3. 吃透这JAVA并发十二核心,面试官都得对你刮目相看

    1.HashMap 面试第一题必问的 HashMap,挺考验Javaer的基础功底的,别问为啥放在这,因为重要!HashMap具有如下特性: HashMap 的存取是没有顺序的. KV 均允许为 NU ...

  4. JAVA并发十二连招

    1.HashMap 面试第一题必问的 HashMap,挺考验Javaer的基础功底的,别问为啥放在这,因为重要!HashMap具有如下特性: HashMap 的存取是没有顺序的. KV 均允许为 NU ...

  5. 纯干货!Java后端开发十二条经验分享!

    前言 本文是博主从事后端开发以来,对公司.个人项目的经验总结,包含代码编写.功能推荐.第三方库使用及优雅配置等,希望大家看到都能有所收获 一. 优雅的进行线程池异常处理 在Java开发中,线程池的使用 ...

  6. java se系列(十二)集合

    1.集合 1.1.什么是集合 存储对象的容器,面向对象语言对事物的体现,都是以对象的形式来体现的,所以为了方便对多个对象的操作,存储对象,集合是存储对象最常用的一种方式.集合的出现就是为了持有对象.集 ...

  7. Java多线程(十二)之线程池深入分析(下)

    一.数据结构与线程构造方法 由于已经看到了ThreadPoolExecutor的源码,因此很容易就看到了ThreadPoolExecutor线程池的数据结构.图1描述了这种数据结构. 图1 Threa ...

  8. java学习笔记(十二)----集合

    集合类 集合类用于存储一组对象,其中的每个对象称之为元素,经常会用以的有Vector,Enumeration,ArrayList,Collection,Iterator,Set,List等集合和接口 ...

  9. Java多线程学习十二:悲观锁和乐观锁的本质||

    悲观锁和乐观锁是从是否锁住资源的角度进行分类的. 悲观锁 悲观锁比较悲观,它认为如果不锁住这个资源,别的线程就会来争抢,就会造成数据结果错误,所以悲观锁为了确保结果的正确性,会在每次获取并修改数据时, ...

  10. java EE 第十二周 web前端开发的周总结 (含思维导图)

    第十周思维导图 Tomcat 目录分析 bin 可执行文件 conf 配置文件 lib 依赖jar包 logs 日志文件 temp 临时文件 webapps 存放 work 存放运行时的数据 Tomc ...

最新文章

  1. .net简单算法实现无限级分类(一)
  2. js中给数组中对象去重
  3. iOS 11 UIScrollView的新特性(automaticallyAdjustsScrollViewInsets 不起作用了)
  4. tomcat中关于websocket的性能优化配置
  5. 现在的编译器还需要手动展开循环吗_DSP(知识点+思考题)
  6. flutter listview 滚动到底部_Flutter系列之Flex布局详解
  7. cc++编译链接过程
  8. 剑指offer——面试题9:求斐波那切数列的四种方法
  9. zabbix3.4+grafana5.0.1数据可视化
  10. Linux调试分析诊断利器——strace
  11. Python利用 Django开发网站
  12. php 主机管理系统,LuManager虚拟主机管理系统
  13. Centos 7.6 挂载硬盘
  14. 友盟统计如何去掉“站长统计”
  15. 中英文常用标点符号统一清洗为英文格式
  16. STM32F7+STM32CubeMX5.21+SD+FATFS
  17. python将工作表根据一列拆分成多个独立的sheet工作薄
  18. 新电脑从另外一台电脑完整拷贝环境,不需要安装环境
  19. python输入姓和名_编程练习1-输入姓,返回名
  20. 通达OA 在OA系统中增加员工自助查询工资条的功能(图文)

热门文章

  1. 浅谈如何更好的打开和关闭ADO.NET连接池
  2. ASP.NET Eval如何进行数据绑定
  3. mysql中in的用法
  4. ELK学习8_ELK数据流传输过程_问题总结1
  5. Go的strconv二
  6. python中gt是什么意思_python--gt;函数基础
  7. java8 collect 类型转换_Java 8 新特性 Stream类的collect方法
  8. mysql 数据库存储表情
  9. 闲置硬盘自制nas私有云_闲置U盘不用扔,教你一招变云盘,随时随地备份数据、访问私有云...
  10. xampp mysql 内存溢出_php - SQLSTATE [HY000] [2002]连接被拒绝 - 堆栈内存溢出