线程池 - ThreadPoolExecutor

继承了AbstractExecutorService(抽象类)

  该抽象类实现了ExecutorService 接口

  该接口又继承于Executor接口 

      Executor接口只有一个方法void execute(Runnable command);

   Executor是一个顶层接口,其唯一的方法用来执行runnable任务;

   ExecutorService接口继承于Executor,并声明了一些submit,invokeAll,invokeAny及shutdown方法。主要是负责线程的一些操作。

   AbstractExecutorService基本实现了executorService中的方法, 线程池又继承了aes。

核心参数:

   corePoolSize: 核心池大小,默认情况下线程不会超过核心大小。

   maximumPoolSize: 最大线程数, 当达到一定负载时,线程数会超过核心数,但始终小于最大线程数. 当负载较轻会回收线程至核心池数量

   keepAliveTime: 表示线程没有任务执行时,的存活时间. 默认情况,当线程数大于核心小于最大数量时才会启用;  如果调用allowCoreThreadTimeOut(boolean)方法,线程数下界为0

   unit:keepAliveTime的时间单位

   workQueue: 阻塞队列,用来存储等待执行的任务。 一般很少使用abq和pbq,多用lbq和synchronousQueue.队列.  

         abq: arrayBlockingQueue队列,基于数组的先进先出,创建时必须指定大小

         pbq: PriorityBlockingQueue 优先级队列

         lbq: linkedBlockingQueue,基于链表的队列,默认长度为Integer.MAX_VALUE

         synchronousQueue: 不保存任务,直接创建新线程

   threadFactory:线程工厂

   handler: 对拒绝任务的处理策略,四种参数. abortPolicy(丢弃任务并抛异常),discardPolicy(丢弃任务不抛异常),DiscardOldestPolicy(丢弃最前面的任务),callerRunsPolicy(交由调用线程处理)

运行时参数:

   workers: 工作集

   allowCoreThreadTimeOut: 是否允许核心线程设置存活时间

   poolSize: 线程池中当前线程数

   largestPoolSize: 记录曾经出现过的最大线程数

   completedTaskCount: 记录已经执行完的任务数

线程池的四种状态:

    running : 0 创建线程池后

    shutdown : 1 调用了shutdown()方法,此时线程池无法接受新任务

    stop : 2 调用shutdownNow()方法,无法接受新任务并尝试终止现有任务

    terminated : 3 所有工作线程销毁并且任务缓冲队列清空后的状态

常见线程池:

// 实际采用的linkedBlockingQueue,缓存队列,threadNum既是核心线程数也是最大线程数。
ExecutorService pool = Executors.newFixedThreadPool(threadNum);
// 可缓存线程池,实际采用synchronousQueue队列,最大线程数为Integer.MAX_VALUE
ExecutorService pool = Executors.newCachedThreadPool();
// 单线程线程池,只有核心线程和最大线程都为1
ExecutorService pool = Executors.newSingleThreadExecutor();
// 延迟线程池,可实现delay接口,可以延迟或按周期执行。参数为核心线程池数 
ExecutorService pool = Executors.newScheduledThreadPool(threadNum); 

构造函数:

  线程池构造函数: 实际都是指向最后一个构造函数;



// 真正的执行构造函数
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;  // 核心线程数
        this.maximumPoolSize = maximumPoolSize; // 最大线程数
        this.workQueue = workQueue; // 工作队列
        this.keepAliveTime = unit.toNanos(keepAliveTime); // 存活时间
        this.threadFactory = threadFactory; // 线程工程
        this.handler = handler; // 任务拒绝策略
 }

线程池接收新任务的执行流程图 : 

   文字版: 

来一个新任务, 如果目前线程池的线程数量小于核心线程数,则创建一个新线程并执行该任务.;

如果目前线程数大于核心数量,则尝试添加到缓存队列中,如果缓存队列满了则新创建线程并执行.

如果线程数量已达到最大且缓存队列满了,则按照策略拒绝任务

流程图版:

     流程图里的please/just wait和 分配线程,线程执行的具体策略和出现的问题会根据 不同种类的线程池、采取的策略问题而不同。

线程池一些源码:   

public void execute(Runnable command) {
    if (command == null) //任务不能为空
        throw new NullPointerException();

    if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {
/* 
  此时判断未加锁,判断核心线程数和当前线程数的关系,如果数目小于核心线程则直接去创建线程并执行.所以返回true,取!的目的是,说明如果不能创建新线程,则保证任务放入队列中
 */
        if (runState == RUNNING && workQueue.offer(command)) { 
           //判断线程池状态并且将任务放入任务队列中
            if (runState != RUNNING || poolSize == 0) 
               //再次确认状态,确保线程池可以处理任务,防止shutdown的调用
                ensureQueuedTaskHandled(command);//确保任务放入队列中
        } else if (!addIfUnderMaximumPoolSize(command)) {
           //判断当前线程数和最大线程数的关系,如果达到最大则拒绝任务(根据之前参数的选择)
            reject(command); // is shutdown or saturated
        }
    }
}

private void ensureQueuedTaskHandled(Runnable command) {
            //  如果当前状态不是RUNING,则当前任务不加入到任务队列中,判断如果状态是停止,线程数小于允许的最大数,且任务队列还不空
             if (state < STOP &&
                     poolSize < Math.max(corePoolSize, 1) &&
                     !workQueue.isEmpty())
            //则加入一个新的工作线程到线程池来帮助处理还未处理完的任务
                t = addThread(null);
        if (reject)
            reject(command);
}

private boolean addIfUnderCorePoolSize(Runnable firstTask) {
    Thread t = null;
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock(); //上锁
    try {
        if (poolSize < corePoolSize && runState == RUNNING) //线程数小于核心数,则添加新的线程并执行任务
            t = addThread(firstTask);        //创建线程去执行firstTask任务   
        } finally {
        mainLock.unlock();
    }
    if (t == null) //创建失败
        return false;
    t.start(); //启动线程
    return true;
}


private Thread addThread(Runnable firstTask) { 
    Worker w = new Worker(firstTask);
    Thread t = threadFactory.newThread(w);  //创建一个线程,执行任务   
    if (t != null) {
        w.thread = t;            //将创建的线程的引用赋值为w的成员变量       
        workers.add(w);
        int nt = ++poolSize;     //当前线程数加1       
        if (nt > largestPoolSize) //更新最大线程数记录
            largestPoolSize = nt;
    }
    return t;
}

Worker 类

private final class Worker implements Runnable { //说明是个线程
    private final ReentrantLock runLock = new ReentrantLock();
    private Runnable firstTask;
    volatile long completedTasks;
    Thread thread;
    Worker(Runnable firstTask) {
        this.firstTask = firstTask;
    }

    boolean isActive() { //判断是否可以自由/活跃,为true说明已上锁
        return runLock.isLocked();
    }

    void interruptIfIdle() {
        final ReentrantLock runLock = this.runLock;
        if (runLock.tryLock()) {
            try {
        if (thread != Thread.currentThread())
        thread.interrupt();
            } finally {
                runLock.unlock();
            }
        }
    }

    void interruptNow() {
        thread.interrupt();
    }
 
    private void runTask(Runnable task) {
        final ReentrantLock runLock = this.runLock;
        runLock.lock();//上锁
        try {
            if (runState < STOP &&
                Thread.interrupted() &&
                runState >= STOP)
            boolean ran = false;
            beforeExecute(thread, task);   //beforeExecute方法是ThreadPoolExecutor类的一个方法,没有具体实现,用户可以根据
            //自己需要重载这个方法和后面的afterExecute方法来进行一些统计信息,比如某个任务的执行时间等           
            try {
                task.run();
                ran = true;
                afterExecute(task, null);
                ++completedTasks;
            } catch (RuntimeException ex) {
                if (!ran)
                    afterExecute(task, ex);
                throw ex;
            }
        } finally {
            runLock.unlock();
        }
    }
 
    public void run() {
        try {
            Runnable task = firstTask;
            firstTask = null;
            while (task != null || (task = getTask()) != null) {
                runTask(task);//执行任务
                task = null;
            }
        } finally {
            workerDone(this);   //当任务队列中没有任务时,进行清理工作       
        }
    }
}

Runnable getTask() { //从缓存队列中取任务
    for (;;) {
        try {
            int state = runState;
            if (state > SHUTDOWN)
                return null;
            Runnable r;
            if (state == SHUTDOWN)  // Help drain queue
                r = workQueue.poll();
            else if (poolSize > corePoolSize || allowCoreThreadTimeOut) //如果线程数大于核心池大小或者允许为核心池线程设置空闲时间,
                //则通过poll取任务,若等待一定的时间取不到任务,则返回null
                r = workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS);
            else
                r = workQueue.take();
            if (r != null)
                return r;
            if (workerCanExit()) {    //如果没取到任务,即r为null,则判断当前的worker是否可以退出
                if (runState >= SHUTDOWN) // Wake up others
                    interruptIdleWorkers();   //中断处于空闲状态的worker
                return null;
            }
            // Else retry
        } catch (InterruptedException ie) {
            // On interruption, re-check runState
        }
    }
}

private boolean workerCanExit() {//判断是否可以退出
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    boolean canExit;
    //如果runState大于等于STOP,或者任务缓存队列为空了
    //或者  允许为核心池线程设置空闲存活时间并且线程池中的线程数目大于1
    try {
        canExit = runState >= STOP ||
            workQueue.isEmpty() ||
            (allowCoreThreadTimeOut &&
             poolSize > Math.max(1, corePoolSize));
    } finally {
        mainLock.unlock();
    }
    return canExit;
}
void interruptIdleWorkers() {//中断worker
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        for (Worker w : workers)  //实际上调用的是worker的interruptIfIdle()方法
            w.interruptIfIdle();
    } finally {
        mainLock.unlock();
    }
}
void interruptIfIdle() {
    final ReentrantLock runLock = this.runLock;
    if (runLock.tryLock()) {    //注意这里,是调用tryLock()来获取锁的,因为如果当前worker正在执行任务,锁已经被获取了,是无法获取到锁的
                                //如果成功获取了锁,说明当前worker处于空闲状态
        try {
    if (thread != Thread.currentThread())  
    thread.interrupt();
        } finally {
            runLock.unlock();
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_26140191/article/details/85762935