Java线程池详解系列01:高效并发编程的核心利器

01 - Java线程池详解:高效并发编程的核心利器

参考资料:https://www.cnblogs.com/damaoa/p/18936921

前提:需要掌握多线程概念

一、什么是线程池

1. 线程池的定义

线程池就像一个"线程工厂",它预先创建一定数量的工作线程并放在"池子"里待命。

当有任务需要执行时,不需要重新创建线程,而是直接从池子里取一个空闲线程来干活。

任务完成后,线程不会被销毁,而是重新回到池子里等待下一个任务。

这就好比一个餐厅,与其每来一个客人就临时招聘一个服务员,不如提前雇好几个服务员待命,这样既节省了招聘成本,又能保证服务质量。

2. 为什么需要线程池

想象一下没有线程池的痛苦:

传统方式的问题:

  • 资源浪费严重:每个任务都创建新线程,用完就丢弃,
  • 响应速度慢:创建线程需要时间,用户等得不耐烦
  • 系统压力大:线程数量无法控制,高并发时可能创建成千上万个线程,系统直接崩溃
  • 内存溢出风险:每个线程都要占用内存空间,线程太多直接爆内存
// 反面教材:每次都创建新线程
public void handleRequest(String request) {
   
   
    new Thread(() -> {
   
   
        System.out.println("处理请求: " + request);
        // 处理业务逻辑...
    }).start(); // 用完就销毁,太浪费了!
}

使用线程池的优势:

  • 资源复用:线程用完不销毁,循环利用,环保又高效
  • 快速响应:线程提前准备好,任务来了立即执行
  • 流量控制:限制最大线程数,保护系统不被压垮
  • 统一管理:线程的创建、销毁、监控都有专人负责
// 正确做法:使用ThreadPoolExecutor创建线程池
private final ThreadPoolExecutor executor = new ThreadPoolExecutor(
    5,                          // 核心线程数
    10,                         // 最大线程数
    60L, TimeUnit.SECONDS,      // 空闲线程存活时间
    new LinkedBlockingQueue<>(100), // 工作队列
    Executors.defaultThreadFactory(), // 线程工厂
    new ThreadPoolExecutor.AbortPolicy() // 拒绝策略
);

public void handleRequest(String request) {
   
   
    executor.submit(() -> {
   
   
        System.out.println("处理请求: " + request);
        // 处理业务逻辑...
    });
}

3. 线程池工作原理

线程池的工作流程可以用一个形象的比喻来理解:

想象线程池是一个快递公司,有以下几个关键角色:

  • 核心快递员:公司的正式员工,即使没活干也不会被裁员
  • 临时快递员:业务繁忙时临时雇佣的员工
  • 任务仓库:存放待配送包裹的仓库
  • 人事部门:负责处理超出处理能力的订单
新任务到来
核心线程都忙?
分配核心线程执行
队列是否满?
任务入队等待
达到最大线程数?
创建临时线程执行
执行拒绝策略

4. 线程池的执行流程

1)如果workerCount < corePoolSize ==> 创建线程执行提交的任务
2)如果workerCount >= corePoolSize && 阻塞队列未满 ==> 添加至阻塞队列,等待后续线程来执行提交地任务
3)如果workerCount >= corePoolSize && workerCount < maxinumPoolSize && 阻塞队列已满 ==> 创建非核心线程执行提交的任务
4)如果workerCount >= maxinumPoolSize && 阻塞队列已满 ==> 执行拒绝策略

4.1 提交任务
public void execute(Runnable command) {
   
   
    if (command == null)
        throw new NullPointerException();
    int c = ctl.get();
	// 工作线程数量 < corePoolSize => 直接创建线程执行任务
    if (workerCountOf(c) < corePoolSize) {
   
   
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
	// 工作线程数量 >= corePoolSize && 线程池处于运行状态  => 将任务添加至阻塞队列中
    if (isRunning(c) && workQueue.offer(command)) {
   
   
        int recheck = ctl.get();
		/**
         * 为什么需要double check线程池的状态?
         * 在往阻塞队列中添加任务地时候,有可能阻塞队列已满,需要等待其他的任务移出队列,在这个过程中,线程池的状态可能会发生变化,所以需要doublecheck
         * 如果在往阻塞队列中添加任务地时候,线程池地状态发生变化,则需要将任务remove
         */
        if (! isRunning(recheck) && remove(command))
            reject(command);
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
    else if (!addWorker(command, false))
        reject(command);
}
4.2 addWorker 创建线程加入线程池
private boolean addWorker(Runnable firstTask, boolean core) {
   
   
    retry:
    for (;;) {
   
   
        int c = ctl.get();
        int rs = runStateOf(c);

        // Check if queue empty only if necessary.
		// 线程池状态处于非RUNNING状态,添加worker失败
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&
               firstTask == null &&
               ! workQueue.isEmpty()))
            return false;
		// 判断线程池中线程数量是否处于该线程池允许的最大线程数量,如果允许创建线程,则cas更新线程池中线程数量,并退出循环检查,执行下面创建线程地逻辑
        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
        }
    }

    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.
               
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

佳瑞Jarrett

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值