Java线程池源码解析

Java线程池基础传送门:Java线程池基础及AtomicInteger

Java线程池原理

除了newScheduledThreadPool,其他线程池都是基于ThreadPoolExecutor实现的。

线程池内部状态

既然是线程池,必然存在生命周期:运行中,关闭,停止等。ThreadPoolExecutor是用AtomicInteger变量ctl前三位表示这个状态的,另外用了后29位表示线程数,最大可以支持5亿多,如果以后硬件可以支持启动这么多线程,直接将AtomicInteger改成AtomicLong就可以了。

  1. RUNNING:该状态的线程池正在运行中,会接收新任务,并处理阻塞队列中的任务
  2. SHUTDOWN:该状态的线程池不会接收新任务,但会处理阻塞队列中的任务
  3. STOP :该状态的线程不会接收新任务,也不会处理阻塞队列中的任务,而且会中断正在运行中的任务
  4. TIDYING:所有任务都已经处理完毕,线程数为0,转为为TIDYING状态之后,会调用terminated()回调
  5. TERMINATED:terminated()执行完毕

所有状态都是二进制表示的,而且依次递增,从而比较方便比较。比如想获取当前是否为运行状态,直接判断是否runStateOf(ctl)<SHUTDOWN就可以。

    //保存线程数和线程状态
	private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));	
    private static final int COUNT_BITS = Integer.SIZE - 3;
    private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

    // runState is stored in the high-order bits	将低三位移到高三位
    private static final int RUNNING    = -1 << COUNT_BITS;		//0x111
    private static final int SHUTDOWN   =  0 << COUNT_BITS;		//0x000
    private static final int STOP       =  1 << COUNT_BITS;		//0x001
    private static final int TIDYING    =  2 << COUNT_BITS;		//0x010
    private static final int TERMINATED =  3 << COUNT_BITS;		//0x011

    // Packing and unpacking ctl 
    private static int runStateOf(int c)     { return c & ~CAPACITY; }	//取高三位
    private static int workerCountOf(int c)  { return c & CAPACITY; }	//取低29位
    private static int ctlOf(int rs, int wc) { return rs | wc; }

    //高三位+第三位进行或操作即可
    private static int ctlOf(int rs, int wc) { return rs | wc; }

    private static boolean runStateLessThan(int c, int s) {
        return c < s;
    }

    private static boolean runStateAtLeast(int c, int s) {
        return c >= s;
    }

    private static boolean isRunning(int c) {
        return c < SHUTDOWN;
    }
    
    //下面三个方法,通过CAS修改worker的数目
    private boolean compareAndIncrementWorkerCount(int expect) {
        return ctl.compareAndSet(expect, expect + 1);
    }
    
    //只尝试一次,失败了则返回,是否重试由调用方决定
    private boolean compareAndDecrementWorkerCount(int expect) {
        return ctl.compareAndSet(expect, expect - 1);
    }
    
    //跟上一个不一样,会一直重试
    private void decrementWorkerCount() {
        do {} while (! compareAndDecrementWorkerCount(ctl.get()));
    }

下面是比较核心的字段,这里workers采用的是非线程安全的HashSet,而不是线程安全的版本,主要是因为这里有一些复合的操作,比如说将worker添加到workers后,我们还需要判断是需要更新largestPoolSize等,workers只有在获取到mainLock的情况下才会进行读写,另外这里的mainLock也用于中断线程的时候进行串行执行,否则如果不加锁的话,可能会造成并发去中断线程,引起不必要的中断风暴。

private final ReentrantLock mainLock = new ReentrantLock();

private final HashSet<Worker> workers = new HashSet<Worker>();

private final Condition termination = mainLock.newCondition();

private int largestPoolSize;

private long completedTaskCount;

核心方法

ThreadPoolExecutor#submit()

拿到一个线程池后,我们就可以提交任务,让它去执行了,我们看一下submit是如何实现的。

    public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<Void> ftask = newTaskFor(task, null);
        execute(ftask);
        return ftask;
    }

    public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }

这两个方法都很简单,可以接收Runnable和Callable参数,都包装成RunnableFuture,然后调用execute()方法,execute是线程池最核心的一个方法。

ThreadPoolExecutor#execute()
public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
   
        int c = ctl.get();
    
        //判断当前worker数量,小于核心则扩容
        if (workerCountOf(c) < corePoolSize) {
            /*
            	调用addWorker(Runnable firstTask, boolean core)进行扩容,
            	fitstTask表示worker启动后要执行的第一个任务,core为是否为核心线程
            */
            if (addWorker(command, true))		
                return;
            //如果增加失败,那么重新获取ctl快照(有可能线程池在这个期间关闭了)
            c = ctl.get();		
        }
   		//线程池状态为正在执行,然后将任务加入队列成功
        if (isRunning(c) && workQueue.offer(command)) {	
            //
            int recheck = ctl.get();
            /*
            	进行一次double check,检查线程池是否关闭了。
            	如果不是运行中的状态,则不再接受新任务,将任务移除成功后调用拒绝处理器jeject()
            */
            if (! isRunning(recheck) && remove(command))
                reject(command);	//执行reject方法处理任务
            /*
            	如果仍为进行中的状态,则double check检查当前work是否为0,
            	如果为0,则可能在上面逻辑执行过程中,有worker销毁,那么再进行一次扩容。
            	这里任务已经进入队列了,所以不需要传递firstTask,这里的扩容为非核心线程false
            */
            else if (workerCountOf(recheck) == 0)	//???
                addWorker(null, false);		//????
        }
        else if (!addWorker(command, false))
            reject(command);
    }

……%%&……*@#@ 待补充,没看懂

ThreadPoolExecutor#addWorker()

线程池的具体扩容操作

private boolean addWorker(Runnable firstTask, boolean core) {
    
    	retry:
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);	//获取当前线程池的状态


            /*
            	如果线程值的状态>=shutdown,那么此时线程池已经不再接受任务,因此可以直接返回false;
            	如果状态为SHUTDOWN并且firstTask为空,同时队列非空,则可以进行扩容
            */
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;

            for (;;) {
                int wc = workerCountOf(c);		
                //如果work大于容量,直接返回false;然后根据是否为核心线程判断work数量
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;	
                //CAS操作自增worker,成功则跳出循环
                if (compareAndIncrementWorkerCount(c))	
                    break retry;		//跳出retry循环,开始创建新的线程执行任务
                // 重新读取变量
                c = ctl.get();  
                //和之前线程池状态不一致(比如线程池关闭了),则跳到最外层for循环
                if (runStateOf(c) != rs)	
                    continue retry;
                // else CAS failed due to workerCount change; retry inner loop
            }
        }
    
        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
            w = new Worker(firstTask);		//新建线程
            final Thread t = w.thread;
            if (t != null) {
                //可重入锁
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();	//获得锁
                try {

                    int rs = runStateOf(ctl.get());		//获取线程运行状态
                    //当前线程池正在运行或者 已经shutdown并且没有正在执行的任务
                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        //判断线程是否已经启动,如果为true,证明已经调用了start方法,抛出异常
                        if (t.isAlive()) 
                            throw new IllegalThreadStateException();
                        //加入HashSet<worker> workers
                        workers.add(w);		
                        int s = workers.size();
                        //更新largestPoolSize
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                //如果worker添加成功,则启动线程,这时候worker就开始执行任务了
                if (workerAdded) {
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                 //添加失败
                addWorkerFailed(w);
        }
        return workerStarted;
    }
ThreadPoolExecutor#Worker
  1. Worker继承自同步器AQS,可以方便的实现线程中止操作。使用了状态变量state表示是否获取锁,0表示解锁,1表示获得所。exclusiveOwnerThread表示当前持有锁的线程。

  2. 实现了Runnable接口,可以将自身作为一个任务在工作线程中执行。

  3. 在创建线程对象时,将自身作为参数传入,当调用Thread.start()时,实际上是调用task.run();

	private final class Worker
        extends AbstractQueuedSynchronizer
        implements Runnable
    {
        /**
         * This class will never be serialized, but we provide a
         * serialVersionUID to suppress a javac warning.
         */
        private static final long serialVersionUID = 6138294804551838833L;

        /** Thread this worker is running in.  Null if factory fails. */
        final Thread thread;
        /** Initial task to run.  Possibly null. */
        Runnable firstTask;
        /** Per-thread task counter */
        volatile long completedTasks;

        /**
         * Creates with given first task and thread from ThreadFactory.
         * @param firstTask the first task (null if none)
         */
        Worker(Runnable firstTask) {
            setState(-1); // inhibit interrupts until runWorker
            this.firstTask = firstTask;
            this.thread = getThreadFactory().newThread(this);
        }

        /** Delegates main run loop to outer runWorker  */
        public void run() {
            runWorker(this);	//实际执行的Run方法
        }

        // Lock methods
        //
        // The value 0 represents the unlocked state.
        // The value 1 represents the locked state.

        protected boolean isHeldExclusively() {
            return getState() != 0;
        }

		//尝试CAS操作获取锁
        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) {
                }
            }
        }
    }

这里执行Worker构造方法时,state状态为-1,直到执行runWorker方法时才会被设置为0,也就是说,在Worker启动之前,都不允许进行加锁操。

ThreadPoolExecutor#runWorker()

在线程启动后,实际执行的Run方法是runWorker(Worker w)

	final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // 此时允许中断正在执行的任务,将state设为0,其他线程可以获得所或者中断锁
        boolean completedAbruptly = true;
        try {
             /*
                首先尝试执行firstTask,若没有的话,则调用getTask()从队列中获取任务
             */
            while (task != null || (task = getTask()) != null) {
                w.lock();
                // If pool is stopping, ensure thread is interrupted;
                // if not, ensure thread is not interrupted.  This
                // requires a recheck in second case to deal with
                // shutdownNow race while clearing interrupt
                /*
                以上翻译过来:
                如果线程池正在停止,请确保线程被中断;
                如果没有,请确保线程没有中断。
                这需要在第二种情况下重新检查,以便在清除中断时处理shutdownnow race
                */
                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回调函数,同上
                        afterExecute(task, thrown);
                    }
                } finally {
                    task = null;
                    //已完成任务++,因为在锁中,没有线程安全问题,volatile修饰,保证可见性
                    w.completedTasks++;	
                    w.unlock();	//释放锁
                }
            }
            completedAbruptly = false;
        } finally {
            processWorkerExit(w, completedAbruptly);	//执行出队
        }
    }

	private void processWorkerExit(Worker w, boolean completedAbruptly) {
        //如果是异常终止的,那么减少worker的数目
        if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
            decrementWorkerCount();

        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            //将当前worker中workers中删除掉,并累加当前worker已执行的任务到completedTaskCount中
            completedTaskCount += w.completedTasks;
            workers.remove(w);
        } finally {
            mainLock.unlock();
        }

        //上文说过,减少worker的操作都需要调用这个方法
        tryTerminate();

        /*
            如果当前线程池仍然是运行中的状态,那么就看一下是否需要新增另外一个worker替换此worker
         */
        int c = ctl.get();
        if (runStateLessThan(c, STOP)) {
            /*
                如果是异常结束的则直接扩容,否则的话则为正常退出,比如当前队列中已经没有任务需要处理,
                如果允许core线程超时的话,那么看一下当前队列是否为空,空的话则不用扩容。否则话看一下
                是否少于corePoolSize个worker在运行。
             */
            if (!completedAbruptly) {
                int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
                if (min == 0 && ! workQueue.isEmpty())
                    min = 1;
                if (workerCountOf(c) >= min)
                    return; // replacement not needed
            }
            addWorker(null, false);
        }
    }


 	private Runnable getTask() {
        boolean timedOut = false; // 上一次poll()是否超时了

        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);

            // 若线程池关闭了(状态大于STOP)
            // 或者线程池处于SHUTDOWN状态,但是队列为空,那么返回null
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }

            int wc = workerCountOf(c);

            /*
                如果允许core线程超时 或者 不允许core线程超时但当前worker的数目大于core线程数,
                那么下面的poll()则超时调用
             */
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

            /*
                获取任务超时了并且(当前线程池中还有不止一个worker 或者 队列中已经没有任务了),那么就尝试
                减少worker的数目,若失败了则重试
             */
            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }

            try {
                //从队列中抓取任务
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    return r;
                //走到这里表明,poll调用超时了
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

这里有个貌似不太起眼的方法tryTerminate,这个方法会在所有可能导致线程池终结的地方调用,比如说减少worker的数目等,如果满足条件的话,那么将线程池转换为TERMINATED状态。另外这个方法没有用private修饰,因为ScheduledThreadPoolExecutor继承自ThreadPoolExecutor,而ScheduledThreadPoolExecutor也会调用这个方法。

    final void tryTerminate() {
        for (;;) {
            int c = ctl.get();
            /*
                如果当前线程处于运行中、TIDYING、TERMINATED状态则直接返回,运行中的没
                什么好说的,后面两种状态可以说线程池已经正在终结了,另外如果处于SHUTDOWN状态,
                并且workQueue非空,表明还有任务需要处理,也直接返回
             */
            if (isRunning(c) ||
                runStateAtLeast(c, TIDYING) ||
                (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
                return;
            //可以退出,但是线程数非0,那么就中断一个线程,从而使得关闭的信号能够传递下去,
            //中断worker后,worker捕获异常后,会尝试退出,并在这里继续执行tryTerminate()方法,
            //从而使得信号传递下去
            if (workerCountOf(c) != 0) {
                interruptIdleWorkers(ONLY_ONE);
                return;
            }

            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                //尝试转换成TIDYING状态,执行完terminated回调之后
                //会转换为TERMINATED状态,这个时候线程池已经完整关闭了,
                //通过signalAll方法,唤醒所有阻塞在awaitTermination上的线程
                if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                    try {
                        terminated();
                    } finally {
                        ctl.set(ctlOf(TERMINATED, 0));
                        termination.signalAll();
                    }
                    return;
                }
            } finally {
                mainLock.unlock();
            }
            // else retry on failed CAS
        }
    }

    /**
     * 中断空闲的线程
     * @param onlyOne
     */
    private void interruptIdleWorkers(boolean onlyOne) {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            for (Worker w : workers) {
                //遍历所有worker,若之前没有被中断过,
                //并且获取锁成功,那么就尝试中断。
                //锁能够获取成功,那么表明当前worker没有在执行任务,而是在
                //获取任务,因此也就达到了只中断空闲线程的目的。
                Thread t = w.thread;
                if (!t.isInterrupted() && w.tryLock()) {
                    try {
                        t.interrupt();
                    } catch (SecurityException ignore) {
                    } finally {
                        w.unlock();
                    }
                }
                if (onlyOne)
                    break;
            }
        } finally {
            mainLock.unlock();
        }
    }
关闭线程池

关闭线程池一般有两种形式 ,shutdown()和shutdownNow()

    public void shutdown() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            checkShutdownAccess();
            //通过CAS将状态更改为SHUTDOWN,这个时候线程池不接受新任务,但会继续处理队列中的任务
            advanceRunState(SHUTDOWN);
            //中断所有空闲的worker,也就是说除了正在处理任务的worker,其他阻塞在getTask()上的worker
            //都会被中断
            interruptIdleWorkers();
            //执行回调
            onShutdown(); // hook for ScheduledThreadPoolExecutor
        } finally {
            mainLock.unlock();
        }
        tryTerminate();
        //这个方法不会等待所有的任务处理完成才返回
    }
    public List<Runnable> shutdownNow() {
        List<Runnable> tasks;
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            checkShutdownAccess();
            /*
                不同于shutdown(),会转换为STOP状态,不再处理新任务,队列中的任务也不处理,
                而且会中断所有的worker,而不只是空闲的worker
             */
            advanceRunState(STOP);
            interruptWorkers();
            tasks = drainQueue();//将所有的任务从队列中弹出
        } finally {
            mainLock.unlock();
        }
        tryTerminate();
        return tasks;
    }

    private List<Runnable> drainQueue() {
        BlockingQueue<Runnable> q = workQueue;
        ArrayList<Runnable> taskList = new ArrayList<Runnable>();
        /*
            将队列中所有的任务remove掉,并添加到taskList中,
            但是有些队列比较特殊,比如说DelayQueue,如果第一个任务还没到过期时间,则不会弹出,
            因此这里通过调用toArray方法,然后再一个一个的remove掉
         */
        q.drainTo(taskList);
        if (!q.isEmpty()) {
            for (Runnable r : q.toArray(new Runnable[0])) {
                if (q.remove(r))
                    taskList.add(r);
            }
        }
        return taskList;
    }

原文出处 : Java线程池ThreadPoolExecutor实现原理剖析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值