首页
技术小册
AIGC
面试刷题
技术文章
MAGENTO
云计算
视频课程
源码下载
PDF书籍
「涨薪秘籍」
登录
注册
01 | 可见性、原子性和有序性问题:并发编程Bug的源头
02 | Java内存模型:看Java如何解决可见性和有序性问题
03 | 互斥锁(上):解决原子性问题
04 | 互斥锁(下):如何用一把锁保护多个资源?
05 | 一不小心就死锁了,怎么办?
06 | 用“等待-通知”机制优化循环等待
07 | 安全性、活跃性以及性能问题
08 | 管程:并发编程的万能钥匙
09 | Java线程(上):Java线程的生命周期
10 | Java线程(中):创建多少线程才是合适的?
11 | Java线程(下):为什么局部变量是线程安全的?
12 | 如何用面向对象思想写好并发程序?
13 | 理论基础模块热点问题答疑
14 | Lock和Condition(上):隐藏在并发包中的管程
15 | Lock和Condition(下):Dubbo如何用管程实现异步转同步?
16 | Semaphore:如何快速实现一个限流器?
17 | ReadWriteLock:如何快速实现一个完备的缓存?
18 | StampedLock:有没有比读写锁更快的锁?
19 | CountDownLatch和CyclicBarrier:如何让多线程步调一致?
20 | 并发容器:都有哪些“坑”需要我们填?
21 | 原子类:无锁工具类的典范
22 | Executor与线程池:如何创建正确的线程池?
23 | Future:如何用多线程实现最优的“烧水泡茶”程序?
24 | CompletableFuture:异步编程没那么难
25 | CompletionService:如何批量执行异步任务?
26 | Fork/Join:单机版的MapReduce
27 | 并发工具类模块热点问题答疑
28 | Immutability模式:如何利用不变性解决并发问题?
29 | Copy-on-Write模式:不是延时策略的COW
30 | 线程本地存储模式:没有共享,就没有伤害
31 | Guarded Suspension模式:等待唤醒机制的规范实现
32 | Balking模式:再谈线程安全的单例模式
33 | Thread-Per-Message模式:最简单实用的分工方法
34 | Worker Thread模式:如何避免重复创建线程?
35 | 两阶段终止模式:如何优雅地终止线程?
36 | 生产者-消费者模式:用流水线思想提高效率
37 | 设计模式模块热点问题答疑
38 | 案例分析(一):高性能限流器Guava RateLimiter
39 | 案例分析(二):高性能网络应用框架Netty
40 | 案例分析(三):高性能队列Disruptor
41 | 案例分析(四):高性能数据库连接池HiKariCP
42 | Actor模型:面向对象原生的并发模型
43 | 软件事务内存:借鉴数据库的并发经验
44 | 协程:更轻量级的线程
45 | CSP模型:Golang的主力队员
当前位置:
首页>>
技术小册>>
Java并发编程实战
小册名称:Java并发编程实战
### 章节 27 | 并发工具类模块热点问题答疑 在Java并发编程的广阔领域中,并发工具类模块无疑是构建高效、安全并发程序的核心基石。这些工具类,如`java.util.concurrent`包下的各类集合、锁、同步器、线程池等,为开发者提供了丰富的并发控制手段。然而,随着并发复杂度的提升,这些工具类的使用也伴随着一系列常见问题与误区。本章将围绕并发工具类模块的热点问题,进行深入解析与答疑,帮助读者更好地理解和应用这些强大的工具。 #### 27.1 线程池(ExecutorService)的常见问题 **问题一:如何合理配置线程池的大小?** 线程池的大小配置是一个权衡CPU利用率、内存消耗、响应时间和吞吐量等多方面因素的过程。常见的配置策略包括: - **CPU密集型任务**:线程数大致等于CPU核心数(`Runtime.getRuntime().availableProcessors()`),这样可以最大化CPU的利用率。 - **I/O密集型任务**:由于线程在等待I/O操作完成时会阻塞,因此线程数应多于CPU核心数,以利用CPU在等待期间的空闲时间。具体数量取决于I/O操作的等待时间与CPU处理时间的比例,以及系统的可用资源。 - **混合型任务**:对于包含CPU密集型与I/O密集型混合的任务,需要基于实际测试与经验来调整线程池大小。 **问题二:线程池拒绝策略有哪些,如何选择?** Java提供了四种内置的线程池拒绝策略: - **AbortPolicy**:默认策略,直接抛出`RejectedExecutionException`。 - **CallerRunsPolicy**:调用者线程(即提交任务的线程)直接执行该任务,不会立即拒绝。 - **DiscardPolicy**:静默地丢弃无法处理的任务,不抛出异常。 - **DiscardOldestPolicy**:如果队列已满,丢弃队列中最旧的任务,并尝试提交新任务。 选择哪种策略取决于应用的需求与容错能力。例如,对于关键任务,可能需要自定义拒绝策略,如记录日志、发送告警或尝试将任务提交到其他线程池。 #### 27.2 并发集合的误区与最佳实践 **问题一:并发集合是否完全替代了同步集合?** 并发集合(如`ConcurrentHashMap`、`CopyOnWriteArrayList`等)在并发环境下提供了比同步集合更高的性能,但它们并不总是最佳选择。同步集合(通过`Collections.synchronizedXxx`方法包装)简单直接,适用于并发级别不高或代码重构成本较高的场景。选择时应基于具体需求与性能分析。 **问题二:`ConcurrentHashMap`的工作原理是什么?为何它比`Hashtable`更高效?** `ConcurrentHashMap`采用了分段锁(在Java 8及以后版本中改为基于CAS的锁自由节点数组+链表/红黑树结构)技术,将数据分为多个段(segment),每个段维护自己的锁,从而允许多个读操作或不同段的写操作并发进行。这种设计显著减少了锁竞争,提高了并发性能。相比之下,`Hashtable`使用单一锁来控制整个表,导致任何时刻只能有一个线程进行读写操作,性能低下。 #### 27.3 锁与同步器的深入解析 **问题一:ReentrantLock与synchronized的区别及选择依据?** - **灵活性**:`ReentrantLock`提供了比`synchronized`更灵活的锁定机制,包括尝试非阻塞地获取锁(`tryLock()`)、可中断地获取锁(`lockInterruptibly()`)以及尝试获取锁时设置超时时间等。 - **锁的可视性**:`ReentrantLock`可以关联多个`Condition`对象,实现更细粒度的线程间通信;而`synchronized`关键字隐式支持单个对象的锁及其关联的等待/通知机制。 - **性能**:在竞争不激烈的场景下,`synchronized`的性能可能优于`ReentrantLock`,因为它是由JVM直接支持的,减少了方法调用的开销。但在高并发场景下,`ReentrantLock`的性能可能更优,因为其提供了更多的优化空间。 选择时,若对性能有极致追求且场景复杂,可考虑`ReentrantLock`;若追求简洁明了且并发要求不高,`synchronized`是更好的选择。 **问题二:Semaphore与CountDownLatch的区别及应用场景?** - **Semaphore**:信号量,用于控制同时访问某个特定资源的操作数量,或同时执行某个指定操作的数量。适用于资源有限制的场景,如数据库连接池、线程池等。 - **CountDownLatch**:倒计时器,用于等待一组操作的完成。当调用`countDown()`方法时,计数器减一;当计数器减至0时,所有等待的线程将被唤醒。适用于需要等待多个线程完成某项操作再继续执行的场景,如初始化多个资源后启动服务等。 #### 27.4 其他并发工具类的使用注意事项 **问题一:CyclicBarrier与Exchanger的区别?** - **CyclicBarrier**:允许多个线程在相互等待,直到所有线程都到达某个公共屏障点(barrier point)。所有线程必须到达屏障点后才能继续执行,适用于需要所有线程完成某个阶段后才能进行下一步操作的场景。 - **Exchanger**:用于两个线程之间的数据交换。每个线程在到达某个点时必须等待另一个线程到达相同的点,然后才能交换数据并继续执行。适用于两个线程之间需要传递数据的场景。 **问题二:ForkJoinPool的优势与适用场景?** `ForkJoinPool`是专为可递归分解的任务设计的并行执行框架。它通过将大任务分割成多个小任务,并在多个线程上并行执行这些小任务,最后将结果合并,从而显著提高程序的并行性能。`ForkJoinPool`适用于可以递归分解为更小任务、且这些任务之间相对独立、易于合并的场景,如数组排序、大规模数据处理等。 ### 结语 本章通过对并发工具类模块中热点问题的深入解析与答疑,旨在帮助读者更全面地理解和掌握这些工具类的使用。无论是线程池的配置与优化、并发集合的选择与误区、锁与同步器的深入理解,还是其他并发工具类的使用注意事项,都是构建高效、安全并发程序不可或缺的知识。希望本章内容能为读者在Java并发编程的实践中提供有力支持。
上一篇:
26 | Fork/Join:单机版的MapReduce
下一篇:
28 | Immutability模式:如何利用不变性解决并发问题?
该分类下的相关小册推荐:
Java语言基础8-Java多线程
Java语言基础4-数组详解
Java语言基础9-常用API和常见算法
SpringBoot零基础到实战
Java必知必会-Maven初级
手把手带你学习SpringBoot-零基础到实战
Java语言基础12-网络编程
Java语言基础15-单元测试和日志技术
Java语言基础13-类的加载和反射
Java语言基础1-基础知识
Java语言基础11-Java中的泛型
Mybatis合辑1-Mybatis基础入门