1.线程状态
请解释 Java 中线程的几种状态,并描述每种状态的特点和转换条件。
NEW
(新建):线程被创建,但尚未启动。RUNNABLE
(可运行):线程正在运行,可能在执行代码,也可能等待操作系统资源。BLOCKED
(阻塞):线程在等待监视器锁,以便进入同步块/方法。WAITING
(等待):线程等待另一个线程显式地唤醒它(例如,Object.wait()
,Thread.join()
)。TIMED_WAITING
(计时等待):线程等待另一个线程在指定的时间内唤醒它(例如,Thread.sleep()
,Object.wait(long timeout)
)。TERMINATED
(终止):线程已完成执行。
线程状态的转换条件包括线程的启动、资源竞争、同步块/方法的进入与退出、以及超时等。
2.synchronized 和 ReentrantLock
synchronized
和ReentrantLock
有什么区别?在什么情况下会选择使用ReentrantLock
?
synchronized
:是Java中的内置同步机制,修饰方法
或代码块
,使用对象内部的监视器锁。简单易用,但功能有限(如不能尝试锁定、不能定时锁定)。ReentrantLock
:是java.util.concurrent.locks
包中的锁,具有更多的高级功能,如可重入、可定时、可中断
的锁定方式,支持公平锁和非公平锁
。
选择 ReentrantLock
的情况:
- 需要尝试锁定或定时锁定。
- 需要公平锁定(顺序锁定)。
- 需要更灵活的锁定机制和条件变量(例如
Condition
)。
3.线程池
请说明
ThreadPoolExecutor
类的核心参数及其作用。你会如何调整线程池的配置来应对高并发的需求?
ThreadPoolExecutor
类的核心参数:
corePoolSize
:核心线程数,线程池中始终保持存活的线程数。maximumPoolSize
:最大线程数,线程池中允许的最大线程数。keepAliveTime
:线程空闲时间,当线程数超过 corePoolSize 时,超时未任务的线程会被终止。unit
:keepAliveTime 的时间单位。workQueue
:任务队列,保存等待执行的任务。threadFactory
:线程工厂,创建新线程的方式。handler
:拒绝策略,当任务无法提交到线程池时的处理方式。
高并发配置建议:
- 根据任务类型调整 corePoolSize 和 maximumPoolSize。
- 选择合适的队列(有界/无界)避免资源耗尽。
- 使用合适的拒绝策略(如
CallerRunsPolicy
)以防止任务丢失。
4.Future 和 CompletableFuture
Future
和CompletableFuture
有何区别?在什么情况下你会选择使用CompletableFuture
?
Future
:表示一个异步计算的结果,可以通过get()
方法获取计算结果,但会阻塞
直到任务完成。适用于简单的异步任务。CompletableFuture
:扩展了Future
,提供了更丰富的 API 来进行异步任务的组合和处理(如thenApply
、thenAccept
)。支持链式调用和异常处理
。
使用 CompletableFuture
的情况:
- 需要进行多个异步任务的组合。
- 需要非阻塞地处理异步结果。
- 需要处理异步计算的异常。
5.阻塞队列
请介绍几种常用的阻塞队列及其适用场景。
常用的阻塞队列:
ArrayBlockingQueue
:基于数组的有界阻塞队列。LinkedBlockingQueue
:基于链表的有界或无界阻塞队列。PriorityBlockingQueue
:支持优先级排序的无界阻塞队列。DelayQueue
:支持延时获取元素的无界阻塞队列。SynchronousQueue
:不存储元素的队列,每个插入操作必须等待对应的移除操作。
适用场景:
- ArrayBlockingQueue:固定容量的场景,避免队列过大。
- LinkedBlockingQueue:需要动态增长的队列长度场景。
- PriorityBlockingQueue:需要优先级处理的场景。
- DelayQueue:需要延迟执行的任务调度场景。
- SynchronousQueue:生产者和消费者一对一交互的场景。
6.CAS
什么是 CAS(Compare-And-Swap)?它是如何在 Java 中实现的?请描述其优缺点。
CAS(Compare-And-Swap)
:
- CAS 是一种无锁算法,用于实现
原子操作
。通过比较内存中的某个值与预期值,如果相同则修改成新值,否则不修改。 - 在 Java 中,CAS 通过
sun.misc.Unsafe
类中的方法实现(如compareAndSwapInt
)。
优点:
- 高效,无需阻塞线程。
- 适合在多线程环境下保证数据一致性。
缺点:
- 可能会导致忙等待(如果 CAS 操作频繁失败)。
- 不适合复杂的同步场景(如需要维护多个变量的一致性)。