JUC 03
今天是2025/03/28 20:46 day 14
总路线请移步主页Java大纲相关文章
今天进行JUC 6,7,8 个模块的归纳
首先是JUC的相关内容概括的思维导图
由于内容比较多且重要,
个人还整理了一份详细JUC的思维导图,需要的请评论。是 xmind文件
6. 锁机制
深入解析 锁机制是JUC中处理线程同步的核心模块,其核心在于提供更精细的线程控制能力,同时兼顾性能优化。
核心组件扩展
-
ReentrantLock
-
公平锁 vs 非公平锁
-
公平锁:严格按照线程请求顺序分配锁(通过
new ReentrantLock(true)
启用),但可能因频繁上下文切换降低吞吐量。 -
非公平锁:允许线程“插队”获取锁(默认模式),减少线程切换开销,但可能导致线程饥饿。
-
-
可重入性:同一线程可多次获取锁(锁计数器+1),必须等计数器归零后其他线程才能竞争。
-
锁中断:支持
lockInterruptibly()
,允许线程在等待锁时响应中断。
-
-
ReentrantReadWriteLock
-
锁降级:写线程持有写锁时,可获取读锁后释放写锁,保证数据可见性。
-
锁升级限制:不允许读锁直接升级为写锁(可能导致死锁)。
-
-
StampedLock
-
乐观读:通过
tryOptimisticRead()
获取“票据”(无锁),随后通过validate(stamp)
验证数据是否被修改。 -
锁转换:支持将读锁转换为写锁(
tryConvertToWriteLock()
),需处理可能的失败。 -
缺点:不支持可重入,且复杂的API容易引发错误。
-
-
Condition
-
精准唤醒:通过多个
Condition
对象(如condition1
、condition2
)实现不同条件的等待与唤醒。 -
典型应用:生产者-消费者模型(不同条件队列管理生产者和消费者)。
-
底层原理
-
AQS(AbstractQueuedSynchronizer):锁机制的基石,通过CLH队列管理线程排队,利用
state
变量表示锁状态。 -
CAS(Compare and Swap):通过原子操作(如
Unsafe
类)实现锁状态的修改,避免传统互斥锁的性能问题。
使用场景与示例
-
高竞争写场景:使用
ReentrantLock
的非公平模式提升吞吐量。 -
读多写少场景:优先选择
ReentrantReadWriteLock
或StampedLock
的乐观读。 -
复杂协作:使用
Condition
实现线程间条件等待。
生产者-消费者示例
ReentrantLock lock = new ReentrantLock(); Condition notFull = lock.newCondition(); Condition notEmpty = lock.newCondition(); Queue<Integer> queue = new LinkedList<>(); int capacity = 10; // 生产者 lock.lock(); try { while (queue.size() == capacity) { notFull.await(); // 等待队列不满 } queue.add(data); notEmpty.signal(); // 唤醒消费者 } finally { lock.unlock(); } // 消费者 lock.lock(); try { while (queue.isEmpty()) { notEmpty.await(); // 等待队列不空 } data = queue.poll(); notFull.signal(); // 唤醒生产者 } finally { lock.unlock(); }
注意事项
-
死锁预防:避免嵌套锁请求,使用
tryLock()
设置超时。 -
性能监控:通过JVM工具(如JConsole)监控锁竞争情况。
7. 工具类
深入解析 工具类通过封装复杂的线程协作逻辑,提供轻量级同步原语,适用于多种并发场景。
核心组件扩展
-
CountDownLatch
-
一次性屏障:计数器归零后无法重置,适合“主线程等待子线程初始化完成”的场景。
-
典型应用:微服务启动时等待所有依赖服务就绪。
-
-
CyclicBarrier
-
可重用性:通过
reset()
重置计数器,适合分阶段任务(如多轮数据清洗)。 -
回调功能:构造时可传入
Runnable
任务,所有线程到达屏障后触发。
-
-
Semaphore
-
公平性控制:构造函数支持公平模式(
new Semaphore(permits, true)
)。 -
动态调整许可:通过
release()
和acquire()
动态增减信号量。
-
-
Phaser
-
动态注册/注销:支持
register()
和arriveAndDeregister()
动态调整参与线程数。 -
分层阶段:支持多阶段任务(如
onAdvance()
方法定义阶段结束条件)。
-
-
Exchanger
-
数据交换:两个线程通过
exchange()
方法交换数据,适用于“流水线”处理模型。
-
底层原理
-
共享同步状态:多数工具类基于AQS实现(如
CountDownLatch
使用AQS的共享模式)。 -
条件队列管理:如
CyclicBarrier
通过ReentrantLock
和Condition
实现线程等待。
使用场景与示例
-
批量任务并行执行:
CyclicBarrier barrier = new CyclicBarrier(5, () -> System.out.println("All tasks ready!")); // 5个线程调用 barrier.await()
-
限流保护:
Semaphore semaphore = new Semaphore(100); // 限制并发数为100 semaphore.acquire(); try { /* 访问资源 */ } finally { semaphore.release(); }
注意事项
-
避免线程泄漏:确保
CountDownLatch
的计数器最终归零。 -
Phaser的灵活性:适合动态调整任务阶段的场景,但需谨慎处理阶段超时。
8. 高级主题
深入解析 高级主题聚焦于性能优化和复杂并发模型,需结合底层机制和实际场景综合运用。
核心内容扩展
-
原子类进阶
-
LongAdder:通过分段累加(Cell数组)减少CAS竞争,适用于高并发计数场景。
-
AtomicStampedReference:通过版本号解决ABA问题(如无锁栈的实现)。
-
-
并发集合优化
-
ConcurrentHashMap:
-
分段锁(Java 7):将数据分为16个Segment,降低锁粒度。
-
CAS + synchronized(Java 8+):对单个Node加锁,进一步提升并发度。
-
-
CopyOnWriteArrayList:每次写操作复制新数组,适合读多写极少场景(如监听器列表)。
-
-
Fork/Join框架
-
工作窃取算法:空闲线程从其他线程的任务队列尾部“窃取”任务,减少竞争。
-
递归任务拆分:通过
RecursiveTask
或RecursiveAction
实现分治逻辑。 -
示例(计算1~n的和):
class SumTask extends RecursiveTask<Long> { protected Long compute() { if (任务足够小) return 直接计算; else { SumTask left = new SumTask(...); SumTask right = new SumTask(...); left.fork(); return right.compute() + left.join(); } } }
-
-
CompletableFuture
-
链式调用:通过
thenApply()
,thenCompose()
,thenCombine()
组合异步任务。 -
异常处理:通过
exceptionally()
或handle()
捕获异常。 -
超时控制:Java 9+支持
orTimeout()
和completeOnTimeout()
。
-
-
线程池调优
-
核心参数:
-
核心线程数:CPU密集型任务建议设置为CPU核数,IO密集型可适当增大。
-
队列选择:
SynchronousQueue
(直接传递任务)、LinkedBlockingQueue
(无界队列,可能OOM)。
-
-
监控指标:活跃线程数、队列堆积、任务拒绝次数(通过
ThreadPoolExecutor
钩子方法)。
-
使用场景与示例
-
高并发计数器:
LongAdder adder = new LongAdder(); adder.increment(); // 线程安全
-
异步服务调用链:
CompletableFuture<User> future = CompletableFuture .supplyAsync(() -> getUserById(id), executor) .thenApplyAsync(user -> enrichUser(user), executor) .exceptionally(ex -> fallbackUser());
注意事项
-
无锁编程的陷阱:CAS可能导致“忙等待”,需结合退避策略(如指数退避)。
-
线程池资源隔离:不同业务使用独立线程池,避免相互影响。
总结 JUC的高级模块要求开发者深入理解底层机制(如AQS、CAS)并结合实际场景灵活选择工具。锁机制提供精细化控制,工具类简化线程协作,高级主题则通过原子类、Fork/Join等实现高效并发模型。在实际应用中,需结合性能监控工具(如Arthas、JProfiler)持续优化,平衡性能与复杂度。