Java并发并发编程实战-并发容器和同步工具类
并发容器
ConcurrentHashMap
设计原理
- 分段锁(JDK 7) :将数据分成多个段(Segment),每个段独立加锁,不同段的操作可并行执行。
- CAS + synchronized(JDK 8+) :取消分段锁,改用
CAS(无锁算法)和细粒度synchronized锁桶(Node),进一步提升并发性能。
核心特性
- 线程安全:支持多线程并发读写,无需外部同步。
- 高吞吐量:锁的粒度更细,减少线程竞争。
- 弱一致性:迭代器遍历时可能不反映最新修改(但不抛出
ConcurrentModificationException)。
适用场景
- 高并发读写(如缓存、计数器)。
- 替代
Hashtable或Collections.synchronizedMap。
对比传统同步容器
特性 ConcurrentHashMapHashtable/synchronizedMap锁粒度 细粒度(桶级别) 粗粒度(整个表) 并发性能 高 低 迭代器一致性 弱一致性 强一致性(可能抛出异常)
CopyOnWriteArrayList
设计原理
- 写时复制(Copy-On-Write) :每次修改(增、删、改)时,复制底层数组,在新副本上操作,完成后替换原数组。
- 读操作无锁:直接访问原数组,无需同步。
- 写操作加锁:保证同一时刻只有一个线程修改。
核心特性
- 线程安全:读操作完全无锁,写操作通过复制保证安全。
- 数据一致性:迭代器遍历的是创建时的数组快照,不反映后续修改。
- 内存开销:频繁修改会导致大量数组复制,占用内存。
适用场景
- 读多写极少(如监听器列表、配置白名单)。
- 替代
Collections.synchronizedList,在读远多于写时性能更优。
对比传统同步容器
特性 CopyOnWriteArrayListsynchronizedList读性能 无锁,极高 需加锁,较低 写性能 复制数组,较低 直接修改,较高 内存占用 高(频繁写时) 低 数据一致性 快照一致性 强一致性
并发容器适用场景
- 高并发读写 →
ConcurrentHashMap - 读多写极少 →
CopyOnWriteArrayList - 写多读少 → 考虑
ConcurrentLinkedQueue或阻塞队列(如LinkedBlockingQueue) - 强一致性需求 → 慎用
CopyOnWriteArrayList,优先使用锁同步的容器。
阻塞队列
Java阻塞队列
| 实现类 | 数据结构 | 特性 |
|---|---|---|
ArrayBlockingQueue |
数组 | 有界队列,固定容量,公平性可选(基于ReentrantLock) |
LinkedBlockingQueue |
链表 | 可选有界或无界(默认Integer.MAX_VALUE),吞吐量通常更高 |
PriorityBlockingQueue |
堆(优先级队列) | 无界队列,元素按优先级排序(需实现Comparable或提供Comparator) |
SynchronousQueue |
无存储 | 直接传递队列,插入操作必须等待取出操作(无缓冲,适合线程间直接传递任务) |
DelayQueue |
堆(延迟队列) | 无界队列,元素需实现Delayed接口,按到期时间排序(用于定时任务调度) |
LinkedTransferQueue |
链表 | 混合阻塞队列,支持transfer方法(生产者直接等待消费者取走元素) |
阻塞队列的工作原理
- 线程安全机制:内部通过
ReentrantLock和Condition实现线程同步 - 锁分离:插入和取出操作使用不同的锁(如
LinkedBlockingQueue的putLock和takeLock),减少竞争。 - 条件变量:队列空或满时,通过
Condition的await()和signal()实现阻塞与唤醒。
阻塞队列的典型使用场景
- 生产者-消费者模式:适合任务量不可控但需快速响应的场景(如日志处理)。
- 线程池任务调度:Java线程池(如
ThreadPoolExecutor)默认使用LinkedBlockingQueue存储待执行任务。 - 流量削峰与系统解耦:在高并发场景下,用队列缓冲瞬时流量,保护下游系统。
阻塞队列的选择与调优
队列容量
- 有界队列(如
ArrayBlockingQueue):避免内存溢出,但需合理设置容量,防止任务被拒绝。 - 无界队列(如
LinkedBlockingQueue):可能因任务堆积导致内存耗尽,需谨慎使用。
- 有界队列(如
公平性
公平锁(
fairness=true)减少线程饥饿,但降低吞吐量;非公平锁(默认)反之。ArrayBlockingQueue<Integer> fairQueue = new ArrayBlockingQueue<>(100, true);
特殊需求
- 优先级调度 →
PriorityBlockingQueue - 延迟任务 →
DelayQueue - 直接传递任务 →
SynchronousQueue
- 优先级调度 →
阻塞队列的常见问题
死锁风险
- 场景:多个线程互相等待对方释放资源。
- 解决:使用超时方法(如
poll(timeout)),避免无限阻塞。
资源耗尽
- 场景:无界队列导致内存溢出。
- 解决:改用有界队列,配合拒绝策略(如线程池的
RejectedExecutionHandler)。
性能瓶颈
- 场景:队列成为系统吞吐量的瓶颈。
- 解决:优化队列类型(如
LinkedTransferQueue提升吞吐量),或增加消费者线程。
同步工具类
CountDownLatch
核心功能
- 一次性屏障:允许一个或多个线程等待其他线程完成操作后再继续执行。
- 计数器递减:初始化时设定计数值(
count),线程调用countDown()减少计数,计数归零时唤醒等待线程。
主要方法
CountDownLatch(int count):构造函数,指定初始计数。await():阻塞当前线程,直到计数归零。countDown():减少计数值,计数为0时唤醒所有等待线程。
使用场景:主线程等待所有子任务完成;多线程等待同一事件触发(如模拟并发测试)
Semaphore
核心功能
- 控制资源访问的并发数:通过许可证(
permits)限制同时访问某资源的线程数量。 - 可公平/非公平模式:默认非公平,按请求顺序或竞争获取许可证。
- 控制资源访问的并发数:通过许可证(
主要方法
Semaphore(int permits):构造函数,指定许可证数量。acquire():获取许可证(若无可用则阻塞)。release():释放许可证。tryAcquire():非阻塞尝试获取许可证。
使用场景:限流(如数据库连接池);实现互斥锁(许可证为1的信号量)
CyclicBarrier
核心功能
- 可重置的屏障:让一组线程相互等待,直到所有线程到达屏障点后同时继续执行。
- 支持回调:所有线程到达屏障后,可触发一个
Runnable任务。
主要方法
CyclicBarrier(int parties):构造函数,指定参与的线程数。CyclicBarrier(int parties, Runnable barrierAction):指定到达屏障后的回调任务。await():线程到达屏障点并等待其他线程。
使用场景:分阶段并行计算;多线程数据合并(如分布式计算)
同步工具对比与选型
| 工具 | 核心机制 | 重用性 | 典型场景 |
|---|---|---|---|
CountDownLatch |
等待其他线程完成 | 一次性 | 主线程等待子任务、并发触发 |
Semaphore |
控制资源访问并发数 | 可重用 | 限流、资源池(如数据库连接) |
CyclicBarrier |
多线程相互等待至屏障点 | 可重用 | 分阶段任务、数据合并Java并发并发编程实战-并发容器和同步工具类 |
Java并发并发编程实战-并发容器和同步工具类的更多相关文章
- java 利用同步工具类控制线程
前言 参考来源:<java并发编程实战> 同步工具类:根据工具类的自身状态来协调线程的控制流.通过同步工具类,来协调线程之间的行为. 可见性:在多线程环境下,当某个属性被其他线程修改后,其 ...
- Java核心知识点学习----线程同步工具类,CyclicBarrier学习
线程同步工具类,CyclicBarrier日常开发较少涉及,这里只举一个例子,以做备注.N个人一块出去玩,相约去两个地方,CyclicBarrier的主要作用是等待所有人都汇合了,才往下一站出发. 1 ...
- 《java并发编程实战》读书笔记4--基础构建模块,java中的同步容器类&并发容器类&同步工具类,消费者模式
上一章说道委托是创建线程安全类的一个最有效策略,只需让现有的线程安全的类管理所有的状态即可.那么这章便说的是怎么利用java平台类库的并发基础构建模块呢? 5.1 同步容器类 包括Vector和Has ...
- Java并发(基础知识)——显示锁和同步工具类
显示锁 Lock接口是Java ...
- 并发是个什么鬼之同步工具类CountDownLatch
扯淡 写这篇文章,我先酝酿一下,实不相瞒,脱离底层太久了,更确切的情况是,真没曾认真研究过.就目前来说,很多框架包括工具类已经把实现封装的很深,你只需轻轻的调用一下API,便不费半点力气.以至于大家会 ...
- java.util.concurrent中的几种同步工具类
java.util.concurrent并发包中提供了一系列的的同步工具类,这些基础类不管是否能在项目中使用到,了解一下使用方法和原理对java程序员来说都是有必要的.博主在看<java并发编程 ...
- Java并发之同步工具类
1. CountDownlatch(计数器) 描述: 一个同步工具类,允许一个或多个线程等待其它线程完成操作 类图 通过指定的count值进行初始化,调用await方法的线程将被阻塞,直到count值 ...
- Java中创建操作文件和文件夹的工具类
Java中创建操作文件和文件夹的工具类 FileUtils.java import java.io.BufferedInputStream; import java.io.BufferedOutput ...
- 获取Spring容器Bean对象工具类
在开发中,总是能碰到用注解注入不了Spring容器里面bean对象的问题.为了解决这个问题,我们需要一个工具类来直接获取Spring容器中的bean.因此就写了这个工具类,在此记录一下,方便后续查阅. ...
- Java多线程同步工具类之CountDownLatch
在过去我们实现多线程同步的代码中,往往使用join().wait().notiyAll()等线程间通信的方式,随着JUC包的不断的完善,java为我们提供了丰富同步工具类,官方也鼓励我们使用工具类来实 ...
随机推荐
- Robot Framework 自动化测试部署常见问题及处理方法(二)
书接上文 4.使用Open Browser关键字打开浏览器报错"WebDriverException: Message: 'geckodriver' executable needs to ...
- layui table表格单元格动态合并,并设置隔行变色
layui table表格单元格动态合并,并设置隔行变色,此代码只针对嵌套数组只有一层的时候有效,多个数组嵌套还在冥想当中!! 需求描述 我们知道在layui插件官方平台有个可以无限极单元格合并的模块 ...
- e-prime3安装
e-prime2.0版本太老,现在安装尝试3.0. 下载 链接: https://pan.baidu.com/s/1XJFDqhoArpIwEf0NpKvoIQ 提取码: h5xk 安装 解压安装包后 ...
- redis启停shell脚本
启停脚本(redis-5.0.5) 一.编辑脚本 vim /u01/redis/redisServer.sh #!/bin/sh # # Simple Redis init.d script conc ...
- 深入浅出理解Continuous Queries和Cypher Query Language
1. 什么是Continuous Queries? 连续查询是 Drasi 最重要的组件.它们是您告诉 Drasi 要在源系统中检测哪些更改以及检测到更改时要分发的数据的机制.源为订阅的 Contin ...
- Aspire+扣子智能体实现AI自动CodeReview
一.引言 Code Review在软件开发中扮演着至关重要的角色,它不仅能够提升代码质量,确保代码的可维护性和一致性,还能促进团队成员之间的知识共享和技术提升. 传统的代码审查过程面临着诸多挑战和局限 ...
- 安川MOTOMAN示教盒触摸不良维修及解决方法
1.安川MOTOMAN示教盒触摸不良或局部不灵. (解决方法:更换触摸面板) 2.安川MOTOMAN示教盒无显示. (解决方法:维修或更换内部主板或液晶屏) 3.安川MOTOMAN示教盒显示不良.竖线 ...
- ABB喷涂机器人控制柜维护保养
ABB喷涂机器人的管理与维护保养目的是减少机器人的故障率和停机时间,充分利用机器人这一生产要素,最大限度地提高产效率.喷涂机器人维修与保养在企业生产中尤为重要,直接影响到系统的寿命,必须精心维护. A ...
- 搭建本地NCBI病毒库用于Blast
搭建本地NCBI病毒库用于Blast 目的:为了通过Blast剔除我数据集中所有与Human任意片段相似度超过97%的序列 日期:2022/11/17 1. Nt库下载 创建conda环境 conda ...
- Python - qrcode(二维码模块)
import qrcode codeText = 'https://www.cnblogs.com/houhuilinblogs' img = qrcode.make(codeText) print( ...