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 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 workQueue;  

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

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

//在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 workers = new HashSet();  //任务队列

任务队列中存放的是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 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 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 shutdownNow() {
        List 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的主要作用.

你可能感兴趣的:(java多线程,多线程)