java高并发(十二)并发容器J.U.C
并发容器是JDK提供的一个包名:java.util.concurrent
ArrayList -> CopyOnWriteArrayList
CopyOnWriteArrayList是线程安全的,写操作时复制,当有新元素添加到CopyOnWriteArrayList时先从原有的list中拷贝出来,然后在新的list上写操作,写完之后将原来的list指向新的list,整个操作都是在锁的保护下进行的,这样做为了防止多线程下多个add操作时产生多个副本,导致最终的数据不是我们期望的。
CopyOnWriteArrayList有几个缺点:
- 由于写操作时需要拷贝数组,因此比较消耗内存。当元素内容比较多时会导致Full GC
- 不能用于实时读的场景,拷贝数组需要时间,所以调用一个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相关推荐
- 疯狂JAVA讲义---第十二章:Swing编程(五)进度条和滑动条
http://blog.csdn.net/terryzero/article/details/3797782 疯狂JAVA讲义---第十二章:Swing编程(五)进度条和滑动条 标签: swing编程 ...
- Java设计模式(十二) 策略模式
策略模式介绍 策略模式定义 策略模式(Strategy Pattern),将各种算法封装到具体的类中,作为一个抽象策略类的子类,使得它们可以互换.客户端可以自行决定使用哪种算法. 策略模式类图 策略模 ...
- 吃透这JAVA并发十二核心,面试官都得对你刮目相看
1.HashMap 面试第一题必问的 HashMap,挺考验Javaer的基础功底的,别问为啥放在这,因为重要!HashMap具有如下特性: HashMap 的存取是没有顺序的. KV 均允许为 NU ...
- JAVA并发十二连招
1.HashMap 面试第一题必问的 HashMap,挺考验Javaer的基础功底的,别问为啥放在这,因为重要!HashMap具有如下特性: HashMap 的存取是没有顺序的. KV 均允许为 NU ...
- 纯干货!Java后端开发十二条经验分享!
前言 本文是博主从事后端开发以来,对公司.个人项目的经验总结,包含代码编写.功能推荐.第三方库使用及优雅配置等,希望大家看到都能有所收获 一. 优雅的进行线程池异常处理 在Java开发中,线程池的使用 ...
- java se系列(十二)集合
1.集合 1.1.什么是集合 存储对象的容器,面向对象语言对事物的体现,都是以对象的形式来体现的,所以为了方便对多个对象的操作,存储对象,集合是存储对象最常用的一种方式.集合的出现就是为了持有对象.集 ...
- Java多线程(十二)之线程池深入分析(下)
一.数据结构与线程构造方法 由于已经看到了ThreadPoolExecutor的源码,因此很容易就看到了ThreadPoolExecutor线程池的数据结构.图1描述了这种数据结构. 图1 Threa ...
- java学习笔记(十二)----集合
集合类 集合类用于存储一组对象,其中的每个对象称之为元素,经常会用以的有Vector,Enumeration,ArrayList,Collection,Iterator,Set,List等集合和接口 ...
- Java多线程学习十二:悲观锁和乐观锁的本质||
悲观锁和乐观锁是从是否锁住资源的角度进行分类的. 悲观锁 悲观锁比较悲观,它认为如果不锁住这个资源,别的线程就会来争抢,就会造成数据结果错误,所以悲观锁为了确保结果的正确性,会在每次获取并修改数据时, ...
- java EE 第十二周 web前端开发的周总结 (含思维导图)
第十周思维导图 Tomcat 目录分析 bin 可执行文件 conf 配置文件 lib 依赖jar包 logs 日志文件 temp 临时文件 webapps 存放 work 存放运行时的数据 Tomc ...
最新文章
- .net简单算法实现无限级分类(一)
- js中给数组中对象去重
- iOS 11 UIScrollView的新特性(automaticallyAdjustsScrollViewInsets 不起作用了)
- tomcat中关于websocket的性能优化配置
- 现在的编译器还需要手动展开循环吗_DSP(知识点+思考题)
- flutter listview 滚动到底部_Flutter系列之Flex布局详解
- cc++编译链接过程
- 剑指offer——面试题9:求斐波那切数列的四种方法
- zabbix3.4+grafana5.0.1数据可视化
- Linux调试分析诊断利器——strace
- Python利用 Django开发网站
- php 主机管理系统,LuManager虚拟主机管理系统
- Centos 7.6 挂载硬盘
- 友盟统计如何去掉“站长统计”
- 中英文常用标点符号统一清洗为英文格式
- STM32F7+STM32CubeMX5.21+SD+FATFS
- python将工作表根据一列拆分成多个独立的sheet工作薄
- 新电脑从另外一台电脑完整拷贝环境,不需要安装环境
- python输入姓和名_编程练习1-输入姓,返回名
- 通达OA 在OA系统中增加员工自助查询工资条的功能(图文)
热门文章
- 浅谈如何更好的打开和关闭ADO.NET连接池
- ASP.NET Eval如何进行数据绑定
- mysql中in的用法
- ELK学习8_ELK数据流传输过程_问题总结1
- Go的strconv二
- python中gt是什么意思_python--gt;函数基础
- java8 collect 类型转换_Java 8 新特性 Stream类的collect方法
- mysql 数据库存储表情
- 闲置硬盘自制nas私有云_闲置U盘不用扔,教你一招变云盘,随时随地备份数据、访问私有云...
- xampp mysql 内存溢出_php - SQLSTATE [HY000] [2002]连接被拒绝 - 堆栈内存溢出