(史上最全)线程池

news2024/9/20 22:24:11

线程池

文章目录

    • 线程池
      • 一,前言
      • 二,线程池
      • 三,参数
      • 四,线程池的实现原理
      • 5.线程池的使用案例(自定义线程池)
      • 6.使用Executors 创建常见的功能线程池
        • 1.固定大小线程池
        • 2.定时线程
        • 3.可缓存线程池
        • 4.单线程化线程池

一,前言

虽然线程给我们程序带来了更高的执行效率,但是线程不是创建的越多越好,那么线程创建的过多,会带来什么问题呢?

首先线程的创建和销毁都是很耗时很浪费性能的操作

(new三五个Thread还好,我需要一千个线程呢?)

线程之间频繁的进行上下文切换,增加系统的负载

为了解决上述问题,线程池诞生了,线程池的核心思想就是:线程复用

也就是说线程用完后不销毁,放到池子里等着新任务的到来,反复利用N个线程来执行所有新老任务。这带来的开销只会是那N个线程的创建,而不是每来一个请求都带来一个线程的从生到死的过程。

二,线程池

概念

‌‌线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。‌ 线程池是一种线程复用的技术,可以有效地控制线程的数量,减少线程创建和销毁带来的开销,提高系统响应速度,并方便线程管理。(官方)

简单来说,线程池就是提前创建好一批线程,当有任务的时候,从池子中取出一个线程去执行该任务,执行结束后,再把线程放回池子中,以备循环使用。

三,参数

public ThreadPoolExecutor(int corePoolSize,
        int maximumPoolSize,  
		long keepAliveTime,
		TimeUnit unit,
		BlockingQueue<Runnable> workQueue,
		ThreadFactory threadFactory,
		RejectedExecutionHandler handler) {
}

参数解释

corePoolSize:核心线程数

线程池在完成初始化之后,默认情况下,线程池中不会有任何线程,线程池会等有任务来的时候
再去创建线程。核心线程创建出来后即使超出了线程保持的存活时间配置也不会销毁,核心线程
只要创建就永驻了,就等着新任务进来进行处理。

maximumPoolSize:最大线程数

核心线程忙不过来且任务存储队列满了的情况下,还有新任务进来的话就会继续开辟线程,但是
也不是任意的开辟线程数量,线程数(包含核心线程)达到最大线程数后就不会产生新线程了,
就会执行拒绝策略。

keepAliveTime:线程保持的存活时间

如果线程池当前的线程数多于核心线程数,那么如果多余的线程空闲时间超过线程保持的存活时
间,那么这些多余的线程(超出核心线程数的那些线程)就会被回收。

unit:线程保持的存活时间单位

比如:TimeUnit.MILLISECONDS、TimeUnit.SECONDS

workQueue:任务存储队列

核心线程数满了后还有任务继续提交到线程池的话,就先进入任务存储队列。

workQueue通常情况下有如下选择:
LinkedBlockingQueue:无界队列,意味着无限制,其实是有限制,大小是int的最大值。也可以
自定义大小。
ArrayBlockingQueue:有界队列,可以自定义大小,到了阈值就开启新线程(不会超过最大线
程数)。
SynchronousQueue: Executors.newCachedThreadPool();默认使用的队列。
一般都采取无界队列,因为他也可以设置大小,可以取代有界队列。

threadFactory:当线程池需要新的线程时,会用threadFactory来生成新的线程

默认采用的是 DefaultThreadFactory ,主要负责创建线程。 newThread() 方法。创建出来的
线程都在同一个线程组且优先级也是一样的。

handler:拒绝策略,任务量超出线程池的配置限制或执行shutdown还在继续提交任务的话,会执行handler 的逻辑。

默认采用的是 AbortPolicy ,遇到上面的情况,线程池将直接采取直接拒绝策略,也就是直接抛
出异常。 RejectedExecutionException

四种内置的拒绝策略
1. AbortPolicy(默认):直接抛出RejectedExecutionException异常,阻止系统正常运行。
2. CallerRunsPolicy:由调用线程(提交任务的线程)执行被拒绝的任务。这样做可以降低新任务
的提交速度,但可能会影响整体性能。
3. DiscardPolicy:默默地丢弃被拒绝的任务,不做任何处理。
4. DiscardOldestPolicy:丢弃最早被放入队列的任务,然后尝试重新提交被拒绝的任务。
 
//自定义拒绝策略,实现RejectedExecutionHandler接口,并重写rejectedExecution方法来定义自
己的处理逻辑

四,线程池的实现原理

在这里插入图片描述

从图中我们可以看到完整的执行流程

  1. 线程提交到线程池
  2. 判断核心线程池是否已经达到设定的数量,如果没有达到,则直接创建线程执行任务
  3. 如果达到了,则放在队列中,等待执行
  4. 如果队列已经满了,则判断线程的数量是否已经达到设定的最大值,如果达到了,则直接执行拒绝策略
  5. 如果没有达到,则创建线程执行任务。

5.线程池的使用案例(自定义线程池)

import java.util.concurrent.*;

public class ThreadPoolExample {
    public static void main(String[] args) {
        // 创建线程池
        ExecutorService executorService = new ThreadPoolExecutor(
                2,     //两个核心线程数
                4,     //最大线程数
                60,		// 线程保持的存活时间
                TimeUnit.SECONDS,//指定了 keepAliveTime 的单位为秒
                new ArrayBlockingQueue<>(10),//最多可以在这个队列中排队 10 个任务
                Executors.defaultThreadFactory(),// Java 提供的默认线程工厂来创建新线程
                new ThreadPoolExecutor.AbortPolicy());//拒绝策略

        // 提交任务
        for (int i = 0; i < 10; i++) {
            executorService.submit(() -> {//submit 方法:用于提交一个可执行的任务
  										  //() -> { ... }:表示一个实现了 Runnable 接口的匿名类。大括号内的代码是你希											望在独立线程中执行的逻辑。
                try {
                    System.out.println("执行任务开始 " + Thread.currentThread().getName());
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            });
        }

        // 关闭线程池
        executorService.shutdown();
    }
}
//输出结果
执行任务开始 pool-1-thread-1
执行任务开始 pool-1-thread-2
执行任务开始 pool-1-thread-2
执行任务开始 pool-1-thread-1
执行任务开始 pool-1-thread-2
执行任务开始 pool-1-thread-1
执行任务开始 pool-1-thread-2
执行任务开始 pool-1-thread-1
执行任务开始 pool-1-thread-1
执行任务开始 pool-1-thread-2

在输出中,pool-1-thread-1pool-1-thread-2 中的数字分别代表以下含义:

  1. pool-1:这是线程池的名称。1 表示这是第一个创建的线程池,如果有多个线程池,则会以递增的数字命名。
  2. thread-1thread-2:这些表示线程在该线程池中的编号。它们是按照创建顺序递增的。thread-1 是第一个线程,thread-2 是第二个线程,依此类推。

因此,整个字符串表示该线程池中的具体线程,帮助我们识别和调试哪个线程在执行哪个任务。

6.使用Executors 创建常见的功能线程池

Executors为我们封装好了 4 种常见的功能线程池如下:

  1. 定长线程(固定大小):FixedThreadPool
  2. 定时线程:ScheduledThreadPool
  3. 可缓存线程池:CachedThreadPool
  4. 单线程化线程池:SingleThreadExecutor
1.固定大小线程池

核心线程数和最大线程数是一样的,所以称之为固定线程数。
其他参数配置默认为:永不超时(0ms),无界队列( LinkedBlockingQueue )、默认线程工厂
( DefaultThreadFactory )、直接拒绝策略( AbortPolicy )。

public class ThreadPoolTest {
	public static void main(String[] args) {
		ExecutorService executorService = Executors.newFixedThreadPool(2);
		for (int i = 0; i < 10; i++) {
			// 从结果中可以发现线程name永远都是两个。不会有第三个。
			executorService.execute(() -
	> System.out.println(Thread.currentThread().getName()));
			}
		}
}
2.定时线程

核心线程数手动传进来,最大线程数是Integer.MAX_VALUE,最大线程数是内部默认的,不可更改。
其他参数配置默认为:永不超时(0ns),带延迟功能的队列( DelayedWorkQueue )、默认线程工厂
( DefaultThreadFactory )、直接拒绝策略( AbortPolicy )。

public class ThreadPoolTest {
	public static void main(String[] args) {
		ScheduledExecutorService scheduledExecutorService = Executors.newSchedul
edThreadPool(2);
		// 五秒一次
		scheduledExecutorService.schedule(() -> System.out.println(Thread.currentThread().getName()), 5, TimeUnit.SECONDS);
		// 首次五秒后执行,其次每隔1s执行一次
		scheduledExecutorService.scheduleAtFixedRate(() -> System.out.println(Thread.currentThread().getName()), 5, 1, TimeUnit.SECONDS);
}

3.可缓存线程池

他的功能是来个任务我就开辟个线程去处理,不会进入队列, SynchronousQueue 队列也不带存储元素
的功能。那这意味着来一亿个请求就会开辟一亿个线程去处理,keepAliveTime为60S,意味着线程空
闲时间超过60S就会被杀死;这就叫带缓存功能的线程池。
核心线程数是0,最大线程数是int的最大值,内部默认的,不可更改。

public class ThreadPoolTest {
	public static void main(String[] args) {
		ExecutorService executorService = Executors.newCachedThreadPool();
		for (int i = 0; i < 10; i++) {
			// 从结果中可以发现线程name有10个。也就是有几个任务就会开辟几个线程。
			executorService.execute(() -
> System.out.println(Thread.currentThread().getName()));
		}
	}
}
4.单线程化线程池

核心线程数和最大线程数是1,内部默认的,不可更改,所以称之为单线程数的线程池。
类似于 Executors.newFixedThreadPool(1);
其他参数配置默认为:永不超时(0ms),无界队列( LinkedBlockingQueue )、默认线程工厂
( DefaultThreadFactory )、直接拒绝策略( AbortPolicy )。

public class ThreadPoolTest {
	public static void main(String[] args) {
		ExecutorService executorService = Executors.newSingleThreadExecutor();
		for (int i = 0; i < 10; i++) {
			// 从结果中可以发现线程name永远都是pool-1-thread-1。不会有第二个出现。
			executorService.execute(() -
> System.out.println(Thread.currentThread().getName()));
		}
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2147081.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Prometheus 上手指南

文章目录 Prometheus 相关概念Prometheus 的特点Prometheus 架构数据模型 Datemode使用场景 指标类型 Metric type适用场景 作业和实例 Jobs and instances使用场景 Prometheus 安装Prometheus 配置prometheusalertmanager Grafana 可视化Grafana 安装Grafana 配置选项Grafana …

假期学习--iOS 编译链接

iOS 编译链接 编译流程 四步&#xff1a; 1.预处理 2.编译 3.汇编 4.链接 大概的步骤如下&#xff1a; 预处理 作为编译的第一步&#xff0c;将.m文件转换为.i文件 &#xff1b; 预处理是要处理源代码中所有以#开头的所有预编译指令 &#xff1b; 规则如下&#xff1…

更换UFS绑定固件与“工程固件”的区别 小米10s机型更换cpu绑定包对比 写入以及修复基带

目前机型的安全机制越来越高。机型cpu与字库存在绑定关系。主板cpu如损坏需要更换。换新cpu后就需要刷写底层绑定包来修复 。今天的博文将为大家带来UFS绑定包与工程固件的区别以及写入 修复基带的步骤解析 通过博文了解 1💝💝💝-----更换UFS绑定包与工程固件的区别 2…

利士策分享,赚钱与体重:一场关于生活平衡的微妙探索

利士策分享&#xff0c;赚钱与体重&#xff1a;一场关于生活平衡的微妙探索 在当今社会&#xff0c;赚钱与体重&#xff0c;这两个看似风马牛不相及的概念&#xff0c; 却在无形中交织着人们的生活轨迹。 它们不仅仅是数字上的增减&#xff0c;更是个人选择、生活方式乃至心理…

Mycat搭建分库分表

分库分表解决的问题 单表数据量过大带来的性能和存储容量的限制的问题&#xff1a; 索引效率下降读写瓶颈存储容量限制事务性能问题分库分表架构 再搭建一对主从复制节点&#xff0c;3307主节点&#xff0c;3309从节点配置数据源 dw1 , dr1,创建集群c1创建逻辑库 CREATE DATAB…

【AI小项目6】QLoRA针对资源受限设备上的大模型微调和文本分类任务的推理

目录 一、项目简介概述时间主要工作和收获技术栈数据集结果参考 二、训练阶段的完整代码什么是 QLoRA 微调&#xff1f;注意 安装库导入包配置定义一个Config类配置训练参数配置Lora 初始化分词器和模型数据预处理计算模型评估指标交叉验证划分数据集举例&#xff1a; 创建Trai…

Redis-分片集群

分片集群 主从和哨兵可以解决高可用、高并发读的问题。但是依然有两个问题没有解决&#xff1a; 海量数据存储问题 高并发写的问题 使用分片集群可以解决上述问题&#xff0c;如图: 分片集群特征&#xff1a; 集群中有多个master&#xff0c;每个master保存不同数据 每个ma…

Java-测试-Mockito 入门篇

之前很长一段时间我都认为测试就是使用SpringBootTest类似下面的写法&#xff1a; SpringBootTest class SysAuthServiceTest {AutowiredSysRoleAuthMapper sysRoleAuthMapper;Testpublic void test() {QueryWrapper<SysRoleAuth> queryWrapper new QueryWrapper<&g…

Linux命令:对文本文件的内容进行排序的工具sort详解

目录 一、概述 二、用法 1、 基本语法 2、 常用选项 3、获取帮助 三、示例 1. 基本用法 2. 按数字排序 3. 按第二列排序 4. 逆序排序 5. 删除重复行 6. 忽略大小写排序 7. 按人类可读的数值排序 8. 按版本号排序 四、高级用法 1. 与 uniq 结合使用去重 2. 与 gr…

1.使用 VSCode 过程中的英语积累 - File 菜单(每一次重点积累 5 个单词)

前言 学习可以不局限于传统的书籍和课堂&#xff0c;各种生活的元素也都可以做为我们的学习对象&#xff0c;本文将利用 VSCode 页面上的各种英文元素来做英语的积累&#xff0c;如此做有 3 大利 这些软件在我们工作中是时时刻刻接触的&#xff0c;借此做英语积累再合适不过&a…

不断挑战才有不断机遇!Eagle Trader等你来加入!

2024“Eagle Trader杯”全国职业交易联赛S1赛季已火热进行一个多月&#xff0c;吸引了超过355名交易员的积极参与&#xff01;目前&#xff0c;每天都有新的交易员踊跃报名参加&#xff01; 经过严格地交易考核&#xff0c;13名选手成功通过初试&#xff0c;正进入下一阶段的挑…

XILINX ZYNQ 7000 使用 FreeRTOS

XILINX 官方的SDK可以生成FreeRTOS 本文分为三个部分&#xff1a; 1.ZYNQ 7010 创建一个最小ZYNQ Processer系统&#xff0c;能够使用串口打印 2.使用SDK 创建一个FreeRTOS最小软件系统 3.浅析FreeRTOS最小软件系统 一&#xff1a;ZYNQ 7010 创建一个最小ZYNQ Processer系统&…

基于Linux系统离线安装oracle数据库

注意事项&#xff1a; 在安装的时候多次涉及root用户和oracle用户的切换&#xff0c;请注意区分&#xff0c;本文已明显 一、环境准备 1、关闭防火墙 [rootlocalhost ~]# systemctl stop firewalld2、 禁用NetworkManager服务&#xff08;非必须&#xff09; [rootlocalhost …

信号与线性系统实验四 离散系统的时域及变换域分析

文章目录 一、实验目的二、实验内容与原理三、实验器材四、实验步骤五、实验数据及结果分析第一部分&#xff1a;离散时间信号的时域基本运算第二部分&#xff1a; 离散LTI系统的时域分析第三部分&#xff1a;离散LTI系统Z域分析 六、实验结论七、其他(主要是心得体会) 一、实验…

通信工程学习:什么是PON无源光网络

PON&#xff1a;无源光网络 PON&#xff08;Passive Optical Network&#xff0c;无源光纤网络&#xff09;是一种采用光分路器等无源光器件进行信号传输和分配的光纤接入技术。它利用光纤作为传输媒介&#xff0c;通过无源设备将光信号从中心局&#xff08;如光线路终端OLT&am…

Linux基础4-进程1(操作系统,进程介绍,Linux进程相关命令,getpid,fork)

上篇文章&#xff1a;Linux基础3-基础工具4&#xff08;git&#xff09;&#xff0c;冯诺依曼计算机体系结构-CSDN博客 本章重点&#xff1a; 1. 操作系统简介 2. 什么是进程&#xff1f; 3. 在Linux使用命令查看进程&#xff08;ps&#xff09; 4. getpid&#xff0c;getppid,…

卷积和相关

卷积和相关是两种运算关系(或过程),都是含参变量的无穷积分。都是两个函数通过某种运算得到另外一个函数。 卷积运算: 可用来表示一个观测系统或一个观 测仪器对输入信号的作用过程等。 相关运算:常用来比较两个函数的关联性,相似程度,用于信号检测,图像识别。如:在混…

SCSAI平台面向对象建模技术的设计和实现(1)

SCSAI平台面向对象建模技术的设计和实现&#xff08;1&#xff09; 原创 团长团 AI智造AI编程 2024年09月19日 20:09 北京 用爱编程30年&#xff0c;倾心打造工业和智能智造软件研发平台SCSAI,用创新的方案、大幅的让利和极致的营销&#xff0c;致力于为10000家的中小企业实现…

【jupyter notebook】环境部署及pycharm连接虚拟机和本地两种方式

Python数据处理分析简介 Python作为当下最为流行的编程语言之一 可以独立完成数据分析的各种任务数据分析领域里有海量开源库机器学习/深度学习领域最热门的编程语言在爬虫&#xff0c;Web开发等领域均有应用 与Excel&#xff0c;PowerBI&#xff0c;Tableau等软件比较 Excel有…

双立方(三次)卷积插值

前言 图像处理中有三种常用的插值算法&#xff1a; 最邻近插值 双线性插值 双立方&#xff08;三次卷积&#xff09;插值 其中效果最好的是双立方&#xff08;三次卷积&#xff09;插值&#xff0c;本文介绍它的原理以及使用 如果想先看效果和源码&#xff0c;可以拉到最底…