面试题答案
一键面试自定义终止策略思路
- 实现
RejectedExecutionHandler
接口:用于处理拒绝的任务,这里用于在任务被拒绝时准备持久化。 - 继承
ThreadPoolExecutor
类:重写terminated
方法,在池终止时执行任务持久化操作。 - 性能分析:通过记录任务执行时间、线程活动时间等指标来分析资源使用情况。
- 优化建议:使用合适的队列类型、调整线程数、减少锁竞争等。
关键代码片段
- 自定义拒绝策略
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
public class CustomRejectedExecutionHandler implements RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
// 这里可以对被拒绝的任务进行预处理,比如加入到待持久化列表
}
}
- 自定义线程池并实现终止策略
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import com.google.gson.Gson;
public class CustomThreadPoolExecutor extends ThreadPoolExecutor {
private List<Runnable> unfinishedTasks = new ArrayList<>();
public CustomThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, new CustomRejectedExecutionHandler());
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
// 可以在这里记录任务执行时间等性能指标
}
@Override
protected void terminated() {
Gson gson = new Gson();
String json = gson.toJson(unfinishedTasks);
try (FileWriter writer = new FileWriter("unfinished_tasks.json")) {
writer.write(json);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void execute(Runnable task) {
if (isShutdown()) {
// 如果线程池已关闭,将任务加入待持久化列表
unfinishedTasks.add(task);
} else {
super.execute(task);
}
}
}
- 性能分析与优化
- 减少线程切换开销:
- 调整线程数:根据任务类型(CPU 密集型或 I/O 密集型)合理设置核心线程数和最大线程数。例如,CPU 密集型任务,核心线程数可设置为 CPU 核心数;I/O 密集型任务,可适当增加线程数。
- 使用
ThreadLocal
:避免多线程竞争共享资源,减少锁的使用,从而减少线程切换。
- 提高任务队列处理效率:
- 选择合适的队列:对于有界任务,
ArrayBlockingQueue
可以有效控制内存使用;对于无界任务,LinkedBlockingQueue
更合适。 - 优化队列操作:尽量减少对任务队列的同步操作,避免不必要的锁竞争。例如,在任务入队和出队时,可以使用无锁数据结构(如
ConcurrentLinkedQueue
)来提高效率。
- 选择合适的队列:对于有界任务,
使用示例
public class Main {
public static void main(String[] args) {
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>();
CustomThreadPoolExecutor executor = new CustomThreadPoolExecutor(
2, 4, 10, TimeUnit.SECONDS, workQueue);
for (int i = 0; i < 10; i++) {
executor.execute(() -> {
// 模拟任务执行
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
executor.shutdown();
try {
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow();
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
System.err.println("Pool did not terminate");
}
}
} catch (InterruptedException ie) {
executor.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
上述代码实现了一个自定义线程池,具备任务持久化到本地文件的终止策略,并给出了性能分析与优化建议。代码中使用了 Google 的 Gson 库来处理 JSON 序列化,实际应用中可以根据需要选择其他 JSON 处理库。