线程池的是实现原理

本文介绍了线程池相关知识。线程池可提前创建线程,处理任务后不销毁,能提升频繁创建和销毁线程时的系统性能。Java通过Executors接口提供四种线程池,还阐述了线程池核心任务提交方法execute()的工作原理与步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、什么是线程池

         线程池就是提前创建若干个线程,如果有任务需要处理,线程池里的线程就会处理任务,处理完之后线程并不会被销毁,而是等待下一个任务。由于创建和销毁线程都是消耗系统资源的,所以当你想要频繁的创建和销毁线程的时候就可以考虑使用线程池来提升系统的性能。

2、线程池的分类

      Java通过Executors接口提供四种线程池,分别为:

  • newCachedThreadPool:创建一个可缓存的线程池,如果当前没有可执行任务,在执行结束后缓存60s,如果不被调用则移除线程。调用execute()方法时可以重用缓存中的线程(线程池没有固定大小,为无限大)。适用于很多短期异步任务的环境,可以提高程序性能。
public static ExecutorService newCachedThreadPool() {
      return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
}
  • newFixedThreadPool :创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
  • newScheduledThreadPool :创建一个定长线程池,支持定时及周期性任务执行。
//创建周期性线程池,设置线程池大小
ScheduledExecutorService pool = Executors.newScheduledThreadPool(1);
//设置线程任务,执行延迟时间、执行的周期时间表达式
pool.schedule(callable, delay, unit);
  • newSingleThreadExecutor: 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

3、线程池的工作原理与步骤

(1)execute(Runnable command)(提交任务)

           在ThreadPoolExecutor类中,最核心的任务提交方法是execute()方法,虽然通过submit也可以提交任务,但是实际上submit方法里面最终调用的还是execute()方法,所以我们只需要研究execute()方法的实现

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
         int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command);
    }   

源码解析:

1、如果线程池当前线程数量少于corePoolSize,则addWorker(command, true)创建新worker线程,如创建成功返回,如没创建成功,则执行后续步骤;
    addWorker(command, true)失败的原因可能是:
    A、线程池已经shutdown,shutdown的线程池不再接收新任务
    B、workerCountOf(c) < corePoolSize 判断后,由于并发,别的线程先创建了worker线程,导致workerCount>=corePoolSize
2、如果线程池还在running状态,将task加入workQueue阻塞队列中,如果加入成功,进行double-check,如果加入失败(可能是队列已满),则执行后续步骤;
    double-check主要目的是判断刚加入workQueue阻塞队列的task是否能被执行
    A、如果线程池已经不是running状态了,应该拒绝添加新任务,从workQueue中删除任务
    B、如果线程池是运行状态,或者从workQueue中删除任务失败(刚好有一个线程执行完毕,并消耗了这个任务),确保还有线程执行任务(只要有一个就够了)
3、如果线程池不是running状态 或者 无法入队列,尝试开启新线程,扩容至maxPoolSize,如果addWork(command, false)失败了,拒绝当前command

### Java线程池实现原理 Java中的线程池主要通过`ThreadPoolExecutor`类来实现,它是整个线程池机制的核心组件。以下是关于线程池实现原理的具体说明: #### 1. 核心概念与参数解析 `ThreadPoolExecutor`是一个灵活的线程池实现类,它的构造函数允许开发者定义多个重要参数以控制线程池的行为[^1]。这些参数包括但不限于: - `corePoolSize`: 核心线程数量,在任何情况下都会保持活跃的状态。 - `maximumPoolSize`: 线程池能够容纳的最大线程数。 - `keepAliveTime`: 当前活动线程超过核心线程数时,多余的空闲线程等待新任务的时间长度。 - `workQueue`: 存储待处理任务的阻塞队列。 #### 2. 工作流程分析 当向线程池提交一个新任务时,线程池按照以下逻辑顺序进行处理[^2]: 1. 判断当前核心线程是否全部被占用。如果有未使用的线程,则分配给新的任务;否则继续下一步。 2. 如果核心线程已满,尝试将任务放入工作队列中。如果队列尚未达到上限,任务会被暂时存放在队列里等待执行。 3. 若队列也已填满,再评估是否有可用的工作线程(不超过最大线程数)。若有则启动额外的新线程去完成此任务。 4. 假设以上条件均不满足,即无法创建更多线程也无法排队等候,那么依据设定好的拒绝策略决定如何处置该任务。 #### 3. 静态 vs 动态线程池 除了基本功能外,还存在一种特殊形式——动态线程池。这种类型的线程池具备更强适应性和灵活性,因为它可以根据实际运行状况实时调节自身的属性设置,比如调整核心线程数目或者改变队列大小等,从而更好地匹配不同的业务场景需求[^3]。 #### 4. 实际应用案例展示 下面给出一段简单的代码演示了如何利用`ThreadPoolExecutor`构建并操作自己的线程池实例[^4]: ```java public class ThreadPoolDemo { public static void main(String[] args) throws InterruptedException { // 初始化线程池 ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( 3, // corePoolSize 5, // maximumPoolSize 0L, // keepAliveTime TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy() ); // 提交三个任务线程池 for (int i = 0; i < 6; i++) { final int taskNumber = i; threadPoolExecutor.submit(() -> { try { Thread.sleep(100); System.out.println("Task " + taskNumber + " is running on " + Thread.currentThread().getName()); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }); } // 安全关闭线程池 threadPoolExecutor.shutdown(); while (!threadPoolExecutor.awaitTermination(1, TimeUnit.SECONDS)) {} } } ``` 上述例子展示了如何自定义一个拥有固定最小线程数但可扩展到一定限度内的线程池,并且展示了任务提交以及最终安全终止的过程。 #### 5. C++对比视角下的补充说明 值得注意的是,虽然本讨论聚焦于Java平台上的线程池设计模式及其具体实践方法论,但在其他编程语言领域同样存在着类似的解决方案。例如C++标准库提供了std::async作为轻量级异步任务调度工具之一,而第三方开源项目Boost.Asio更是实现了高度复杂的事件驱动型并发框架。尽管它们之间语法风格和技术细节有所差异,但从宏观角度来看,其背后蕴含的思想却是相通的:合理规划计算资源分布、优化I/O密集型作业效率等等[^5]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值