Java线程池详解

参考文章

Java线程池实现原理及其在美团业务中的实践-美团

线程池优势

  • 降低资源消耗,复用已有线程
  • 控制并发数量
  • 提高响应速度,复用已有线程
  • 方便管理

总体设计

  • 采用生产者-消费者模型将任务和线程解藕,采用阻塞队列缓冲任务
  • Executor框架完成线程的调配和任务的执行部分
  • ExecutorService接口增加了一些能力:(1)扩充执行任务的能力,补充可以为一个或一批异步任务生成Future的方法;(2)提供了管控线程池的方法,比如停止线程池的运行。
  • AbstractExecutorService则是上层的抽象类,将执行任务的流程串联了起来,保证下层的实现只需关注一个执行任务的方法即可。最下层的实现类ThreadPoolExecutor实现最复杂的运行部分,ThreadPoolExecutor将会一方面维护自身的生命周期,另一方面同时管理线程和任务,使两者良好的结合从而执行并行任务
    在这里插入图片描述

源码解析

相关资源控制

线程池相关信息管理

// 高3位存储线程池的运行状态,低29位保存线程数量
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

private static int runStateOf(int c)     { return c & ~CAPACITY; } //计算当前运行状态
private static int workerCountOf(int c)  { return c & CAPACITY; }  //计算当前线程数量
private static int ctlOf(int rs, int wc) { return rs | wc; }   //通过状态和线程数生成ctl

ThreadPoolExecutor的5种运行状态

在这里插入图片描述
ThreadPoolExecutor的生命周期转换
在这里插入图片描述

阻塞队列

  • 两个附加的操作是:
    • 在队列为空时,获取元素的线程会等待队列变为非空,从而获取元素
    • 当队列满时,存储元素的线程会等待队列可用,从而存储元素
      在这里插入图片描述

拒绝策略

在这里插入图片描述

线程创建执行任务或线程在任务队列取任务执行

  • submit -> execute -> addWorker -> runWorker -> getTask
    在这里插入图片描述
    在这里插入图片描述

submit函数

execute方法

在这里插入图片描述

public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    // clt记录着runState和workerCount
    int c = ctl.get();
    //workerCountOf方法取出低29位的值,表示当前活动的线程数
    //然后拿线程数和 核心线程数做比较
    if (workerCountOf(c) < corePoolSize) {
        // 如果活动线程数<核心线程数
        // addWorker中的第二个参数表示限制添加线程的数量是根据corePoolSize来判断还是maximumPoolSize来判断
        if (addWorker(command, true))
            // 如果成功则返回
            return;
        // 如果失败则重新获取 runState和 workerCount
        c = ctl.get();
    }
    // 如果当前线程池是运行状态并且任务添加到队列成功
    if (isRunning(c) && workQueue.offer(command)) {
        // 重新获取 runState和 workerCount
        int recheck = ctl.get();
        // 如果不是运行状态并且
        if (! isRunning(recheck) && remove(command))
            reject(command);
        else if (workerCountOf(recheck) == 0)
            //第一个参数为null,表示在线程池中创建一个线程,但不去启动
            // 第二个参数为false,将线程池的有限线程数量的上限设置为maximumPoolSize
            addWorker(null, false);
    }
    //再次调用addWorker方法,但第二个参数传入为false,将线程池的有限线程数量的上限设置为maximumPoolSize
    else if (!addWorker(command, false))
        //如果失败则拒绝该任务
        reject(command);
}

addWorker方法

private boolean addWorker(Runnable firstTask, boolean core) {
    retry:
    for (;;) {
        int c = ctl.get();
        //  获取运行状态
        int rs = runStateOf(c);
        // 如果状态值 >= SHUTDOWN (不接新任务&不处理队列任务)
        // 并且!(rs为SHUTDOWN 且 firsTask为空 且 阻塞队列不为空)
        // 判断是否有未完成的任务
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&
               firstTask == null &&
               ! workQueue.isEmpty()))
            // 返回false
            return false;
        for (;;) {
            //获取线程数wc
            int wc = workerCountOf(c);
            // 如果wc>容量 || core如果为true表示根据corePoolSize来比较,否则为maximumPoolSize
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
            // 自增workerCount(原子操作)
            if (compareAndIncrementWorkerCount(c))
                // 如果增加成功,则跳出
                break retry;
            // wc增加失败,则再次获取runState
            c = ctl.get();  // Re-read ctl
            // 如果当前的运行状态不等于rs,说明状态已被改变,返回重新执行
            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 {
        // 根据firstTask来创建Worker对象
        w = new Worker(firstTask);
        // 根据worker创建一个线程
        final Thread t = w.thread;
        if (t != null) {
            final ReentrantLock mainLock = this.mainLock;
            // 加锁
            mainLock.lock();
            try {
                // 获取runState
                int rs = runStateOf(ctl.get());
                // 如果rs小于SHUTDOWN(处于运行)或者(rs=SHUTDOWN && firstTask == null)
                // firstTask == null证明只新建线程而不执行任务
                if (rs < SHUTDOWN ||
                    (rs == SHUTDOWN && firstTask == null)) {
                    // 如果t活着就抛异常
                    if (t.isAlive()) // precheck that t is startable
                        throw new IllegalThreadStateException();
                    // 否则加入worker(HashSet)
                    //workers包含池中的所有工作线程。仅在持有mainLock时访问。
                    workers.add(w);
                    // 获取工作线程数量
                    int s = workers.size();
                    //largestPoolSize记录着线程池中出现过的最大线程数量
                    if (s > largestPoolSize)
                        // 如果 s比它还要大,则将s赋值给它
                        largestPoolSize = s;
                    // worker的添加工作状态改为true
                    workerAdded = true;
                }
            } finally {
                mainLock.unlock();
            }
            // 如果worker的添加工作完成
            if (workerAdded) {
                // 启动线程,
                t.start();// 等同于启动worker本身,调用worker自身的run方法
                // 修改线程启动状态
                workerStarted = true;
            }
        }
    } finally {
        if (! workerStarted)
            addWorkerFailed(w);
    }
    // 返回线启动状态
    return workerStarted;
}

runWorker方法

final void runWorker(Worker w) {
    // 拿到当前线程
    Thread wt = Thread.currentThread();
    // 拿到初始化时提交的任务
    Runnable task = w.firstTask;
    // 将Worker.firstTask置空 并且释放锁
    w.firstTask = null;
    w.unlock(); // allow interrupts
    boolean completedAbruptly = true;
    try {
        // 如果task或者getTask不为空,则一直循环
        while (task != null || (task = getTask()) != null) {
            // 加锁
            w.lock();
            // 如果线程池状态>=STOP(停止) 或者 (线程中断且线程池状态>=STOP)且当前线程没有中断
            // 其实就是保证两点:
            // 1. 线程池没有停止
            // 2. 保证线程没有中断
            if ((runStateAtLeast(ctl.get(), STOP) ||
                 (Thread.interrupted() &&
                  runStateAtLeast(ctl.get(), STOP))) &&
                !wt.isInterrupted())
                // 中断当前线程
                wt.interrupt();
            try {
                // 任务执行前
                beforeExecute(wt, task);
                Throwable thrown = null;
                try {
                    // 执行run方法(Runable对象)
                    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置空, 完成任务++, 释放锁
                task = null;
                w.completedTasks++;
                w.unlock();
            }
        }
        completedAbruptly = false;
    } finally {
        // 退出工作
        processWorkerExit(w, completedAbruptly);
    }
}

getTask方法

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;
        }
        //获取运行线程数,根据allowCoreThreadTimeOut决定是否允许定时等待
        int wc = workerCountOf(c);
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
        //线程超时并且队列为空时通过CAS将实际运行线程数减1
        if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
            if (compareAndDecrementWorkerCount(c))
                return null;
            continue;
        }

        try {
            //允许超时则调用队列的poll方法定时等待
            //否则调用take获取任务
            Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take(); // 将线程阻塞,从而保证核心线程不被销毁
            //获取任务,返回结果
            if (r != null)
                return r;
            //继续循环,并且置超时标识为true
            timedOut = true;
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}

Worker线程管理

Worker内部类

  • 继承自AQS,实现了Runnable接口
  • 线程池使用HashSet去持有线程的引用,这样可以通过添加引用、移除引用这样的操作来控制线程的生命周期
  • 一直运行runWorker()方法
private final class Worker
	extends AbstractQueuedSynchronizer
	implements Runnable
{
private static final long serialVersionUID = 6138294804551838833L;
// worker运行的线程
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);
}
// run函数
public void run() {
    runWorker(this);
}

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

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) {
        }
    }
}

在这里插入图片描述

Worker线程回收

  • 将线程引用移出线程池,由JVM回收
try {
	while (task != null || (task = getTask()) != null) {
	  //执行任务
	}
} finally {
	processWorkerExit(w, completedAbruptly);//获取不到任务时,主动回收自己
}

判断线程是否在运行

  • 线程运行期间会加锁
    在这里插入图片描述

创建线程池参数

五个必须

  • int corePoolSize:该线程池中核心线程数最大值
  • 核心线程:核心线程默认情况下会一直存在于线程池中,即使这个核心线程什么都不干(铁饭碗),
  • 非核心线程:如果长时间的闲置,就会被销毁(临时工)
  • int maximumPoolSize:该线程池中线程总数最大值 。

该值等于核心线程数量 + 非核心线程数量。

  • long keepAliveTime:非核心线程闲置超时时长,默认情况下只有当线程池中的线程数大于corePoolSize时才会起作用
  • TimeUnit unit:keepAliveTime的单位。
  • BlockingQueue workQueue:阻塞队列,维护着等待执行的Runnable任务对象。后面详细介绍

两个非必须参数

  • RejectedExecutionHandler handler:拒绝策略
  • ThreadFactory threadFactory:线程工厂,统一在创建线程时设置一些参数

Executors自带线程池

newCachedThreadPool

  • 特点:线程不够的话可以无限增加
  • 使用SynchronousQueue:不存储元素
  • 核心线程数为:0
  • 程池没有最大线程数量限制,所以当大量线程蜂拥而至,会造成资源耗尽

newFixedThreadPool

  • 特点:线程不销毁,一直等待
  • 使用LinkedBlockingQueue:无界队列
  • corePoolSize == maximumPoolSize
  • 阻塞队列无限大造成OOM

newScheduledThreadPool

  • DelayedWorkQueue:无限长的
  • 初始化值为核心线程数,最大线程数为Integer.MAX_VALUE
  • 提交延时任务

newSingleThreadExecutor

  • 特点:保证多任务按顺序执行
  • 缺点:单线程,高并发业务下性能差
  • LinkedBlockingQueue
  • corePoolSize == maximumPoolSize = 1

常见问题

  • 核心线程和非核心线程的区别
  • 什么时候会去任务队列拿任务?
  • 如果提交了新任务,但是有空闲的线程,这个任务是由新创建的线程执行还是由空闲的线程执行?
    • 线程数量没有达到核心线程数总是会新建线程去执行任务
  • 怎么保证核心线程不被销毁?
    • 线程池的数量>核心线程数,且拿不到任务了,则线程结束
    • 线程池的数量<=核心线程数,调用阻塞队列的take()方法,拿不到任务会阻塞
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值