Java中的线程池

99 阅读3分钟

“开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 7 天,点击查看活动详情

线程池参数

ThreadPoolExecutor(int corePoolSize,
                   int maximumPoolSize,
                   long keepAliveTime,
                   TimeUnit unit,
                   BlockingQueue<Runnable> workQueue,
                   ThreadFactory threadFactory,
                   RejectedExecutionHandler handler)

1.corePoolSize:核心线程池大小 2.maximumPoolSize:最大线程池大小 3.keepAliveTime:线程最大空闲时间 4.unit:时间单位 5.workQueue:线程等待队列 6.threadFactory:线程创建工厂 7handler:拒绝策略 当在execute(Runnable)方法中提交新任务并且少于corePoolSize线程正在运行时,即使其他工作线程处于空闲状态,会创建一个新线程来处理该请求。如果有多于corePoolSize但小于maximumPoolSize线程正在运行,则仅当队列已满时才会创建新线程。如果maximumPoolSize达到最大值会执行拒绝策略。

线程池拒绝策略

  1. 丢弃任务并且抛出异常(默认)
  2. 丢弃任务但是不抛出异常
  3. 丢弃队列中最早的任务,重新提交被拒绝的任务(要看是否允许丢弃老任务)
  4. 由调用线程来处理该任务,目的要让所有任务都执行完毕

worker线程

private final class Worker extends AbstractQueuedSynchronizer implements Runnable{
    final Thread thread;//Worker持有的线程
    Runnable firstTask;//初始化的任务,可以为null
}

thread是调用构造方法时通过ThreadFactory来创建线程,可以用来执行任务 firstTask是该线程传入的第一个任务,如果该值非null,则在创建初期就立即执行这个任务(对应核心线程情况) 如果该值为null,需要创建一个线程去执行work queue中的任务(非核心线程的创建) Worker线程被创建后就会不断去轮询获取任务去执行,核心线程可以无限轮询,非核心线程只能限时获取任务 当Worker线程无法获取到任务时,循环会结束,主动消除自身在线程池的引用

线程池使用一张Hash表持有线程的引用,通过删除,增加引用来控制线程的生命周期 如何判断线程是否在运行? Worker继承AQS,使用AQS实现独占锁功能,没有使用可重入锁ReentrantLock,依靠不可重入性反应线程现在的状态 线程回收请求执行lock()方法,尝试获取独占锁,获取成功说明线程在运行状态(那么就不能中断线程) 如果线程不是独占锁的状态,那就是空闲状态,说明没在处理任务,可以进行中断 线程池在执行shutdown方法或tryTerminate方法时会调用interruptIdleWorkers方法来中断空闲的线程 interruptIdleWorkers调用tryLock()判断线程是否处于空闲状态,如果处于空闲状态即可回收

手动实现线程池

/**
 * @author Bruce
 */
public class MyThreadPool {
    private AtomicInteger ct = new AtomicInteger(0);//当前执行任务的线程个数
    private int corePoolSize;
    private int maximumPoolSize;
    private long keepAliveTime;
    private TimeUnit unit;
    private BlockingQueue<Runnable> taskQueue;
    private RejectPolicy policy;
    private ArrayList<MyWorker> workers = new ArrayList<>();
    private volatile boolean isStopped;
    private boolean useTimed;

    public int getCt(){
        return ct.get();
    }

    public MyThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, RejectPolicy policy, int maxTasks) {
        assert corePoolSize > 0;
        assert maximumPoolSize > 0;
        assert keepAliveTime >= 0;
        assert maxTasks > 0;
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.keepAliveTime = keepAliveTime;
        this.unit = unit;
        this.taskQueue = new ArrayBlockingQueue<>(maxTasks);
        this.policy = policy;

        useTimed = keepAliveTime != 0;
    }

    /**
     *
     * @param runnable
     * @param max 判断达到哪个阈值
     * @return
     */
    public synchronized boolean addWorker(Runnable runnable, boolean max){
        if (ct.get() > corePoolSize && !max) return false;
        if (ct.get() > maximumPoolSize && max) return false;
        MyWorker worker = new MyWorker(runnable);
        workers.add(worker);
        Thread t = new Thread(worker, "ThreadPool-" + "Thread-" + ct.addAndGet(1));
        t.start();
        return true;
    }

    public void execute(Runnable runnable) throws InterruptedException{
        checkPoolState();

        if (addWorker(runnable, true) || !taskQueue.offer(runnable) || addWorker(runnable, false)) return;

        if (!taskQueue.offer(runnable)){
            reject(runnable);
        }

    }

    private void reject(Runnable runnable) throws InterruptedException {
        switch (policy){
            case ABORT:
                throw new RuntimeException("Task queue is full");
            case DISCARD:
                return;
            case CALLER_RUN:
                runnable.run();
            case DISCARD_OLDEST:
                taskQueue.poll();
                execute(runnable);
        }
    }

    public <V> RunnableFuture<V> submit(Callable<V> task) throws InterruptedException{
        checkPoolState();
        FutureTask<V> futureTask = new FutureTask<>(task);
        execute(futureTask);
        return futureTask;
    }

    // 强制关闭线程池
    public synchronized void stop() {
        isStopped = true;
        for (MyWorker worker : workers) {
            worker.stopWorker();
        }
    }

    public synchronized void shutDown() {
        // 先表示关闭线程池 线程就不能再向线程池提交任务
        isStopped = true;
        // 先等待所有的任务执行完成再关闭线程池
        waitForAllTasks();
        stop();
    }

    private void waitForAllTasks() {
        // 当线程池当中还有任务的时候 就不退出循环
        while (taskQueue.size() > 0) {
            Thread.yield();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private void checkPoolState() {
        if (isStopped){
            throw new RuntimeException("thread pool has been stopped, so quit submitting task");
        }
    }

    class MyWorker implements Runnable{
        private Thread thisThread;
        private final Runnable firstTask;
        private volatile boolean isStopped;

        public MyWorker(Runnable firstTask){
            this.firstTask = firstTask;
        }
        @Override
        public void run() {
            firstTask.run();
            thisThread = Thread.currentThread();
            while (!isStopped){
                try {
                    //useTimed判断 如果在一定时间内没有从队列中获取到任务,就返回null,线程随之退出,但要判断线程数不能小于核心线程数
                    Runnable task = useTimed ? taskQueue.poll(keepAliveTime, unit) : taskQueue.take();
                    if (task == null){
                        int i;
                        boolean exit = true;
                        if (ct.get() > corePoolSize){
                            do {
                                i = ct.get();
                                if (i <= corePoolSize){
                                    exit = false;
                                    break;
                                }
                            }while (!ct.compareAndSet(i, i - 1));//原子性记录当前线程的安全退出
                            if (exit){
                                return;
                            }
                        }else{
                            task.run();
                        }
                    }
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        public synchronized void stopWorker() {
            if (isStopped) {
                throw new RuntimeException("thread has been interrupted");
            }
            isStopped = true;
            thisThread.interrupt();
        }
    }
}

PS:

线程池----美团技术团队

ThreadPoolExecutor源码解析