面试题答案
一键面试- 创建线程池:
import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class CPUIntensiveTaskExecutor { public static void main(String[] args) { int corePoolSize = Runtime.getRuntime().availableProcessors(); int maximumPoolSize = Runtime.getRuntime().availableProcessors(); long keepAliveTime = 10; TimeUnit unit = TimeUnit.SECONDS; BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(); ThreadPoolExecutor executor = new ThreadPoolExecutor( corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue ); } }
- 核心参数设置及原因:
- 核心线程数(
corePoolSize
):- 设置为
Runtime.getRuntime().availableProcessors()
。原因是CPU密集型任务主要依赖CPU资源,将核心线程数设置为CPU的核心数,可以充分利用CPU的并行处理能力,避免过多线程竞争CPU资源导致的上下文切换开销。如果核心线程数设置过多,会增加线程切换的开销,降低整体性能;如果设置过少,则无法充分利用CPU资源。
- 设置为
- 最大线程数(
maximumPoolSize
):- 同样设置为
Runtime.getRuntime().availableProcessors()
。对于CPU密集型任务,增加额外的线程并不能显著提高性能,因为CPU核心数是固定的。过多的线程会导致频繁的上下文切换,反而降低系统性能。所以最大线程数设置为与核心线程数相同,以避免不必要的线程创建。
- 同样设置为
- 队列容量:
- 使用无界队列
LinkedBlockingQueue
,这里没有设置具体容量(实际队列容量理论上为Integer.MAX_VALUE
)。原因是CPU密集型任务执行时间相对较长,设置有界队列可能会导致任务频繁拒绝(因为任务执行慢,队列很快就会满)。使用无界队列可以确保任务不会因为队列满而被拒绝,所有提交的任务都会排队等待执行,直到系统资源耗尽。不过要注意,如果任务提交速度过快且执行时间长,可能会导致内存耗尽等问题,在实际应用中需要根据系统资源和任务特点综合考虑。
- 使用无界队列
- 线程存活时间(
keepAliveTime
)和时间单位(unit
):- 设置
keepAliveTime
为10秒,时间单位为秒。当线程池中的线程数超过核心线程数时,多余的空闲线程在等待新任务到来的时间超过keepAliveTime
后,会被终止。这里设置10秒是一个相对合理的时间,如果设置过短,可能会导致线程频繁创建和销毁;设置过长,可能会导致空闲线程长时间占用资源。在CPU密集型任务场景下,由于任务执行时间较长,适当设置这个值可以在任务量有波动时有效管理线程资源。
- 设置
- 核心线程数(