Java线程池底层原理

文章详细介绍了Java线程池的工作原理,包括线程池的创建、核心线程数、最大线程数、存活时间和拒绝策略。在创建线程池时,可以通过指定参数来调整这些属性。execute()方法用于提交任务,会根据线程池的状态和任务队列的容量决定是创建新线程、放入队列还是执行拒绝策略。线程池通过ctl变量控制状态,并使用AtomicInteger保证并发安全性。
摘要由CSDN通过智能技术生成

Java线程池底层原理

Java线程池是用来优化多线程的,由于原始线程的创建以及关闭(线程垃圾的回收)是非常消耗资源的的,而线程池是用来优化多个线程反复创建或者关闭的操作的。

线程池的创建

ThreadPoolExecutor pool = new ThreadPoolExecutor(
    2, 	// 核心线程数 	
    5, 	// 最大线程数 推荐为cpu核心数 * 2
    10, // 线程存活时间:空闲线程或者设置allowCoreThreadTimeout=true的核心线程
    TimeUnit.MINUTES,	// 线程存活时间单位
    new ArrayBlockingQueue<>(3),	// 阻塞队列/任务队列
    Executors.defaultThreadFactory(),	// 线程工厂,创建线程的方式,可以自定义
    new ThreadPoolExecutor.AbortPolicy()	// 拒绝策略
);
拒绝策略描述
AbortPolicy拒绝并抛出异常。
CallerRunsPolicy重试提交当前的任务,即再次调用运行该任务的execute()方法。
DiscardOldestPolicy抛弃队列头部(最旧)的一个任务,并执行当前任务。
DiscardPolicy抛弃当前任务。

线程池创建任务

pool.execute(new Runnable() {
    @Override
    public void run() {
        方法名(参数);
    }
});

execute()方法的源码

public void execute(Runnable command) {
    if (command == null)	// 先排除异常值,也就是传入了空指针线程变量
        throw new NullPointerException();

    int c = ctl.get();	// 获取主线程池控制状态

    if (workerCountOf(c) < corePoolSize) {	// 判断工作中的线程是否小于核心线程
        // 尝试添加线程,参数为true表示是否新建线程,因为多线程环境下的并发操作可能导致幻读
        // true,表示新增线程时,判断当前线程数是否少于corePoolSize,即会创建核心线程
        if (addWorker(command, true))	
            return;
        c = ctl.get(); 	// 如果没成功,重新获取线程池状态
    }
    if (isRunning(c) && workQueue.offer(command)) {	// 查看线程是否在运行,并且将任务添加到任务队列
        int recheck = ctl.get();	// 再次获取线程池状态
        if (! isRunning(recheck) && remove(command))	// 二次状态检查,非RUNNING态,从队列移除
            reject(command);	// 执行拒绝策略
        // 如果设置allowCoreThreadTimeOut=true,核心线程就会因空闲全部回收,所以导致工作线程数为0
        else if (workerCountOf(recheck) == 0)	
            // 为什么传null,线程启动后会自动从阻塞队列拉任务执行
            // false,表示新增线程时,判断当前线程数是否少于maximumPoolSize,即会创建非核心线程,也就是空闲线程
            addWorker(null, false);	
    }
    // 尝试创建空闲线程
    else if (!addWorker(command, false))	
        // 创建失败,执行拒绝策略
        reject(command);
}

ctl:主池控制状态

// 定义ctl:主池控制状态,一个AtomicInteger,低28位用来表示线程数,高4位用来表示线程池状态。
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

// AtomicInteger 用于原子递增计数器等应用程序,不能用作 Integer 的替代品。
private volatile int value;
public AtomicInteger(int initialValue) {
    value = initialValue;
}

线程添加任务流程

img

简单记

  1. 当线程数小于核心线程数时,创建线程。
  2. 当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列。
  3. 当线程数大于等于核心线程数,且任务队列已满:
  • 若线程数小于最大线程数,创建线程。
  • 若线程数等于最大线程数,抛出异常,拒绝任务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值