ThreadPoolExecutor源码分析

应用

Executor e= new ThreadPoolExecutor(3, 5, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(20));
e.execute(new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				
			}
		});

参数说明

this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler);
corePoolSize:核心线程数
maximumPoolSize:最大线程数
keepAliveTime:保持时间
unit:单位
workQueue:工作队列
Executors.defaultThreadFactory():线程工厂
defaultHandler:拒绝策略

怎么达到复用线程的功能?
keepAliveTime参数的作用?

源码分析:主要是分析execute(Runnable command)
线程池的几种状态
RUNNING
SHUTDOWN
STOP
TIDYING
TERMINATED
ctl.get() ctl:32位 前三位表示状态 后29位表示现在正在运行的线程数量

源码分析

主程序分三种情况:
一、workerCountOf© < corePoolSize 表示工作线程数量小于核心线程数
执行addWorker(command, true)
二、线程池是否在运行状态并且能加入到队列中(workerCountOf© >= corePoolSize)这边说明只要大于核心线程数就会放入到队列中,然后从队列中获取任务
1、如果线程池不是运行状态且能去除任务 走拒绝策略
2、如果现在在运行的task为0 的话则 addWorker(null, false)
三、以上情况都不符合 会尝试下添加一个新的任务到现有的线程中(正好运行到这边是运行的线程中有线程运行结束让出了资源)addWorker(command, false)

addWorker第二个参数表示数量和核心数比较还是最大数比较

核心方法:addWorker(Runnable firstTask, boolean core)

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;

向下走的条件:如果现在的状态小于SHUTDOWN(为RUNNING)或者等于SHUTDOWN且添加的task为空且队列不为空的情况(等于没有添加任务的状态,但是这种情况子啊主线程已经判断了,这是一种预防的把 正好在addWorker时 线程被设置为null了)

for (;;) {
    int wc = workerCountOf(c);
    if (wc >= CAPACITY ||
        wc >= (core ? corePoolSize : maximumPoolSize))
        return false;
    if (compareAndIncrementWorkerCount(c))
        break retry;
    c = ctl.get();  // Re-read ctl
    if (runStateOf(c) != rs)
        continue retry;
    // else CAS failed due to workerCount change; retry inner loop
}

如果正在工作的线程大于最大线程数(1 << 29) - 1(不是Integer.MAX_VALUE) 直接返回false 或者 传进来的额第二个参数 true的话表示和核心线程数比较 false的话和最大线程数比较 如果工作线程大于的话则返回false
工作队列添加1 如果成功直接退出大循环 如果添加失败 状态还发生改变则重新循环大循环
说明:除了直接返回false的情况,在状态没有发生变化的时候在不停的尝试对workcount+1

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 {
            // Recheck while holding lock.
            // Back out on ThreadFactory failure or if
            // shut down before lock acquired.
            int rs = runStateOf(ctl.get());

            if (rs < SHUTDOWN ||
                (rs == SHUTDOWN && firstTask == null)) {
                if (t.isAlive()) // precheck that t is startable
                    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);
}

依据fristTask创建一个work对象继承AQS,这里面设置AQS的state=-1 表示等待执行状态 如果不清楚这个可以看AQS-ReentrantLock的相关文章
然后分析:

try {
    // Recheck while holding lock.
    // Back out on ThreadFactory failure or if
    // shut down before lock acquired.
    int rs = runStateOf(ctl.get());

    if (rs < SHUTDOWN ||
        (rs == SHUTDOWN && firstTask == null)) {
        if (t.isAlive()) // precheck that t is startable
            throw new IllegalThreadStateException();
        workers.add(w);
        int s = workers.size();
        if (s > largestPoolSize)
            largestPoolSize = s;
        workerAdded = true;
    }
} finally {
    mainLock.unlock();
}

这个保证了每次创建出来的work对象是新的,且线程是没有启动的(后面会进行启动),这样就可以保证线程启动的次数为有限的 将work放到一个set中

if (workerAdded) {
    t.start();
    workerStarted = true;
}

这边启动线程 t.start()–>java.util.concurrent.ThreadPoolExecutor.Worker.run()–>java.util.concurrent.ThreadPoolExecutor.runWorker(Worker)

核心方法:
java.util.concurrent.ThreadPoolExecutor.runWorker(Worker)

final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;
    w.unlock(); // allow interrupts
    boolean completedAbruptly = true;
    try {
        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
            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);
    }
}

经过一些异常判断后,直接执行Runable中的run方法 (这边没有执行线程的start,将Runable作为一个普通方法进行执行)
w.unlock()?

private Runnable getTask() {
    boolean timedOut = false; // Did the last poll() time out?

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

        // Check if queue empty only if necessary.
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            decrementWorkerCount();
            return null;
        }

        int wc = workerCountOf(c);

        // Are workers subject to culling?
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

        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;
            timedOut = true;
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}

下面的方法表示只有stat>=STOP或者rs=SHUTDOWN且workQueue为空
rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())

java.util.concurrent.ThreadPoolExecutor.allowCoreThreadTimeOut(boolean)设置参数allowCoreThreadTimeOut
首先默认为false
下面的表示 take在没有数据的时候会永远的阻塞在那边 poll的话会在一定时间内返回
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :workQueue.take()

直接从队列头返回一个任务
java.util.concurrent.ThreadPoolExecutor.getTask()

详细源码的分析说明

首先判断任务不能为空

if (command == null)
            throw new NullPointerException();

公共方法说明:
1、获取 ctl

 int c = ctl.get();

2、获取worker的数量 这个是取ctl的后29位

workerCountOf(c)

3、获取线程池状态

runStateOf(c)

线程数(workcount)<corepoolnum
一开始的时候ctl=RUNNING

//workcount<corePoolSize
 if (workerCountOf(c) < corePoolSize) {
     //新增worker
    if (addWorker(command, true))
        return;
    //如果新增失败则在获取下workcount(防止多线程的情况?)    
    c = ctl.get();
}

下面开始分析addWorker 传入的参数为command !=null和true 返回为true的话表示新增成功,false表示失败
1、第一段主要是对一些异常进行判断后对workcount进行加一

for (;;) {
    //获取ctl
    int c = ctl.get();
    //获取线程池状态
    int rs = runStateOf(c);
    
    // Check if queue empty only if necessary.
    //一开始的时候是running状态这个条件走不通 
    //firstTask!=null只有rs的状态为SHUTDOWN STOP TIDYING TERMINATED 这个条件才成立
    if (rs >= SHUTDOWN &&
        ! (rs == SHUTDOWN &&
           firstTask == null &&
           ! workQueue.isEmpty()))
        return false;

    for (;;) {
        //获取worker的数量  一开始为0
        int wc = workerCountOf(c);
        //1、这边判断数量是否大于最大数量 2^29-1  
        //依据传进来的参数进行判断addWorker(Runnable firstTask, boolean core)第二个参数为true的话和核心数比较,如果为false的话和最大数比较
        //这次为执行的话为false
        if (wc >= CAPACITY ||
            wc >= (core ? corePoolSize : maximumPoolSize))
            return false;
        //对workcount进行加一 使用了CAS    
        if (compareAndIncrementWorkerCount(c))
            break retry;
        c = ctl.get();  // Re-read ctl
        //如果发现状态发生变化则从最上面的循环重新执行
        if (runStateOf(c) != rs)
            continue retry;
        // else CAS failed due to workerCount change; retry inner loop
    }
}

2、第二段主要是新建一个worker然后执行启动的线程

//是否启动worker
boolean workerStarted = false;
//worker是否添加成功
boolean workerAdded = false;
Worker w = null;
try {
    //新增一个worker worker的代码在下面
    w = new Worker(firstTask);
    final Thread t = w.thread;
    //这个一般不会为null
    if (t != null) {
        //全局的非公平锁
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            // Recheck while holding lock.
            // Back out on ThreadFactory failure or if
            // shut down before lock acquired.
            //获取线程池状态
            int rs = runStateOf(ctl.get());
            //排除异常:一、如果rs为RUNNING状态且线程已启动 二、rs为SHUTDOWN状态且传进来的command为null且线程已启动
            if (rs < SHUTDOWN ||
                (rs == SHUTDOWN && firstTask == null)) {
                if (t.isAlive()) // precheck that t is startable
                    throw new IllegalThreadStateException();
                //排除异常情况下 向一个HashSet中添加worker  这个Hashset目前知道只是向对外提供下我们正在运行的worker的count    
                workers.add(w);
                int s = workers.size();
                //这个表示曾经最大的workerSet
                if (s > largestPoolSize)
                    largestPoolSize = s;
                workerAdded = true;
            }
        } finally {
            mainLock.unlock();
        }
        if (workerAdded) {
            //核心代码 执行线程
            t.start();
            workerStarted = true;
        }
    }
} finally {
    if (! workerStarted)
        addWorkerFailed(w);
}

这个主要是新建worker

//继承AQS
Worker(Runnable firstTask) {
    //设置state为-1表示随时可以进行获取运行权利
    setState(-1); // inhibit interrupts until runWorker
    this.firstTask = firstTask;
    //通过工厂新建一个线程  这边也设置了线程的名称  这边可以自己重写 直接复制java.util.concurrent.Executors.DefaultThreadFactory的代码后添加线程池的名称(有必要这个可以帮助后期问题的排查)
    //由于这边是将this传入到newThread方法中如果执行t.start()时就是执行的Worker这个方法的run方法
     this.thread = getThreadFactory().newThread(this);
}

看一下getThreadFactory().newThread的方法 为java.util.concurrent.Executors.DefaultThreadFactory这个方法
这个方法很简单 就是新建一个Thread,没什么可以分析 但是建议可以重新这个方法至少可以自己定义ThreadName

static class DefaultThreadFactory implements ThreadFactory {
    private static final AtomicInteger poolNumber = new AtomicInteger(1);
    private final ThreadGroup group;
    private final AtomicInteger threadNumber = new AtomicInteger(1);
    private final String namePrefix;

    DefaultThreadFactory() {
        SecurityManager s = System.getSecurityManager();
        group = (s != null) ? s.getThreadGroup() :
                              Thread.currentThread().getThreadGroup();
        namePrefix = "pool-" +
                      poolNumber.getAndIncrement() +
                     "-thread-";
    }

    public Thread newThread(Runnable r) {
        Thread t = new Thread(group, r,
                              namePrefix + threadNumber.getAndIncrement(),
                              0);
        if (t.isDaemon())
            t.setDaemon(false);
        if (t.getPriority() != Thread.NORM_PRIORITY)
            t.setPriority(Thread.NORM_PRIORITY);
        return t;
    }
}

下面要开始分析t.start()方法,这个方法对应的java.util.concurrent.ThreadPoolExecutor.Worker.run()也就是对应的java.util.concurrent.ThreadPoolExecutor.runWorker(Worker)

final void runWorker(Worker w) {
    //获取当前线程
    Thread wt = Thread.currentThread();
    //表示我们传进去的command
    Runnable task = w.firstTask;
    w.firstTask = null;
    //防止多线程?
    w.unlock(); // allow interrupts
    boolean completedAbruptly = true;
    try {
        //如果传进去的command不为空 或者可以从队列中获取到任务
        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
            //这个判断表示 如果线程池属于停止状态的话我们需要中断这个线程 也就是不接受任何新的任务进来
            if ((runStateAtLeast(ctl.get(), STOP) ||
                 (Thread.interrupted() &&
                  runStateAtLeast(ctl.get(), STOP))) &&
                !wt.isInterrupted())
                wt.interrupt();
            try {
                //这是一个空方法可以自己实现 在线程运行前做些事 相当于切面
                beforeExecute(wt, task);
                Throwable thrown = null;
                try {
                    //这边是将runable方法当作一个普通方法运行run方法,而不是new Thread(task) 这样的话就可以实现线程池创建线程的复用(只有前面getThreadFactory().newThread(this)创建了线程)
                    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);
    }
}

下面来分析下task = getTask()

private Runnable getTask() {
    boolean timedOut = false; // Did the last poll() time out?

    for (;;) {
        int c = ctl.get();
        //获取线程池状态
        int rs = runStateOf(c);

        // Check if queue empty only if necessary.
        //只有线程池状态为STOP及以上或者为SHUTDOWN且队列为空的时候才成立
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            //将ctl中的workcount数量减一
            decrementWorkerCount();
            return null;
        }
        //woker的数量
        int wc = workerCountOf(c);

        // Are workers subject to culling?
        //allowCoreThreadTimeOut可以进行设置  如果allowCoreThreadTimeOut为true 这个一般不会设置 判断后面的workcount是否大于核心线程数
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
        //一、如果workcount大于最大线程数或者workcount大于核心数且超时了 
        //二、线程数大于1或者队列中为空
        //keepAliveTime的体现在这边!!!表示如果线程数大于了最大线程数 或者workcount大于核心数然后一直获取队列中任务超时 这边就会返回null
        if ((wc > maximumPoolSize || (timed && timedOut))
            && (wc > 1 || workQueue.isEmpty())) {
            //如果能workcount减一的话就返回null    
            if (compareAndDecrementWorkerCount(c))
                return null;
            continue;
        }

        try {
            //这个表示 一般不会设置allowCoreThreadTimeOut 则线程数小于核心数的时候我们直接和阻塞式获取队列任务,如果大于核心数了进行超时获取如果获取失败则按照上面的判断会返回null
            Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                workQueue.take();
            if (r != null)
                return r;
            timedOut = true;
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}

下面来分析下processWorkerExit(w, completedAbruptly)

private void processWorkerExit(Worker w, boolean completedAbruptly) {
    //completedAbruptly为true表示前面的runWorker出现了异常
    if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
        decrementWorkerCount();

    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        //设置参数
        completedTaskCount += w.completedTasks;
        workers.remove(w);
    } finally {
        mainLock.unlock();
    }
    //主要是执行完线程池方法后的钩子方法,只有最后队列中没有数据了才会执行terminated()方法
    tryTerminate();

    int c = ctl.get();
    //如果状态小于STOP 就是为RUNNING
    if (runStateLessThan(c, STOP)) {
        //正常结束的
        if (!completedAbruptly) {
            int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
            if (min == 0 && ! workQueue.isEmpty())
                min = 1;
            //如果workcount大于等于核心数的话就返回    
            if (workerCountOf(c) >= min)
                return; // replacement not needed
        }
        //表示会从队列中获取任务 且运行的线程数没有大于最大线程数的数会新建worker
        addWorker(null, false);
    }
}

到此我们对第一种情况分析结束
总结下:
首先workcount加一,然后依据条件是否需要新建worker
新建好了worker就会进行runwork操作
runwork主要是判断传进来的任务或者队列中是否有任务来进行任务的执行
这边解决了为什么线程的效率比一般线程高的原因:线程的创建和启动一个worker只有一次 还说明了keepalive的作用是在没有设置allowCoreThreadTimeOut的情况下 当worker数量大于核心数是从队列中获取任务的最大超时时间 如果设置allowCoreThreadTimeOut为true的话 核心线程取任务的时候也有超时

后面几种情况 统一分析

//运行到这边表示worker的数量大于核心线程数
//判断线程池状态是否为RUNNING 且能队列中加任务能成功
if (isRunning(c) && workQueue.offer(command)) {
    //双重判断
    int recheck = ctl.get();
    //如果线程池状态不为RUNNING 就从队列中去除任务 且执行钩子方法 如果都成立则执行拒绝策略
    if (! isRunning(recheck) && remove(command))
        reject(command);
     //上述条件不成立的话就判断下是否为RUNNING状态   
    else if (workerCountOf(recheck) == 0)
        //表示在运行的线程数没有大于最大线程数的数会新建worker 并从队列中获取任务执行
        addWorker(null, false);
}
//addWorker(command, false)表示在运行的线程数没有大于最大线程数的数会新建worker 并执行现在的任务后在从队列中获取任务
//这个条件成立 只有线程数大于最大线程数
else if (!addWorker(command, false))
    reject(command);

欢迎大家多多评价和参与讨论~~ 还有一个问题没想明白w.unlock()为什么runWorker进去就执行解锁操作?希望了解的大神能指点一二。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值