面试题答案
一键面试线程池参数合理配置
- 核心线程数:
- 对于CPU密集型任务,核心线程数一般设置为
CPU核心数 + 1
。因为CPU密集型任务主要消耗CPU资源,多一个线程可以在某个线程因偶尔的页缺失等情况阻塞时,让CPU不至于空闲。例如,服务器是8核CPU,核心线程数可设为9。 - 对于I/O密集型任务,核心线程数可设置为
2 * CPU核心数
。因为I/O操作会使线程长时间等待,需要更多线程来利用CPU资源。假设服务器是4核CPU,核心线程数可设为8。
- 对于CPU密集型任务,核心线程数一般设置为
- 最大线程数:
- 最大线程数一般应大于等于核心线程数。在高并发场景下,当队列已满,且核心线程都在忙碌时,会创建新线程直到达到最大线程数。但设置过大可能会导致系统资源耗尽,因为每个线程都会占用一定的内存等资源。对于大多数场景,最大线程数可以设置为核心线程数的2倍左右。
- 队列容量:
- 如果任务处理速度较快,队列容量可以设置得较小,比如100 - 500。这样能快速触发创建新线程,及时处理任务。
- 如果任务处理速度较慢,队列容量可以设置得较大,如1000 - 5000,避免过多线程创建导致系统资源耗尽。但过大的队列容量可能会导致任务处理延迟增加。
自定义线程池传递给supplyAsync方法示例
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class CompletableFutureThreadPoolExample {
public static void main(String[] args) {
// 自定义线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(
5, // 核心线程数
10, // 最大线程数
10L, // 线程存活时间
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(100), // 队列容量
new ThreadFactory() {
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final ReentrantLock lock = new ReentrantLock();
private final Condition notFull = lock.newCondition();
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, "MyThread-" + threadNumber.getAndIncrement());
if (t.isDaemon()) {
t.setDaemon(false);
}
if (t.getPriority() != Thread.NORM_PRIORITY) {
t.setPriority(Thread.NORM_PRIORITY);
}
return t;
}
},
new ThreadPoolExecutor.CallerRunsPolicy());
CompletableFuture.supplyAsync(() -> {
// 异步任务逻辑
System.out.println("执行异步任务");
return "任务结果";
}, executor)
.thenAccept(result -> {
System.out.println("处理任务结果: " + result);
});
// 关闭线程池
executor.shutdown();
}
}
在上述示例中,通过 ThreadPoolExecutor
自定义了一个线程池,并将其传递给 CompletableFuture.supplyAsync
方法,在异步任务执行完毕后,通过 thenAccept
处理任务结果。最后通过 executor.shutdown()
关闭线程池。