ThreadPoolExcute运行原理(源码学习)

一、ThreadPoolExcute类主要变量

shutdownPerm:权限检查使用

runState:运行状态,对应有RUNNING 0、SHUTDOWN 1、STOP 2、TERMINATED 3

BlockingQueue<Runnable> workQueue :任务队列

ReentrantLock mainLock:可重入锁

Condition termination=mainLock.newCondition() : 可重入锁变更条件

HashSet<Worker> workers:Runnable封装类,执行线程的池

volatile long  keepAliveTime:线程存活时间

volatile boolean allowCoreThreadTimeOut:线程失败或者终止后能否使用keepAliveTime时间等待

volatile int   corePoolSize;核心线程数量

volatile int   maximumPoolSize;最大线程数量

volatile int   poolSize;当前的线程数量

volatile RejectedExecutionHandler handler;拒绝执行Runnable后的处理器

volatile ThreadFactory threadFactory;线程工厂

RejectedExecutionHandler defaultHandler = new AbortPolicy();默认的失败处理策略

二、workQueue 和workers

1、workQueue 任务队列

①workQueue缓存没有被立即执行的Runnable,当新加入的任务大于corePoolSize又小于maximumPoolSize时,执行workQueue.offer(command),源码如下

    /**
     * Executes the given task sometime in the future.  The task
     * may execute in a new thread or in an existing pooled thread.
     *
     * If the task cannot be submitted for execution, either because this
     * executor has been shutdown or because its capacity has been reached,
     * the task is handled by the current <tt>RejectedExecutionHandler</tt>.
     *
     * @param command the task to execute
     * @throws RejectedExecutionException at discretion of
     * <tt>RejectedExecutionHandler</tt>, if task cannot be accepted
     * for execution
     * @throws NullPointerException if command is null
     */
    public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
		//如果当前线程大于核心线程或者加入works集合不成功,在这里已经执行了一次addIfUnderCorePoolSize加入works集合               
	     if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {
		if (runState == RUNNING && workQueue.offer(command)) {
                   if (runState != RUNNING || poolSize == 0)
                      ensureQueuedTaskHandled(command);//确保队列任务正确插入
                }
                else if (!addIfUnderMaximumPoolSize(command))
                     reject(command); // is shutdown or saturated
             }       
    }


②addIfUnderCorePoolSize方法,当前线程小于corePoolSize并且运行状态为running,则addThread返回Thread对象t,执行start

    private boolean addIfUnderCorePoolSize(Runnable firstTask) {
        Thread t = null;
        final ReentrantLock mainLock = this.mainLock;//在任务调度过程中用可重入锁mainlock进行并发控制
        mainLock.lock();
        try {
            if (poolSize < corePoolSize && runState == RUNNING)
                t = addThread(firstTask);
        } finally {
            mainLock.unlock();
        }
        if (t == null)
            return false;
        t.start();
        return true;
    }

③ensureQueuedTaskHandled方法,如果运行状态不是Running而且workQueue.remove(command)成功,转入异常处理;如果状态中stop之前且线程数小于核心线程数且workQueue队列不为空,则addThread返回Thread对象t,执行start

private void ensureQueuedTaskHandled(Runnable command) {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        boolean reject = false;
        Thread t = null;
        try {
            int state = runState;
            if (state != RUNNING && workQueue.remove(command))
                reject = true;
            else if (state < STOP &&
                     poolSize < Math.max(corePoolSize, 1) &&
                     !workQueue.isEmpty())
                t = addThread(null);
        } finally {
            mainLock.unlock();
        }
        if (reject)
            reject(command);
        else if (t != null)
            t.start();
    }

2、workers,workers是Runnable的一个封装类Worker的集合,实现了Runnable接口,workers真正的线程池核心实现,它是一个HashSet集合,保存当前正在执行和等待执行的任务。

①ReentrantLock

<span style="white-space:pre">	</span>/**
         * The runLock is acquired and released surrounding each task
         * execution. It mainly protects against interrupts that are
         * intended to cancel the worker thread from instead
         * interrupting the task being run.
         */
        private final ReentrantLock runLock = new ReentrantLock();
我们看到有个runlock可重入锁定义,runlock用在中断方法interruptIfIdle以及执行任务的核心方法runtask中控制并发

②Thread thread

源码中定义了一个thread对象用来执行中断thread.interrupt()以及执行shutdown时权限检查for (Worker w : workers)security.checkAccess(w.thread);

既然Thread这么重要,那Thread对象哪里来的?我们看源码addThread方法

    /**
     * Creates and returns a new thread running firstTask as its first
     * task. Call only while holding mainLock.
     *
     * @param firstTask the task the new thread should run first (or
     * null if none)
     * @return the new thread, or null if threadFactory fails to create thread
     */
    private Thread addThread(Runnable firstTask) {
        Worker w = new Worker(firstTask);
        Thread t = threadFactory.newThread(w);
        if (t != null) {
            w.thread = t;
            workers.add(w);
            int nt = ++poolSize;
            if (nt > largestPoolSize)
                largestPoolSize = nt;
        }
        return t;
    }
其实这个Thread就是Worker的一个封装,一个装饰,Thread内部是一个Worker!所以他可以做到很多事情比如中断、权限检查等

③worker和workQueue 是怎么联系在一起的?我们看源码

 <span style="white-space:pre">	</span>/**
         * Main run loop
         */
        public void run() {
            try {
                Runnable task = firstTask;
                firstTask = null;
                while (task != null || (task = getTask()) != null) {
                    runTask(task);
                    task = null;
                }
            } finally {
                workerDone(this);
            }
        }
work执行这个run方法时候,使用getTask方法获得任务,再看getTask

    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)
                    r = workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS);
                else
                    r = workQueue.take();
                if (r != null)
                    return r;
                if (workerCanExit()) {
                    if (runState >= SHUTDOWN) // Wake up others
                        interruptIdleWorkers();
                    return null;
                }
                // Else retry
            } catch (InterruptedException ie) {
                // On interruption, re-check runState
            }
        }
    }

我们看到work的任务,是从workQueue中取出来的。


三、总结

我们最后整理一下思路,我们说worker是实现池的关键,为什么?

①worker中run方法定义

try {
                Runnable task = firstTask;
                firstTask = null;
                while (task != null || (task = getTask()) != null) {
                    runTask(task);
                    task = null;
                }
            } finally {
                workerDone(this);
            }
      关键有两个地方,while方法,只要getTask还有任务,,一直循环运行;如果没有任务了,workerDone,执行结束,然后调用workers.remove(w)把自己干掉,整个Worker就算完成任务。

      ②而getTask又是一个for循环,不断取任务,如果没有取到就一直循环下去,除非workerCanExit()判断,发现可以结束了,则返回null,整个过程结束。


      所谓的池,就是用完后不抛弃,放回去,接着有人再用;

      正是因为Work是一个执行Runnable的Runnable,而且有一个自旋锁While以及getTask里的for循环,再加上corePoolSize、poolSize、maximumPoolSize、等这些变量维持和调节池的正常大小,实现了这个线程池!

----------------------------------------------------------------------------------------------------------------------------------------------------------------------


补充:今天再回头研究ThreadPoolExcute时,阅读runTask方法,其调用getTask时,实际调用的是接口Queue的take方法,take方法是一个阻塞方法。在此备注一下:

take: 有则返回,删除底部元素,没有则阻塞除非中断

poll:有则返回,删除底部元素,没有则返回空,不阻塞

peek:有责返回,没有则返回空,但是不删除元素

remove:有责返回,并且删除元素,没有则报错



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值