【学习笔记】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

相关推荐
云间月131424 分钟前
飞算JavaAI:从智能调度到出行服务的全链路技术升级
java·redis·飞算javaai炫技赛
rannn_11140 分钟前
【Javaweb学习|黑马笔记|Day1】初识,入门网页,HTML-CSS|常见的标签和样式|标题排版和样式、正文排版和样式
css·后端·学习·html·javaweb
lingggggaaaa1 小时前
小迪安全v2023学习笔记(六十一讲)—— 持续更新中
笔记·学习·安全·web安全·网络安全·反序列化
两码事3 小时前
告别繁琐的飞书表格API调用,让飞书表格操作像操作Java对象一样简单!
java·后端
超勇的阿杰4 小时前
gulimall项目笔记:P54三级分类拖拽功能实现
android·笔记
yi.Ist4 小时前
图论——Djikstra最短路
数据结构·学习·算法·图论·好难
灵魂猎手4 小时前
2. MyBatis 参数处理机制:从 execute 方法到参数流转全解析
java·后端·源码
饕餮争锋4 小时前
设计模式笔记_行为型_策略模式
笔记·设计模式·策略模式
灵魂猎手4 小时前
1. Mybatis Mapper动态代理创建&实现
java·后端·源码