面试题答案
一键面试使用Java并发包
ConcurrentHashMap
:在高并发场景下,ConcurrentHashMap
采用分段锁技术,允许多个线程同时访问不同的段,大大提高了并发性能。相比于HashMap
在多线程环境下可能出现死循环等问题,ConcurrentHashMap
保证了线程安全。例如在一个高并发的电商系统中,商品库存信息可以存储在ConcurrentHashMap
中,不同的线程可以同时对不同商品的库存进行增减操作。CopyOnWriteArrayList
:适用于读多写少的场景。当有写操作时,会复制一份原数组进行修改,修改完成后将原引用指向新数组。读操作直接读取原数组,这样读操作完全无锁,提升了读性能。例如在一个日志记录系统中,记录日志的操作较少,而读取日志进行分析的操作较多,就可以使用CopyOnWriteArrayList
来存储日志记录。
线程池的使用
- 合理配置线程池参数:通过设置合适的核心线程数、最大线程数、队列容量等参数,避免线程频繁创建和销毁带来的开销。例如在一个Web服务器中,根据服务器的硬件资源和预估的请求量,合理设置线程池参数。如果核心线程数设置过小,可能导致请求处理不及时;如果设置过大,可能会占用过多系统资源。
- 使用合适的线程池类型:
FixedThreadPool
适用于任务数量已知且处理时间相对稳定的场景,它会创建固定数量的线程来处理任务;CachedThreadPool
适用于任务量不确定且处理时间较短的场景,它会根据任务数量动态创建和销毁线程。比如在一个数据处理系统中,如果任务是批量处理固定数量的数据文件,可使用FixedThreadPool
;如果是处理来自不同客户端的随机请求,可使用CachedThreadPool
。
锁优化
- 偏向锁:当一个线程频繁访问同步块时,偏向锁会偏向于该线程,减少锁竞争。在一个单线程频繁访问某个同步资源的场景下,例如一个单线程的定时任务,每次执行任务时都需要访问一个共享资源,启用偏向锁可以提高性能。
- 轻量级锁:在竞争不激烈的情况下,轻量级锁通过CAS操作来避免重量级锁的线程挂起和唤醒开销。比如在一个多线程操作的缓存系统中,大多数情况下只有一个线程会对缓存进行更新操作,轻量级锁可以有效提升性能。
- 自旋锁:当线程尝试获取锁失败时,不会立即挂起,而是在一定时间内自旋等待锁的释放。适用于锁的持有时间较短的场景,如在一个高并发的计数器场景中,线程对计数器的操作时间很短,自旋锁可以减少线程上下文切换的开销。
无锁数据结构的应用
以ConcurrentHashMap
为例,它的实现原理采用了数组加链表(JDK 1.8后引入红黑树)的结构。在多线程环境下,通过分段锁(JDK 1.8后改为CAS和synchronized结合)保证线程安全。在实际项目中,如分布式缓存系统,使用ConcurrentHashMap
存储缓存数据,可以在高并发读写的情况下,保证数据的一致性和高效访问。
在实际项目中,通常会综合运用这些优化策略。例如在一个大型的电商订单处理系统中,订单的统计信息可以使用ConcurrentHashMap
存储,订单处理任务提交到线程池处理,对于订单状态的修改等操作,可以根据竞争情况选择合适的锁机制(如偏向锁、轻量级锁),以在保证线程安全的前提下,最大限度地优化内存性能。