首页 > 其他分享 >线程池 核心原理

线程池 核心原理

时间:2024-04-01 11:02:16浏览次数:30  
标签:核心 任务 线程 taskId 创建 原理 执行 ThreadPoolExecutor

文章目录

线程池核心原理

线程池的核心原理是基于“池化”(Pooling)思想,这种思想在计算机科学中广泛应用,例如数据库连接池、对象池等。线程池的主要目的是为了减少线程创建和销毁的开销,提高线程的复用性,从而提高程序的性能和响应速度。以下是线程池的核心原理:

  • 线程复用:线程池中维护了一组工作线程(Worker Threads),这些线程被创建后不会立即销毁,而是用于执行多个任务。当任务到达时,线程池会从池中选出一个空闲的线程来执行任务,而不是每次都创建新线程。
  • 任务队列:线程池通常配备了一个任务队列(Work Queue),用于存储待执行的任务。当所有工作线程都处于忙碌状态时,新提交的任务会被放入队列中等待空闲线程。
  • 线程管理:线程池内部会管理线程的生命周期,包括线程的创建、销毁、工作线程的数量等。线程池会根据配置的核心线程数(Core Pool Size)和最大线程数(Maximum Pool Size)来控制线程的数量。
  • 任务分配:线程池中的任务分配器(Task Scheduler)负责从任务队列中取出任务,并将任务分配给空闲的工作线程。
  • 动态线程管理:线程池可以根据当前负载动态地调整线程数量。例如,当任务队列满了,并且所有核心线程都处于忙碌状态时,线程池可能会创建新的线程,直到达到最大线程数。
  • 拒绝策略:当线程池达到最大线程数,并且任务队列已满时,线程池会根据预定义的拒绝策略来处理新提交的任务。常见的拒绝策略包括抛出异常、直接丢弃任务、丢弃队列中最老的任务等。

ThreadPoolExecutor

ThreadPoolExecutor 是 Java 中线程池的核心实现,位于 java.util.concurrent 包下。它提供了线程池的基本功能,包括线程的创建、任务的执行、线程的回收等,并允许开发者自定义线程池的行为。

主要构造函数:

ThreadPoolExecutor(int corePoolSize,
                   int maximumPoolSize,
                   long keepAliveTime,
                   TimeUnit unit,
                   BlockingQueue<Runnable> workQueue,
                   ThreadFactory threadFactory,
                   RejectedExecutionHandler handler)
  • corePoolSize:核心线程数,即始终存在的线程数量。
  • maximumPoolSize:最大线程数,即线程池中允许的最大线程数量。
  • keepAliveTime:非核心线程的空闲存活时间。
  • unit:keepAliveTime 的时间单位。
  • workQueue:用于存放任务的阻塞队列。
  • threadFactory:线程工厂,用于创建新线程。
  • handler:拒绝策略,用于处理当线程池和队列都满时新提交的任务。

执行任务:

ThreadPoolExecutor 提供了多个方法来执行任务:

  • execute(Runnable command):执行一个 Runnable 任务。
  • submit(Runnable task):提交一个 Runnable 任务,并返回一个 Future 对象,可以通过这个对象获取任务执行的结果(如果有)。
  • submit(Callable task):提交一个 Callable 任务,并返回一个 Future 对象,可以通过这个对象获取任务执行的结果。

关闭线程池:

ThreadPoolExecutor 可以通过以下方法来关闭:

  • shutdown():启动线程池的关闭序列,不再接受新任务,但会继续执行所有已经提交的任务。
  • shutdownNow():尝试立即停止所有正在执行的任务,并返回尚未开始执行的任务列表。

线程池生命周期:

ThreadPoolExecutor 定义了线程池的生命周期状态,包括:

  • RUNNING:接受新任务并处理队列中的任务。
  • SHUTDOWN:不接受新任务,但处理队列中的任务。
  • STOP:不接受新任务,不处理队列中的任务,并尝试中断正在执行的任务。
  • TIDYING:所有任务都已终止,线程池正在转换为 TERMINATED 状态。
  • TERMINATED:线程池已终止。

Executor框架

Executor框架是Java 5引入的一个用于并发编程的框架,它提供了任务执行和异步任务管理的工具。这个框架的主要目的是简化线程的使用和管理,使得开发者可以更加专注于任务的逻辑,而不是线程的创建和管理。Executor框架的主要组件包括:

Executor接口:

  • 这是框架的基础,一个简单的接口,定义了执行任务的方法 execute(Runnable command)。

ExecutorService接口:

  • 继承自Executor接口,提供了更多管理任务执行的方法,如 submit()、shutdown()、shutdownNow() 等。
  • 它还提供了用于批量执行任务的方法,如 invokeAll() 和 invokeAny()。

ThreadPoolExecutor类:

  • ExecutorService接口的一个实现,是一个灵活的线程池实现,允许开发者自定义线程池的参数和行为。

ScheduledExecutorService接口:

  • 继承自ExecutorService,提供了定时任务执行的方法,如 schedule()、scheduleAtFixedRate()、scheduleWithFixedDelay()。

ScheduledThreadPoolExecutor类:

  • ScheduledExecutorService接口的一个实现,用于执行定时任务和周期性任务。

Future接口:

  • 表示异步计算的结果,提供了检查计算是否完成、等待计算完成、获取计算结果、取消计算等方法。

Callable接口:

  • 与Runnable类似,但它允许任务返回一个结果或抛出一个异常。

Executor框架的使用通常涉及以下步骤:

  • 创建ExecutorService实例,例如通过ThreadPoolExecutor或Executors工厂类。
  • 提交Runnable或Callable任务到ExecutorService。
  • 使用Future来获取任务的结果(如果任务提交时使用了submit()方法)。
  • 关闭ExecutorService,防止新任务的提交,并等待所有任务执行完成。

线程池实战

使用线程池的实战通常涉及到java.util.concurrent包中的ExecutorService和ThreadPoolExecutor类。以下是一个简单的示例,展示了如何使用线程池来执行多个任务。

步骤1:创建线程池

首先,我们需要创建一个线程池。我们可以使用Executors工厂类来创建一个固定大小的线程池,也可以直接使用ThreadPoolExecutor构造函数来定制线程池。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

// 创建一个固定大小的线程池,包含5个线程
ExecutorService executorService = Executors.newFixedThreadPool(5);

步骤2:创建任务

接下来,我们创建一个实现Runnable接口的任务类。

import java.util.concurrent.TimeUnit;

public class MyTask implements Runnable {
    private final int taskId;

    public MyTask(int taskId) {
        this.taskId = taskId;
    }

    @Override
    public void run() {
        System.out.println("开始执行任务:" + taskId);
        try {
            // 模拟任务执行需要一段时间
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("任务:" + taskId + " 执行完成");
    }
}

步骤3:提交任务到线程池

现在我们可以将任务提交到线程池中执行。

for (int i = 0; i < 10; i++) {
    executorService.submit(new MyTask(i));
}

步骤4:关闭线程池

最后,当我们不再需要线程池时,应该关闭它以释放资源。

executorService.shutdown();

完整示例

将上述步骤组合在一起,我们得到一个完整的线程池使用示例。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class ThreadPoolExample {
    public static void main(String[] args) {
        // 创建一个固定大小的线程池,包含5个线程
        ExecutorService executorService = Executors.newFixedThreadPool(5);

        // 提交任务到线程池
        for (int i = 0; i < 10; i++) {
            executorService.submit(new MyTask(i));
        }

        // 关闭线程池
        executorService.shutdown();
    }
}

class MyTask implements Runnable {
    private final int taskId;

    public MyTask(int taskId) {
        this.taskId = taskId;
    }

    @Override
    public void run() {
        System.out.println("开始执行任务:" + taskId);
        try {
            // 模拟任务执行需要一段时间
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("任务:" + taskId + " 执行完成");
    }
}

我们创建了一个包含5个线程的线程池,并提交了10个任务。由于线程池的大小限制,一次只能执行5个任务,其他任务会在队列中等待。每个任务模拟执行2秒,然后输出完成信息。
在实际应用中,线程池的使用会更加复杂,可能需要根据应用程序的特定需求来调整线程池的大小和配置,以及处理任务执行中的异常和结果。

标签:核心,任务,线程,taskId,创建,原理,执行,ThreadPoolExecutor
From: https://blog.csdn.net/m0_68933188/article/details/137224451

相关文章

  • 线程池
    文章目录线程池线程池的优点线程池的组成使用线程池的场景线程池配置什么情况下建议不要使用线程池线程池线程池(ThreadPool)是一种在多线程环境下常用的一种资源管理手段,主要用于优化线程的创建和管理,以提高程序性能和资源利用率。线程池维护一个已经创建的线程的集......
  • FIFO存储器选型参数,结构原理,工艺与注意问题总结
      ......
  • RGB到HSV的转换原理及例程
    RGB(红绿蓝)和HSV(色相、饱和度、明度)是两种常用的颜色模型,RGB用于表示彩色图像,而HSV主要用于描述颜色的特征。RGB到HSV的转换涉及颜色的几何和三维空间的变换。RGB颜色模型使用红、绿、蓝三个通道来表示各种颜色。每个通道的取值范围为0-255,其中0表示没有该通道的颜色,255表示通......
  • 【前端面试3+1】07vue2和vue3的区别、vue3响应原理及为什么使用proxy、vue的生命周期
    一、vue2和vue3的区别1.性能优化:        Vue3在性能方面有很大的提升,主要是通过虚拟DOM的优化和响应式系统的改进实现的。虚拟DOM重构:Vue3中对虚拟DOM进行了重构,使得更新算法更加高效,减少了更新时的开销,提升了性能。静态树提升:Vue3可以通过静态树提升技术......
  • 从虚拟dom知识无痛深入vue与react的原理
     我们都知道像vue、react都有用到虚拟dom,那么虚拟dom到底是什么?框架为什么不直接操作真实dom而要在中间要引入虚拟dom呢?vue和react的虚拟dom又有什么异同呢?我们就从虚拟dom开始讲起,再来逐步引入讲解vue与react的部分原理及其异同,这里会顺便讲解到数据驱动视图及视图驱动数据,......
  • 史上最全Java核心面试题(带全部答案)2024年最新版
    今天要谈的主题是关于求职,求职是在每个技术人员的生涯中都要经历多次。对于我们大部分人而言,在进入自己心仪的公司之前少不了准备工作,有一份全面细致面试题将帮助我们减少许多麻烦。在跳槽季来临之前,特地做这个系列的文章,一方面帮助自己巩固下基础,另一方面也希望帮助想要换工......
  • Ray Tracking 基本原理
    光线追踪和光栅化的区别光栅化不能处理更全局的信息。比如软阴影、玻璃的反射以及以及经过多次反射的光线。光线追踪将整个过程变换为从摄像机发出感知射线,到达物体之后,如果相同的点也能够被光源感知到,以此进行渲染。感觉光栅化这个过程是从光源出发,最后通过投影转到相机上。光......
  • SQL SERVER 从入门到精通 第5版 第二篇 核心技术 第5章 读书笔记
     第五章SQL基础 P63.SQL概述>.SQL的组成>.数据定义语言(datadefinitionlanguage,DDL):用于在数据库系统中,对数据库,表,视图,索引等数据库对象进行创建和管理>.数据控制语言(datacontrollanguage,DCL):实现对数据库中数据的完整性,完全性等的......
  • @rollup/plugin-url 使用及原理介绍
    @rollup/plugin-url使用及原理介绍一款用于将导入的文件转换成data-uri或者es模块的插件。安装npminstall@rollup/plugin-url-D使用在rollup.config.js文件中引入插件并进行简单配置。importurlfrom'@rollup/plugin-url';exportdefault{input:'......
  • 【Linux】认识线程池 AND 手撕线程池(正常版)
    文章目录0.回顾进程池1.计算机层面的池化技术2.线程池预备知识2.1介绍线程池2.2设计线程池的意义是什么?2.3其他知识3.回顾C++类与对象3.1cpp什么情况下成员函数必须是静态的?3.1可变参数列表3.2格式化输出函数3.3预定义符号4.图解线程池运作原理4.0完整代码Makefilelog.......