Java设计题:如何设计一个线程池

设计线程池

这种设计类问题还是一样,先说下理解,表明你是知道这个东西的用处和原理的,然后开始 阐述。基本上就是按照现有的设计来说,再添加一些个人见解。

我个人觉得如果要设计一个线程池的话得考虑 池内工作线程的管理、任务编排执行、线程池超负荷处理方案、监控。

初始化线程数、核心线程数、最大线程池都暴露出来可配置,包括超过核心线程数的线程空闲消亡配置。

任务的存储结构可配置,可以是无界队列也可以是有界队列,也可以根据配置分多个队列来分配不同优先级的任务,也可以采用 工作窃取stealing 的机制来提高线程的利用率。

也可根据任务的性质选择合适的执行策略:

  • I/O密集型任务:通常需要更多的线程来充分利用等待时间,可以适当增加线程池大小。
  • CPU密集型任务:应避免过多线程竞争CPU资源,线程池大小建议设为CPU核心数加1。

当线程池和队列都满载时,应定义合理的拒绝策略:丢弃任务,拒绝任务并抛出异常,丢弃最旧的任务,自定义策略等

实现细节

  • 线程工厂:使用自定义的ThreadFactory来创建线程,可以设置线程名称、优先级等属性。
  • 任务提交接口:提供submit方法,允许提交RunnableCallable任务。
  • 任务执行接口:内部实现runWorker方法,从队列中取出任务并执行。
  • 线程回收机制:当线程空闲时间超过keepAliveTime时,非核心线程会被自动回收。
  • 动态调整:允许运行时调整线程池参数,如核心线程数、最大线程数等。

注意不需要跟面试官解释什么叫核心线程数之类的,都懂的没必要。简单的线程池实现示例如下

import java.util.concurrent.*;
import java.util.*;
public class CustomThreadPoolExecutor extends ThreadPoolExecutor {
    private final AtomicLong rejectedTasks = new AtomicLong(0);  //记录被拒绝的任务数量
    private final AtomicLong completedTasks = new AtomicLong(0);  //记录已完成的任务数量
								// 核心线程数           最大线程数         空闲线程的存活时间   存活时间的时间单位  任务队列
    public CustomThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
                                   BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }
    @Override   
    protected void beforeExecute(Thread t, Runnable r) {  //在任务执行前调用,可以用于做一些准备工作
        super.beforeExecute(t, r);
    }
    @Override
    protected void afterExecute(Runnable r, Throwable t) {  //在任务执行后调用
        super.afterExecute(r, t);
        completedTasks.incrementAndGet();
    }
    @Override
    protected void terminated() { //在线程池关闭后调用,可以用于做一些最终的清理工作
        super.terminated();
    }
    @Override
    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
        return super.newTaskFor(runnable, value);
    }
    @Override
    protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {  //用于创建任务的包装对象
        return super.newTaskFor(callable); 
    }
    //任务被拒绝时调用,增加了被拒绝任务的计数,并调用拒绝策略处理任务
    @Override
    protected void onRejection(Runnable r, RejectedExecutionHandler handler) {
        rejectedTasks.incrementAndGet();
        handler.rejectedExecution(r, this);
    }
    public long getCompletedTasks() {  //返回已完成的任务数量
        return completedTasks.get();
    }
    public long getRejectedTasks() {   //返回被拒绝的任务数量
        return rejectedTasks.get();
    }
}

public class ThreadPoolExample {
    public static void main(String[] args) {
        // 配置线程池参数
        int corePoolSize = 4;
        int maximumPoolSize = 10;
        long keepAliveTime = 60L;
        TimeUnit unit = TimeUnit.SECONDS;
        BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(100);
        // 创建自定义线程池
        CustomThreadPoolExecutor executor = new CustomThreadPoolExecutor(
                corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue
        );

        // 提交任务
        for (int i = 0; i < 200; i++) {
            executor.submit(() -> {
                System.out.println("Executing task by " + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000); // 模拟任务执行时间
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            });
        }

        // 关闭线程池
        executor.shutdown();
        try {
            if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
                executor.shutdownNow();
            }
        } catch (InterruptedException ex) {
            executor.shutdownNow();
            Thread.currentThread().interrupt();
        }

        // 输出监控信息
        System.out.println("Completed tasks: " + executor.getCompletedTasks());
        System.out.println("Rejected tasks: " + executor.getRejectedTasks());
    }
}

你可能感兴趣的:(java,开发语言,算法,线程池)