面试题答案
一键面试1. 自定义Java线程池设计与实现
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
public class CustomThreadPool {
private final int corePoolSize;
private final int maximumPoolSize;
private final long keepAliveTime;
private final TimeUnit unit;
private final BlockingQueue<Runnable> workQueue;
private final ThreadPoolWorker[] workers;
private int poolSize;
public CustomThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
int workQueueCapacity) {
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.keepAliveTime = keepAliveTime;
this.unit = unit;
this.workQueue = new LinkedBlockingQueue<>(workQueueCapacity);
this.workers = new ThreadPoolWorker[maximumPoolSize];
this.poolSize = 0;
}
public void execute(Runnable task) {
if (poolSize < corePoolSize) {
ThreadPoolWorker worker = new ThreadPoolWorker(task);
workers[poolSize++] = worker;
worker.start();
} else if (!workQueue.offer(task)) {
if (poolSize < maximumPoolSize) {
ThreadPoolWorker worker = new ThreadPoolWorker(task);
workers[poolSize++] = worker;
worker.start();
} else {
// 饱和策略,这里简单丢弃任务
System.out.println("Task rejected: " + task);
}
}
}
private class ThreadPoolWorker extends Thread {
private Runnable task;
public ThreadPoolWorker(Runnable task) {
this.task = task;
}
@Override
public void run() {
while (task != null || (task = workQueue.poll(keepAliveTime, unit)) != null) {
try {
task.run();
} catch (Exception e) {
e.printStackTrace();
}
task = null;
}
}
}
}
2. 模拟高负载计算任务场景
public class HighLoadTask implements Runnable {
@Override
public void run() {
// 模拟复杂数学运算
double result = 0;
for (int i = 0; i < 1000000; i++) {
result += Math.sqrt(i);
}
System.out.println(Thread.currentThread().getName() + " finished task, result: " + result);
}
}
3. 优化思路及具体实现方法
优化思路
- 合理调整核心线程数和最大线程数:根据系统CPU核心数、内存等资源以及任务特性来确定合适的线程数量。对于CPU密集型任务,核心线程数可设置为CPU核心数;对于I/O密集型任务,可适当增加核心线程数。
- 选择合适的任务队列:不同的任务队列有不同的特性,如
LinkedBlockingQueue
是无界队列,可能导致OOM;ArrayBlockingQueue
是有界队列,需要合理设置容量。对于高负载场景,可考虑使用SynchronousQueue
,它不存储任务,直接将任务交给线程处理,减少任务在队列中的等待时间。 - 优化饱和策略:原实现简单丢弃任务,可改为将任务放入一个额外的队列,由一个专门的线程定期重试执行,或者使用
ThreadPoolExecutor.CallerRunsPolicy
,让提交任务的线程自己执行任务,以减轻线程池压力。 - 线程复用与管理:合理设置
keepAliveTime
,使空闲线程在一段时间后销毁,避免过多空闲线程占用资源。同时,可实现一个线程池监控机制,动态调整线程池参数。
具体实现方法
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class OptimizedCustomThreadPool {
private final int corePoolSize;
private final int maximumPoolSize;
private final long keepAliveTime;
private final TimeUnit unit;
private final BlockingQueue<Runnable> workQueue;
private final ThreadPoolExecutor executor;
public OptimizedCustomThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit) {
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.keepAliveTime = keepAliveTime;
this.unit = unit;
this.workQueue = new SynchronousQueue<>();
this.executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
new ThreadPoolExecutor.CallerRunsPolicy());
}
public void execute(Runnable task) {
executor.execute(task);
}
public void shutdown() {
executor.shutdown();
}
}
在上述优化后的代码中:
- 使用
SynchronousQueue
作为任务队列,减少任务在队列中的等待时间。 - 使用
ThreadPoolExecutor
并设置CallerRunsPolicy
饱和策略,让提交任务的线程执行任务,缓解线程池压力。 - 可通过
executor
的其他方法,如shutdown
优雅关闭线程池,以及实现监控机制来动态调整线程池参数。
通过这些优化,可以提高系统整体性能和资源利用率,更好地应对高负载计算任务场景。