Java线程池之ThreadPoolExecutor线程池源码解析

目录

0、引言

0.1任务队列: LinkedBlockingQueue 没有设置固定容量大小

0.2最大线程数量是: Integer.MAX_VALUE

0.3拒绝策略:不能自定义

1、ThreadPoolExecutor

1.1基本架构

1.2提交方法源码解析

1.3线程的管理解析


0、引言

为甚麽线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式?

0.1任务队列: LinkedBlockingQueue 没有设置固定容量大小

//例如
public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

newFixedThreadPool()、newSingleThreadExecutor() 底层代码 中 LinkedBlockingQueue 没有设置容量大小,默认是 Integer.MAX_VALUE, 可以认为是无界的。线程池中 多余的线程会被缓存到 LinkedBlockingQueue中,最终内存撑爆。

0.2最大线程数量是: Integer.MAX_VALUE

//例如
public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

newCachedThreadPool()、newScheduledThreadPool() 的 底层代码 中 的 最大线程数(maximumPoolSize) 是 Integer.MAX_VALUE,可以认为是无限大,如果线程池中,执行中的线程没有及时结束,并且不断地有线程加入并执行,最终会将内存撑爆。

0.3拒绝策略:不能自定义

//Executors 底层其实是使用的 ThreadPoolExecutor 的方式 创建的,但是使用的是 ThreadPoolExecutor 的默认策略
//默认策略
 private static final RejectedExecutionHandler defaultHandler =
        new AbortPolicy();
//构造函数
public ThreadPoolExecutor(int corePoolSize,
                             int maximumPoolSize,
                             long keepAliveTime,
                             TimeUnit unit,
                             BlockingQueue<Runnable> workQueue) {
	this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
            Executors.defaultThreadFactory(), defaultHandler);
}

 


1、ThreadPoolExecutor


1.1基本架构

  • ThreadPoolExecutor(类)-AbstractExecutorService(抽象类)-ExecutorService(接口)-Executor(接口)
  • Executor 定义 execute 方法来执行任务,入参是 Runnable
public interface Executor {
    void execute(Runnable command);
}
  • ExecutorService 丰富了对任务的执行和管理的功能
// 关闭,不会接受新的任务,也不会等待未完成的任务
void shutdown();
// executor 是否已经关闭了,返回值 true 表示已关闭
boolean isShutdown();
// 所有的任务是否都已经终止,是的话,返回 true
boolean isTerminated();
// 在超时时间内,等待剩余的任务终止
boolean awaitTermination(long timeout, TimeUnit unit)
    throws InterruptedException;
// 提交有返回值的任务,使用 get 方法可以阻塞等待任务的执行结果返回
<T> Future<T> submit(Callable<T> task);
// 提交没有返回值的任务,如果使用 get 方法的话,任务执行完之后得到的是 null 值
Future<?> submit(Runnable task);
// 给定任务集合,返回已经执行完成的 Future 集合,每个返回的 Future 都是 isDone = true 的状态
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
    throws InterruptedException;
// 给定任务中有一个执行成功就返回,如果抛异常,其余未完成的任务将被取消
<T> T invokeAny(Collection<? extends Callable<T>> tasks)
    throws InterruptedException, ExecutionException;
  • AbstractExecutorService 是一个抽象类,封装了 Executor 的很多通用功能
// 把 Runnable 转化成 RunnableFuture
// RunnableFuture 是一个接口,继承了 Runnable 和 Future
// FutureTask 是 RunnableFuture 的实现类,主要是对任务进行各种管理
// Runnable + Future => RunnableFuture => FutureTask
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
    return new FutureTask<T>(runnable, value);
}
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
    return new FutureTask<T>(callable);
}
// submit也是我们平时线程池提交任务的方法
// 提交无返回值的任务
public Future<?> submit(Runnable task) {
    if (task == null) throw new NullPointerException();
    // ftask 其实是 FutureTask
    RunnableFuture<Void> ftask = newTaskFor(task, null);
    execute(ftask);// 子类ThreadPoolExecutor实现的
    return ftask;
}
// 提交有返回值的任务
public <T> Future<T> submit(Callable<T> task) {
    if (task == null) throw new NullPointerException();
    // ftask 其实是 FutureTask
    RunnableFuture<T> ftask = newTaskFor(task);
    execute(ftask);// 子类ThreadPoolExecutor实现的
    return ftask;
}
// 任务转化为FutureTask
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
    return new FutureTask<T>(runnable, value);
}

1.2提交方法源码解析

  • 提交 Runnable 和 Callable 任务并且都转化成 FutureTask(是实际的任务类型);
  • 使用父类的submit方法进行实际的流程,返回Future任务;
  • 使用 execute 方法是线程池的主流程;
public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    int c = ctl.get();
    // 1.工作的线程小于核心线程数,创建新的线程,成功返回,失败不抛异常
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        // 线程池状态可能发生变化
        c = ctl.get();
    }
    // 2.线程池状态正常,并且可以入队的话,尝试入队列
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        // 如果线程池状态异常 尝试从队列中移除任务,可以移除的话就拒绝掉任务
        if (!isRunning(recheck) && remove(command))
            reject(command);
        // 发现可运行的线程数是 0,就初始化一个线程,这里是个极限情况,入队的时候,突然发现
        // 可用线程都被回收了
        else if (workerCountOf(recheck) == 0)
            // Runnable是空的,不会影响新增线程,但是线程在 start 的时候不会运行
            // Thread.run() 里面有判断
            addWorker(null, false);
    }
    // 3.队列满了,开启线程到 maxSize,4.如果失败进行拒绝策略,
    else if (!addWorker(command, false))
        reject(command);
}
  • execute里面多次调用了addWork方法,
// 结合线程池的情况看是否可以添加新的 worker
// firstTask 不为空可以直接执行,为空执行不了,Thread.run()方法有判断,Runnable为空不执行
// core 为 true 表示线程最大新增个数是 coresize,false 表示最大新增个数是 maxsize
// 返回 true 代表成功,false 失败
// break retry 跳到retry处,且不再进入循环
// continue retry 跳到retry处,且再次进入循环
private boolean addWorker(Runnable firstTask, boolean core) {
    retry:
    // 先是各种状态的校验
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);
        // Check if queue empty only if necessary.
        // rs >= SHUTDOWN 说明线程池状态不正常
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&
               firstTask == null &&
               ! workQueue.isEmpty()))
            return false;

        for (;;) {
            int wc = workerCountOf(c);
            // 工作中的线程数大于等于容量,或者大于等于 coreSize or maxSize
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
            if (compareAndIncrementWorkerCount(c))
                // break 结束 retry 的 for 循环
                break retry;
            c = ctl.get();  // Re-read ctl
            // 线程池状态被更改
            if (runStateOf(c) != rs)
                // 跳转到retry位置
                continue retry;
        }
    }
    //开始进行进行创建work并且start执行
    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;
    try {
        // 巧妙的设计,Worker 本身是个 Runnable.
        // 在初始化的过程中,会把 worker 丢给 thread 去初始化
        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) {
                // 启动线程,实际上去执行 Worker.run 方法
                t.start();
                workerStarted = true;
            }
        }
    } finally {
        if (! workerStarted)
            addWorkerFailed(w);
    }
    return workerStarted;
}

首选进行了各种条件的验证,然后将任务加入,并且通过Worker类获取对应任务的线程,并且启动线程start

  • addWork方法里创建了Work类,并且进行执行线程start
// 线程池中任务执行的最小单元
// Worker 继承 AQS,具有锁功能
// Worker 实现 Runnable接口,run方法对应外部的runWorker方法,所有本身是一个可执行的任务
private final class Worker
    extends AbstractQueuedSynchronizer
    implements Runnable 
{
    // 任务运行的线程
    final Thread thread;
    // 需要执行的任务
    Runnable firstTask;
    // 非常巧妙的设计,Worker本身是个 Runnable,把自己作为任务传递给 thread
    // 初始化线程
    Worker(Runnable firstTask) {
        setState(-1); // inhibit interrupts until runWorker
        this.firstTask = firstTask;
        // 把 Worker 自己作为 thread 运行的任务
        this.thread = getThreadFactory().newThread(this);
    }
    public void run() {
        runWorker(this);// 外部方法,Worker是内部类,ThreadPoolExecutor是类
    }
    private static final long serialVersionUID = 6138294804551838833L;
    // Lock methods
    // 0 代表没有锁住,1 代表锁住
    protected boolean isHeldExclusively() {
        return getState() != 0;
    }
    // 尝试加锁,CAS 赋值为 1,表示锁住
    protected boolean tryAcquire(int unused) {
        if (compareAndSetState(0, 1)) {
            setExclusiveOwnerThread(Thread.currentThread());
            return true;
        }
        return false;
    }
    // 尝试释放锁,释放锁没有 CAS 校验,可以任意的释放锁
    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) {
            }
        }
    }
}
  • run方法里又调用了runWorker方法
final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    //帮助gc回收
    w.firstTask = null;
    w.unlock(); // allow interrupts
    boolean completedAbruptly = true;
    try {
        // 就是,在这里进行线程的具体管理,而不是实际消亡
        // task 为空的情况:
        // 1:任务入队列了,极限情况下,发现没有运行的线程,于是新增一个线程;
        // 2:线程执行完任务执行,再次回到 while 循环。
        // 如果 task 为空,会使用 getTask 方法阻塞从队列中拿数据,如果拿不到数据,会阻塞住
        while (task != null || (task = getTask()) != null) {
            //锁住 worker
            w.lock();
            // 线程池 stop 中,但是线程没有到达中断状态,帮助线程中断
            if ((runStateAtLeast(ctl.get(), STOP) ||
                 (Thread.interrupted() &&
                  runStateAtLeast(ctl.get(), STOP))) &&
                !wt.isInterrupted())
                wt.interrupt();
            try {
                //执行 before 钩子函数
                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 {
                    //执行 after 钩子函数,如果这里抛出异常,会覆盖 catch 的异常
                    //所以这里异常最好不要抛出来
                    afterExecute(task, thrown);
                }
            } finally {
                //任务执行完成,计算解锁
                task = null;
                w.completedTasks++;
                w.unlock();
            }
        }
        completedAbruptly = false;
    } finally {
        //做一些抛出异常的善后工作
        processWorkerExit(w, completedAbruptly);
    }
}

runWorker,主要就是使用当前线程执行任务的run方法,并且配有执行前和执行后的钩子函数处理!

  • runWorker里调用了run方法
public void run() {
    // 状态不是任务创建,或者当前任务已经有线程在执行了
    if (state != NEW ||
        !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                     null, Thread.currentThread()))
        return;
    try {
        Callable<V> c = callable;
        // Callable 不为空,并且已经初始化完成
        if (c != null && state == NEW) {
            V result;
            boolean ran;
            try {
                // 调用执行
                result = c.call();
                ran = true;
            } catch (Throwable ex) {
                result = null;
                ran = false;
                setException(ex);
            }
            // 给 outcome 赋值
            if (ran)
                set(result);
        }
    } finally {
        runner = null;
        int s = state;
        if (s >= INTERRUPTING)
            handlePossibleCancellationInterrupt(s);
    }
}

run方法里实际是执行FutureTask任务的call方法并且把返回值进行赋值

  • 整体流程:

@ThreadPoolExecute执行上层抽象类的submit方法,@submit里先将任务封装成FutureTask任务,在执行execute方法

@execute方法里实际又新创建一个Worker类(继承AQS,并且实现了Runnable接口)封装任务然后进行addWorker加入

@addWorker里先进行了状态验证,然后加入任务,在获取到Worker类对应的线程并且start启动,创建线程执行run方法

@Worker类里的run方法,调用了runWorker方法,该方法调用FutureTask任务的run方法并加入了执行前/后进行处理

@FutuerTask任务的run实际是调用任务的call方法并且将返回值进行设置

1.3线程的管理解析

  • 实际入口在runWorker函数里面的getTask方法里
....
while (task != null || (task = getTask()) != null) {
            //锁住 worker
            w.lock();
....
// 从阻塞队列中拿任务
private Runnable getTask() {
    boolean timedOut = false;
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);
        //线程池关闭 && 队列为空,不需要在运行了,直接放回
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            decrementWorkerCount();
            return null;
        }
        // 释放线程
        int wc = workerCountOf(c);
        // true  运行的线程数大于 coreSize || 核心线程也可以被灭亡
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
        // 队列以 LinkedBlockingQueue 为例,timedOut 为 true 的话说明下面 poll 方法执行返回的是 null
        // 说明在等待 keepAliveTime 时间后,队列中仍然没有数据
        // 再加上 wc > 1 || workQueue.isEmpty() 的判断,说明此线程已经空闲了 keepAliveTime 了
        // 所以使用 compareAndDecrementWorkerCount 方法使线程池数量减少 1
        // 并且直接 return,return 之后,此空闲的线程会自动被回收
        if ((wc > maximumPoolSize || (timed && timedOut))
            && (wc > 1 || workQueue.isEmpty())) {
            if (compareAndDecrementWorkerCount(c))
                return null;
            continue;
        }
        // 线程获取任务
        try {
            // 从队列中阻塞拿 worker
            Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                workQueue.take();
            if (r != null)
                return r;
            // 设置已超时,说明此时队列没有数据
            timedOut = true;
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}

无限循环,管理线程的消亡和任务的获取(可以通过无限阻塞的take,也可以使用设置超时的poll)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值