java多线程——ThreadPoolExecutor线程池及实现原理

线程池的核心类ThreadPoolExecutor:

线程池可以解决两个不同问题:由于减少了每个任务调用的开销,它们通常可以在执行大量异步任务时提供增强的性能,并且还可以提供绑定和管理资源(包括执行任务集时使用的线程)的方法。每个 ThreadPoolExecutor 还维护着一些基本的统计数据,如完成的任务数。

ThreadPoolExecutor继承了AbstractExecutorService,提供四个构造方法,但最终都是调用一个构造方法来创建对象:

    /**
     * @param corePoolSize 线程池核心线程数量
     * @param maximumPoolSize 线程池最大线程数量
     * @param keepAliveTime 当活跃线程数大于核心线程数时,空闲的多余线程最大存活时间
     * @param unit  keepAliveTime存活时间的单位
     * @param workQueue 存放任务的队列
     * @param threadFactory 用ThreadFactory创建线程,默认用deaufltThreadFactory创建线程
     * @param handler  超出线程范围和队列容量的任务的处理程序
     *
     */
    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;
    }

AbstractExecutorService中的一些方法如submit等,并没有在ThreadPoolExecutor中重写,而是直接使用父类中的方法,在后续的介绍中会慢慢介绍。

ThreadPoolExecutor实现线程池源码解析:

ThreadPoolExecutor中定义的一些变量和常量信息:

线程状态:

//存储所有有效线程的数量和各个线程的状态信息,低29位存线程数,高3位存runState,
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

	// 线程池状态runState,共有五种
	//线程池正常运行,可以接受新的任务并处理队列中的任务;
	private static final int RUNNING    = -1 << COUNT_BITS;  
	//不再接受新的任务,但是会执行队列中的任务;
	private static final int SHUTDOWN   =  0 << COUNT_BITS;  
	//不再接受新任务,不处理队列中的任务
	private static final int STOP       =  1 << COUNT_BITS;  
	//所有的任务都已经停止,workerCount为0,执行terminate()方法
	private static final int TIDYING    =  2 << COUNT_BITS;  
	//terminated()方法执行完成
	private static final int TERMINATED =  3 << COUNT_BITS;  

线程状态以及状态之间的转换:

  1. Running,线程池创建并初始化时,线程池处于RUNNING状态;
  2. Running ——> Shutdown,调用 shutdown()方法;
  3. Running /shutdown ——> Stop,调用shotdownNow()方法;
  4. shutdown ——> Tidying, 队列和线程池都为空;
  5. Stop ——> Tidying, 当线程池为空;
  6. Tidying——> Terminated,terminated()完成。

ctl变量时整个类的核心,AtomicInteger保证了变量操作的原子性,下面看一下atl如何存储和获取线程状态和工作线程数的:

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

private static final int COUNT_BITS = Integer.SIZE - 3;
//二进制数为:00011111111111111111111111111111
private static final int CAPACITY   = (1 << COUNT_BITS) - 1; 

//获取线程状态,取出runState的值(取反,按位与)
private static int runStateOf(int c)     { return c & ~CAPACITY; }

//获取工作线程数,取出workerCount的值(按位与)
private static int workerCountOf(int c)  { return c & CAPACITY; }

//将runState和workerCount存到同一个int中(按位或)
private static int ctlOf(int rs, int wc) { return rs | wc; }

线程池属性信息字段:

//任务队列
private final BlockingQueue<Runnable> workQueue;  

//线程池的主要状态锁,对线程池状态(比如线程池大小、runState等)的改变都要使用这个锁
private final ReentrantLock mainLock = new ReentrantLock(); 

//存放工作集
private final HashSet<Worker> workers = new HashSet<Worker>(); 

//在mainLock下访问的最大线程数
private int largestPoolSize; 

//核心线程数  
private volatile int corePoolSize; 

//最大线程数    
private volatile int maximumPoolSize; 

//已执行完任务数 
private long completedTaskCount;

//用来创建线程的线程工厂  
private volatile ThreadFactory threadFactory;

//任务拒绝策略  
private volatile RejectedExecutionHandler handler;

//线程空闲存活时间  
private volatile long keepAliveTime;  

//是否允许核心线程设置存活时间
private volatile boolean allowCoreThreadTimeOut;

//等待终止的条件
private final Condition termination = mainLock.newCondition(); 

//默认使用的拒绝策略 
private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();

//设置运行时权限  
private static final RuntimePermission shutdownPerm = new RuntimePermission("modifyThread");  

ThreadPoolExecutor中定义的五个内部类:

Worker:

private final class Worker extends AbstractQueuedSynchronizer implements Runnable

    private final class Worker
        extends AbstractQueuedSynchronizer
        implements Runnable
    {
        private static final long serialVersionUID = 6138294804551838833L;

        //线程这个工作程序正在运行。如果工厂失败,则为空
        final Thread thread;
        //初始化线程任务
        Runnable firstTask;
        // 线程任务计数器 
        volatile long completedTasks;

        Worker(Runnable firstTask) {
            setState(-1); // inhibit interrupts until runWorker
            this.firstTask = firstTask;
            this.thread = getThreadFactory().newThread(this);
        }

        public void run() {
            runWorker(this);
        }

        //是否持有锁,0未持有锁,1尺有所
        protected boolean isHeldExclusively() {
            return getState() != 0;
        }

        protected boolean tryAcquire(int unused) {
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        protected boolean tryRelease(int unused) {
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

        public void lock()        { acquire(1); }
        public boolean tryLock()  { return tryAcquire(1); }
        public void unlock()      { release(1); }
        public boolean isLocked() { return isHeldExclusively(); }

        void interruptIfStarted() {
            Thread t;
            if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
                try {
                    t.interrupt();
                } catch (SecurityException ignore) {
                }
            }
        }
    }

ThreadPoolExecutor的属性变量中定义了一个存放工作集的变量worker:

  • private final HashSet<Worker> workers = new HashSet<Worker>();  //任务队列

任务队列中存放的是Worker类型的数据,而Worker实现了Runnable接口,所以Worker是一个线程类。Worker还继承了AbstractQueuedSynchronizer类,以简化获取和释放每个任务执行周围的锁,可以防止中断。Worker主要维护运行任务的线程的中断控制状态,以及其他次要的记帐功能。实现互斥锁主要目的是为了中断的时候判断线程是在空闲还是运行。这里不用ReentrantLock是为了避免任务执行的代码中修改线程池的变量。

关于AbstractQueueSynchronized:提供了一个基于FIFO队列,可以用于构建锁或者其他相关同步装置的基础框架。该同步器(以下简称同步器)利用了一个int来表示状态,期望它能够成为实现大部分同步需求的基础。使用的方法是继承,子类通过继承同步器并需要实现它的方法来管理其状态,管理的方式就是通过类似acquire和release的方式来操纵状态。

Worker中重写的run方法中调用的事runWorker()方法:runWorker()是第一次启动执行初始化进来的任务firstTask,然后会从workQueue中获取任务执行。

    final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;        
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;  //是否异常,执行任务抛异常或被中断,则为true
        try {
            while (task != null || (task = getTask()) != null) {
                w.lock();
                // 如果池停止,确保线程被中断;否则确保线程未被中断
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                try {
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
                        task.run();
                    } catch (RuntimeException x) {
                        thrown = x; throw x;
                    } catch (Error x) {
                        thrown = x; throw x;
                    } catch (Throwable x) {
                        thrown = x; throw new Error(x);
                    } finally {
                        afterExecute(task, thrown);
                    }
                } finally {
                    task = null;
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            processWorkerExit(w, completedAbruptly);
        }
    }

拒绝策略内部类:

    public static class CallerRunsPolicy implements RejectedExecutionHandler {
        public CallerRunsPolicy() { }

        //在调用者的线程中执行任务r,除非执行器已关闭(在这种情况下,任务将被丢弃)。 
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                r.run();
            }
        }
    }


    //系统默认的拒绝策略
    public static class AbortPolicy implements RejectedExecutionHandler {
        public AbortPolicy() { } 

        //抛出异常:RejectedExecutionException. 
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            throw new RejectedExecutionException("Task " + r.toString() +
                                                 " rejected from " +
                                                 e.toString());
        }
    }

    public static class DiscardPolicy implements RejectedExecutionHandler { 
        public DiscardPolicy() { }

        /**
         *仅仅丢弃处理任务,不做其他操作
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        }
    }


    public static class DiscardOldestPolicy implements RejectedExecutionHandler { 
        public DiscardOldestPolicy() { }

        /**
         * 丢弃最开始的请求,然后重试 
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                e.getQueue().poll(); //removeFirst
                e.execute(r);
            }
        }
    }

如果缓冲队列workQueue已满,且线程池数量达到最大maximumPoolSize,线程池会使用handler指定的拒绝策略处理新添加的任务。处理任务的优先级为:核心线程corePoolSize、任务队列workQueue、最大线程maximumPoolSize、handler执行的任务处理器。

ThreadPoolExecutor中的方法:

//常用方法
void execute(Runnable command) 
          在将来某个时间执行给定任务。 
void shutdown() 
          按过去执行已提交任务的顺序发起一个有序的关闭,但是不接受新任务。 
List<Runnable> shutdownNow() 
          尝试停止所有的活动执行任务、暂停等待任务的处理,并返回等待执行的任务列表。 
boolean isShutdown() 
          如果此执行程序已关闭,则返回 true。 
boolean isTerminated() 
          如果关闭后所有任务都已完成,则返回 true。 
boolean isTerminating() 
          如果此执行程序处于在 shutdown 或 shutdownNow 之后正在终止但尚未完全终止的过程中,则返回 true。 

//获取/设置常用属性信息		  
 int getActiveCount() 
          返回主动执行任务的近似线程数。 
 long getCompletedTaskCount() 
          返回已完成执行的近似任务总数。 
 int getCorePoolSize() 
          返回核心线程数。 
 long getKeepAliveTime(TimeUnit unit) 
          返回线程保持活动的时间,该时间就是超过核心池大小的线程可以在终止前保持空闲的时间值。 
 int getLargestPoolSize() 
          返回曾经同时位于池中的最大线程数。 
 int getMaximumPoolSize() 
          返回允许的最大线程数。 
 int getPoolSize() 
          返回池中的当前线程数。 
 BlockingQueue<Runnable> getQueue() 
          返回此执行程序使用的任务队列。 
 RejectedExecutionHandler getRejectedExecutionHandler() 
          返回用于未执行任务的当前处理程序。 
 long getTaskCount() 
          返回曾计划执行的近似任务总数。 
 ThreadFactory getThreadFactory() 
          返回用于创建新线程的线程工厂。 
 void setCorePoolSize(int corePoolSize) 
          设置核心线程数。 
 void setKeepAliveTime(long time, TimeUnit unit) 
          设置线程在终止前可以保持空闲的时间限制。 
 void setMaximumPoolSize(int maximumPoolSize) 
          设置允许的最大线程数。 
 void setRejectedExecutionHandler(RejectedExecutionHandler handler) 
          设置用于未执行任务的新处理程序。 
 void setThreadFactory(ThreadFactory threadFactory) 
          设置用于创建新线程的线程工厂。 

//不常用方法		
 void allowCoreThreadTimeOut(boolean value) 
          如果在保持活动时间内没有任务到达,新任务到达时正在替换(如果需要),则设置控制核心线程是超时还是终止的策略。 
 boolean allowsCoreThreadTimeOut() 
          如果此池允许核心线程超时和终止,如果在 keepAlive 时间内没有任务到达,新任务到达时正在替换(如果需要),则返回 true。 
 boolean awaitTermination(long timeout, TimeUnit unit) 
          请求关闭、发生超时或者当前线程中断,无论哪一个首先发生之后,都将导致阻塞,直到所有任务完成执行。		  		
		  
 int prestartAllCoreThreads() 
          启动所有核心线程,使其处于等待工作的空闲状态。 
 boolean prestartCoreThread() 
          启动核心线程,使其处于等待工作的空闲状态。 
 void purge() 
          尝试从工作队列移除所有已取消的 Future 任务。 
 boolean remove(Runnable task) 
          从执行程序的内部队列中移除此任务(如果存在),从而如果尚未开始,则其不再运行。 
 

execute()方法:

execute方法主要三个步骤:

  • 活动线程小于corePoolSize的时候创建新的线程;
  • 活动线程大于corePoolSize时都是先加入到任务队列当中;
  • 任务队列满了再去启动新的线程,如果线程数达到最大值就拒绝任务。
    public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        int c = ctl.get();
        //活动线程数 < coorPoolSize
        if (workerCountOf(c) < corePoolSize) {
            // 启动新线程,第二个参数true:addWorker中会检查workerCount是否小于corePoolSize
            if (addWorker(command, true))
                //添加成功则返回
                return;
            c = ctl.get();
        }
        //活动线程数 >= corePoolSize, runState 为Running && 队列未满 
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            //非Running状态,则从workeQueue中移除任务并拒绝
            if (! isRunning(recheck) && remove(command))
                reject(command);//拒绝,拒绝策略
            // 线程池处于RUNNING状态 || 线程池处于非RUNNING状态但是任务移除失败
            else if (workerCountOf(recheck) == 0)
                // 这行代码是为了SHUTDOWN状态下没有活动线程了,但是队列里还有任务没执行这种特殊情况。
             // 添加一个null任务是因为SHUTDOWN状态下,线程池不再接受新任务
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command);
    }

可以看到execute方法中,addWorker方法出现了三次,下面主要来看一下addWorker():

    //是否可以根据当前池状态和给定的界限(核心或最大值)添加新worker
    private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;   //返回false,线程创建失败

            //线程池状态为Running,或状态为ShunDown,但队列中还有要执行的任务
            for (;;) {
                int wc = workerCountOf(c);
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                if (compareAndIncrementWorkerCount(c)) //递增workCount
                    break retry; //返回到retry标记,跳出循环
                c = ctl.get();  // Re-read ctl
                if (runStateOf(c) != rs) //若线程池状态发生变化,重试
                    continue retry;
            }
        }

        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
            final ReentrantLock mainLock = this.mainLock;
            w = new Worker(firstTask);
            final Thread t = w.thread;
            if (t != null) {
                mainLock.lock();  //并发访问线程池woekers对象加锁
                try {
                    // Recheck while holding lock.
                    // Back out on ThreadFactory failure or if
                    // shut down before lock acquired.
                    int c = ctl.get();
                    int rs = runStateOf(c);

                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        if (t.isAlive()) 
                            throw new IllegalThreadStateException();
                        workers.add(w); //将启动的线程添加到线程池
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;  
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }

shutdown:

shutdown这个方法会将runState置为SHUTDOWN,并终止所有空闲的线程。

    public void shutdown() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            checkShutdownAccess();
            advanceRunState(SHUTDOWN); //线程池状态设为SHUTDOWN,若已经至少是这个状态则直接返回
            //中断所有空闲的线程:runWorker中等待的线程被中断 → 进入processWorkerExit
            interruptIdleWorkers();
            onShutdown(); // hook for ScheduledThreadPoolExecutor
        } finally {
            mainLock.unlock();
        }
        //保证队列中剩余的任务得到执行
        tryTerminate();
    }

shutdownNow:

shutdownNow方法将runState置为STOP,并终止所有的线程。


    public List<Runnable> shutdownNow() {
        List<Runnable> tasks;
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            checkShutdownAccess();
	          // STOP状态:不再接受新任务且不再执行队列中的任务。
            advanceRunState(STOP);
	          // 中断所有线程
            interruptWorkers();
	          // 返回队列中还没有被执行的任务。
            tasks = drainQueue();
        } finally {
            mainLock.unlock();
        }
        tryTerminate();
        return tasks;
    }

shutdown 和 shutdownNow的主要区别是:shutdown将runState置为SHUTDOWN,并终止所有空闲的线程;而shutdownNow将runState置为STOP,并终止所有的线程。从二者的源码中可以看到,shutdown调用的是interruptIdleWorker方法,而shutdownNow调用的是interruptIfStarted方法:

    private void interruptIdleWorkers(boolean onlyOne) {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            for (Worker w : workers) {
                Thread t = w.thread;
	           // w.tryLock能获取到锁,说明该线程没有在运行,因为runWorker中执行任务会先lock,
                  // 因此保证了中断的肯定是空闲的线程。
                if (!t.isInterrupted() && w.tryLock()) {
                    try {
                        t.interrupt();
                    } catch (SecurityException ignore) {
                    } finally {
                        w.unlock();
                    }
                }
                if (onlyOne)
                    break;
            }
        } finally {
            mainLock.unlock();
        }
    }


      //内部类Worker的方法
      void interruptIfStarted() {
          Thread t;
            //初始化时state == -1
          if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
              try {
                  t.interrupt();
              } catch (SecurityException ignore) {
              }
          }
      }

这就是前面提到的Woker类实现AQS的主要作用.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值