【学习笔记】Java并发编程的艺术——第6章 Java并发容器和框架

第6章 Java并发容器和框架

6.1 Concurrent Hash Map的实现原理与使用

6.1.1 为什么要使用Concurrent HashMap

HashTable同时排斥get与set方法

6.1.2 Concurrent HashMap的结构

6.1.3 初始化

6.1.4 定位Segment

定位到Segment通过Hash算法,这里通过再散列,让更高的位参与到了运算中。

6.1.5 Concurrent HashMap的操作

1>get操作

①get时不需要加锁,因为Entry<K,V>中的value加了volatile修饰,保证了可见性,典型的volatile代替锁。

②但在读到空值时会加锁重读

③在Segment中的hash算法与Concurrent中不同

2>put操作

①扩容:与HashMap不同

HashMap插入后判断是否需要扩容,Segment插入前判断,防止无效扩容

②如何扩容

创建一个两倍于原数组的数组,将原数组再散列后插入(效率低,内存占用有时变为三倍)

所以Concurrent HashMap不会整个扩容,只会对segment进行扩容。而且最好在可预知的情况下队HashMap进行初始size设置

3>size操作

通过两次不锁操作统计,并在统计中判断是否发烧了修改(通过put、remore与clean方法对modcount的加1),若发生过变化,则modcount加1

【JDK1.8之后不适用segment,通过CAS为null节点put;通过synchronized为有值节点put】

6.2 ConcurrentLinkedQueue

6.2.2 入队

1>入队过程

定位尾结点->入队节点变为尾结点的next

2>定位尾结点

tail或者tail.next为尾结点

3>CAS入队,若尾结点不为null,重新定位尾结点

4>HOPS设计意图

尾结点不一定是tail节点,这样可以减少更新tail节点,不过在查找尾结点时需要多读,但减少了写。

6.2.3 出队列

①获取头节点->将其中元素取出并置为null

②获取头节点->元素已为空->获取下个节点

6.3 Java中的阻塞队列

6.3.1 什么是阻塞队列

BlockingQueue支持插入/移除时阻塞

在插入/移除时可选方法:

①抛异常

②返回特殊值

③阻塞

④超时退出

6.3.2 Java里的阻塞队列

1>ArrayBlockingQueue

先进先出排序,但非公平,有界(可选公平)

2>LinkedBlockingQueue(不公平)

同上,链表实现,界限为Int.MAX_VALUE

3>PriorityBlockingQueue

按优先级排序,无界,最小堆(二叉小顶堆)

4>DelayQueue

支持延时获取元素的无界队列,用PriorityQueue实现。队列中的元素需要实现Delay接口,在创建元素时可指定需要多久才能获得元素

【应用场景:

1>缓存系统设计:在存入时指定过期时间,在线程中获取元素,获取到后表示已过期

2>定时任务调度:保存执行任务的任务与执行时间,获取到后开始执行,如:TimerQueue】

【如何使用:

①实现Delay接口,用time记录当前对象延迟时间,sequenceNumber标识元素在队列中的先后顺序

②实现getDelay方法,返回当前元素还需要延时多长时间。单位为纳秒,与time字段配合使用

③实现CompareTo方法,将time值最大的放在末尾】

【如何实现:

在获取元素时判断,没到延时时间则阻塞】

5>synchronousQueue

不存储元素,每一个put操作必须等待一个take操作,否则不能继续添加。默认非公平,可选公平,吞吐量高。

6>LinkedTransferQueue

①transfer方法:该方法添加元素时必会等到元素被消费才返回

②tryTransfer方法:尝试直接给消费者,不行则返回false,可设置超时

7>LinkedBlockingDeque

双向队列,减少竞争

6.3.3 阻塞队列的实现原理

使用通知模式,设置了两个condition,非空与非满时通知,由ReetrantLock获得,其中await由support.park()实现

【park阻塞线程返回的四种情况

①unpark执行或已执行

②线程被中断

③等带完time参数超时

④发生异常】

6.4 Fork/Join框架

6.4.1 什么是Fork/Join框架

把大任务fork成小任务(可多次fork)再join结果

6.4.2 工作窃取模式

某个线程从其他队列里窃取任务来执行

优点:利用线程优点进行并行计算,利用空闲线程

缺点:创建了多个线程与双端队列,消耗更多的资源

6.4.3 Fork/Join 框架的设计

①ForkJoinTask:创建事件

子类:RecursiveAction(无返回值)RecursiveTask(有返回值)

②ForkJoinPool:执行时间

6.4.4 使用Fork/Join框架

Task需实现ForkJoinTask接口并实现compare方法,方法中可完成任务何时分叉执行及何时真正运算,思想类似于递归

6.4.5 Fork/Join框架的异常处理

task.isCompletedAbnormally()判断是否抛出异常

getException()返回null或异常类型

6.4.6 Fork/Join框架的视线原理

主要并行在于compute方法中对于Task的fork与join

fork:当前线程不是ForkJoinWorker Thread,则说明是主Task,若是ForkJoinWorker Thread,则是子Task,加入queue

相关推荐
悟能不能悟1 天前
java重构旧代码有哪些注意的点
java·开发语言·重构
我先去打把游戏先1 天前
ESP32学习笔记(基于IDF):SmartConfig一键配网
笔记·嵌入式硬件·mcu·物联网·学习·esp32·硬件工程
怪兽20141 天前
Redis过期键的删除策略有哪些?
java·数据库·redis·缓存·面试
workflower1 天前
单元测试-例子
java·开发语言·算法·django·个人开发·结对编程
YuanlongWang1 天前
C# 基础——装箱和拆箱
java·开发语言·c#
摇滚侠1 天前
Spring Boot 3零基础教程,WEB 开发 静态资源默认配置 笔记27
spring boot·笔记·后端
b78gb1 天前
电商秒杀系统设计 Java+MySQL实现高并发库存管理与订单处理
java·开发语言·mysql
wb043072011 天前
性能优化实战:基于方法执行监控与AI调用链分析
java·人工智能·spring boot·语言模型·性能优化
LXS_3571 天前
Day 05 C++ 入门 之 指针
开发语言·c++·笔记·学习方法·改行学it
MicroTech20251 天前
微算法科技(MLGO)研发突破性低复杂度CFG算法,成功缓解边缘分裂学习中的掉队者问题
科技·学习·算法