面试题答案
一键面试线程创建与销毁的优化
- 重用线程:可缓存线程池默认会在一定时间(60秒)内缓存空闲线程。为了减少线程创建与销毁开销,确保业务场景下线程的复用率足够高。
- 代码实现:使用
Executors.newCachedThreadPool()
创建线程池时,系统会自动管理线程的缓存与复用。
ExecutorService executorService = Executors.newCachedThreadPool(); for (int i = 0; i < 10; i++) { executorService.submit(() -> { // 执行任务 System.out.println(Thread.currentThread().getName() + " is running task"); }); } executorService.shutdown();
- 代码实现:使用
- 限制线程创建数量:虽然可缓存线程池理论上可创建无限线程,但在高并发场景可能导致资源耗尽。可以自定义线程池并设置最大线程数。
- 代码实现:
ThreadPoolExecutor executor = new ThreadPoolExecutor( 0, // 核心线程数为0 100, // 最大线程数为100 60L, TimeUnit.SECONDS, new SynchronousQueue<>()); for (int i = 0; i < 10; i++) { executor.submit(() -> { // 执行任务 System.out.println(Thread.currentThread().getName() + " is running task"); }); } executor.shutdown();
任务调度优化
- 优先队列调度:对于有优先级的任务,可以使用
PriorityBlockingQueue
作为任务队列,让线程池按照任务优先级执行。- 代码实现:
class PriorityTask implements Runnable, Comparable<PriorityTask> { private int priority; private String taskName; public PriorityTask(int priority, String taskName) { this.priority = priority; this.taskName = taskName; } @Override public void run() { System.out.println(taskName + " with priority " + priority + " is running"); } @Override public int compareTo(PriorityTask other) { return Integer.compare(this.priority, other.priority); } } PriorityBlockingQueue<Runnable> taskQueue = new PriorityBlockingQueue<>(); ThreadPoolExecutor executor = new ThreadPoolExecutor( 0, 100, 60L, TimeUnit.SECONDS, taskQueue); executor.submit(new PriorityTask(3, "Task 3")); executor.submit(new PriorityTask(1, "Task 1")); executor.submit(new PriorityTask(2, "Task 2")); executor.shutdown();
- 分队列调度:根据任务类型将任务分配到不同队列,每个队列可配置不同的线程数处理。
- 代码实现:
class Type1Task implements Runnable { @Override public void run() { System.out.println("Type 1 task is running"); } } class Type2Task implements Runnable { @Override public void run() { System.out.println("Type 2 task is running"); } } BlockingQueue<Runnable> type1Queue = new ArrayBlockingQueue<>(100); BlockingQueue<Runnable> type2Queue = new ArrayBlockingQueue<>(100); ThreadPoolExecutor type1Executor = new ThreadPoolExecutor( 5, 10, 60L, TimeUnit.SECONDS, type1Queue); ThreadPoolExecutor type2Executor = new ThreadPoolExecutor( 3, 5, 60L, TimeUnit.SECONDS, type2Queue); type1Executor.submit(new Type1Task()); type2Executor.submit(new Type2Task()); type1Executor.shutdown(); type2Executor.shutdown();
其他优化策略
- 线程池监控与调整:使用
ThreadPoolExecutor
提供的监控方法,如getActiveCount()
、getTaskCount()
等,实时了解线程池运行状态,动态调整线程池参数。- 代码实现:
ThreadPoolExecutor executor = new ThreadPoolExecutor( 0, 100, 60L, TimeUnit.SECONDS, new SynchronousQueue<>()); for (int i = 0; i < 10; i++) { executor.submit(() -> { // 执行任务 System.out.println(Thread.currentThread().getName() + " is running task"); }); } System.out.println("Active threads: " + executor.getActiveCount()); System.out.println("Total tasks: " + executor.getTaskCount()); executor.shutdown();
- 合理设置线程存活时间:可缓存线程池默认线程存活时间为60秒,可根据业务负载情况适当调整这个时间。如果任务执行频率高且持续时间短,可适当延长存活时间;如果任务执行频率低,可缩短存活时间以释放资源。
- 代码实现:
ThreadPoolExecutor executor = new ThreadPoolExecutor( 0, 100, 30L, TimeUnit.SECONDS, new SynchronousQueue<>()); // 执行任务 executor.shutdown();