面试题答案
一键面试设置合适线程池参数预防异常
- 核心线程数(corePoolSize):
- 确定方法:根据任务的类型和特性来确定。如果任务是CPU密集型,核心线程数可以设置为
CPU核心数 + 1
,这样在一个线程因为偶尔的I/O等阻塞情况时,其他线程能继续利用CPU资源。例如,在一个执行大量复杂数学运算的应用中,若服务器是4核CPU,核心线程数可设为5。如果任务是I/O密集型,核心线程数可以适当增大,比如2 * CPU核心数
,因为I/O操作等待时间长,需要更多线程来充分利用CPU资源。例如,一个频繁读写文件的应用,若CPU是4核,核心线程数可设为8。 - 预防异常:设置过小,可能导致任务长时间等待,增加响应时间;设置过大,对于CPU密集型任务可能会导致CPU过度竞争,降低整体性能。合适的核心线程数能保证系统在正常负载下高效运行,避免因线程不足导致任务积压引发的异常。
- 确定方法:根据任务的类型和特性来确定。如果任务是CPU密集型,核心线程数可以设置为
- 最大线程数(maximumPoolSize):
- 确定方法:最大线程数要考虑系统的资源限制,包括CPU、内存等。它应该是在核心线程数基础上,考虑到突发流量时允许增加的线程数量。比如,在一个Web应用中,预估在高峰时期可能会有比平时多10倍的请求,结合核心线程数,综合考虑服务器资源后设置最大线程数。但不能设置过大,否则过多线程竞争资源会导致系统性能急剧下降。
- 预防异常:如果最大线程数设置过小,在流量突发时,任务无法及时处理,可能会触发拒绝策略;设置过大,可能导致系统资源耗尽,引发OOM(OutOfMemory)等异常。
- 队列容量(workQueue):
- 确定方法:队列容量要结合任务的到达速率和处理速率。如果任务到达相对稳定且处理时间较短,可以设置较小的队列容量。例如,在一个处理高频且快速响应的实时数据处理系统中,队列容量可以设置为100 - 500。如果任务到达有较大波动且处理时间不确定,需要设置较大的队列容量。比如在一个批处理任务系统中,队列容量可设置为1000 - 10000。
- 预防异常:队列容量过小,任务可能很快填满队列,导致触发拒绝策略;队列容量过大,可能导致大量任务积压在队列中,占用过多内存,并且可能使任务处理延迟过长。
处理任务执行过程中抛出的未捕获异常
- 使用Thread.UncaughtExceptionHandler:
- 实现方式:可以创建一个实现
Thread.UncaughtExceptionHandler
接口的类。例如:
- 实现方式:可以创建一个实现
class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
// 记录异常日志,例如使用日志框架记录异常信息
System.err.println("Thread " + t.getName() + " threw an exception: " + e.getMessage());
e.printStackTrace();
// 可以根据异常情况进行一些恢复操作,如重启相关服务等
}
}
然后在创建线程池时,为线程池中的线程设置这个处理器。例如:
ThreadPoolExecutor executor = new ThreadPoolExecutor(
corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS,
new LinkedBlockingQueue<>());
executor.setThreadFactory(new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
return t;
}
});
- 使用Future.get()捕获异常:
- 实现方式:如果是使用
Future
来获取任务执行结果,可以在调用Future.get()
时捕获ExecutionException
和InterruptedException
。例如:
- 实现方式:如果是使用
ExecutorService executorService = Executors.newFixedThreadPool(5);
Future<Integer> future = executorService.submit(() -> {
// 任务逻辑,可能抛出异常
if (Math.random() > 0.5) {
throw new RuntimeException("Simulated exception");
}
return 42;
});
try {
Integer result = future.get();
System.out.println("Task result: " + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
// 处理异常,如记录日志,进行恢复操作等
} finally {
executorService.shutdown();
}