java多线程——线程池

概述

线程池是管理java线程生命周期的工具

  • 降低资源消耗。通过池化技术能够重复利用已创建的线程,降低线程频繁创建和销毁造成的资源消耗
  • 提高线程的可管理性。无需程序员手动销毁线程,控制线程创建的数量,避免无限制的创建影响系统稳定性

线程池的运行机制

线程池的核心参数

  1. corePoolSize(必需):核心线程数量。默认情况下,核心线程会一直存活,但是当allowCoreThreadTimeout 设置为true时,核心线程也会超时回收
  2. maximumPoolSize(必需):最大线程数量,当线程池内的线程数量到达该数之后,后续的新任务将交由拒绝策略处理
  3. keepAliveTime(必需):线程闲置超时时长。如果闲置线程的时间超过该时长,非核心线程就会被回收,如果allowCoreThreadTimeout 设置为true时,核心线程也会超时回收
  4. unit(必需):keepAliveTime参数的时间单位
  5. workQueue(必需):线程等待队列即任务等待的队列
  6. threadFactory(可选):线程工厂,用于指定线程池创建新线程的方式
  7. handler(可选):拒绝策略,当到达最大线程数时需要执行的拒绝策略, 默认为AbortPolicy即丢弃任务并抛异常

提交任务的流程

线程池实现类——ThreadPoolExecutor

构造方法

参数说明

ThreadPoolExecutor(int corePoolSize,

int maximumPoolSize,

long keepAliveTime,

TimeUnit unit,

BlockingQueue<Runnable> workQueue)

corePoolSize:核心线程池大小

maximumPoolSize:最大线程池大小

keepAliveTime:当线程数>核心线程数时,这是 多余线程在任务执行完成后最大的存活时间

unit:时间单位

workQueue:线程等待队列即任务等待的队列

ThreadPoolExecutor(int corePoolSize,

int maximumPoolSize,

long keepAliveTime,

TimeUnit unit,

BlockingQueue<Runnable> workQueue,

ThreadFactory threadFactory)

corePoolSize:核心线程池大小

maximumPoolSize:最大线程池大小

keepAliveTime:当线程数>核心线程数时,这是 多余线程在任务执行完成后最大的存活时间

unit:时间单位

workQueue:线程等待队列即任务等待的队列

threadFactory:线程创建工厂

ThreadPoolExecutor(int corePoolSize,

int maximumPoolSize,

long keepAliveTime,

TimeUnit unit,

BlockingQueue<Runnable> workQueue,

RejectedExecutionHandler handler)

corePoolSize:核心线程池大小

maximumPoolSize:最大线程池大小

keepAliveTime:当线程数>核心线程数时,这是 多余线程在任务执行完成后最大的存活时间

unit:时间单位

workQueue:线程等待队列即任务等待的队列

handler:拒绝执行某个线程的策略LinkedBlockingQueue

LinkedBlockingQueue<Runnable>

队列默认size=Integer.MAX_VALUE,即是一个无界队列

底层实现是链表;读和写使用的是两个不同的锁,所以是读写分离的队列。

阻塞操作:

take();//当队列中无元素时,阻塞等待

put();//当队满时阻塞等待

非阻塞操作:

poll();//当队列为null时,返回null

offer();//堆满时return false;

功能线程池

Executors已经为我们封装好了四种常见的功能线程池:

  • 定长线程池(FixedThreadPool)
  • 定时线程池(ScheduledThreadPool )
  • 可缓存线程池(CachedThreadPool)
  • 单线程化线程池(SingleThreadExecutor)

从结构图中能看到四种线程池的真正实现类是ThreadPoolExecutor

线程池类型

1、newScheduledThreadPool 调度型线程池

  • 支持定时及周期性的执行任务,提交任务时支持设置任务的调度周期
  • 只限制了核心线程数,也就是最大线程数为Integer.MAX_VALUE,当添加任务的速度大于线程池处理任务的速度,可能会创建大量的线程,消耗资源,甚至导致OOM

1.1 构造

构造方法

参数

newScheduledThreadPool(int corePoolSize)

corePoolSize:corePoolSize

maximumPoolSize:Integer.MAX_VALUE

keepAliveTime:0

unit:NANOSECONDS

workQueue:DelayedWorkQueue

newScheduledThreadPool( int corePoolSize, ThreadFactory threadFactory)

1.2 任务队列-DelayedWorkQueue

  • 该队列的数据结构是优先级队列(依赖堆实现),当新来任务时将该task插入堆并根据优先级重新调整堆,保证优先级最高的task在fist index
  • 执行任务时,获取fist index中的task,并保证等待够delay时间后再执行(当fist task执行后也需要重新调整堆)

2、newCachedThreadPool 缓存型线程池

  • 无核心线程数,无非核心线程数,执行完闲置60s回收,任务队列为不存储元素的阻塞队列
  • 适用于短期异步的小任务,或负载较轻的服务器
  • 创建的最大线程数为Integer.MAX_VALUE,当添加任务的速度大于线程池处理任务的速度,可能会创建大量的线程,消耗资源,甚至导致OOM

2.1 构造方法

构造方法

参数

ExecutorService newCachedThreadPool()

参数默认值

corePoolSize:0

maximumPoolSize:Integer.MAX_VALUE

keepAliveTime:60L

unit:TimeUnit.SECONDS

workQueue:SynchronousQueue<Runnable>

ExecutorService newCachedThreadPool(ThreadFactory threadFactory)

2.2 任务队列-SynchronousQueue

  • 队列是不存储元素缓存队列的,每次要进行offer操作时必须等待poll操作,否则不能继续添加元素
  • 当前线程A执行offer操作将task添加到queue中,若没有另一个线程来消费该task,那线程A会一直阻塞直到另一个线程来消费该task

3、newFixedThreadPool

  • 创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程
  • 适用于限制当前线程数量的应用场景,适用于负载比较重的服务器
  • 创建了一个无界队列LinkedBlockingQueuesize,是一个最大值为Integer.MAX_VALUE的线程阻塞队列,当添加任务的速度大于线程池处理任务的速度,可能会在队列堆积大量的请求,消耗很大的内存,甚至导致OOM

3.1 构造方法

构造方法

参数

ExecutorService newFixedThreadPool(int nThreads)

corePoolSize:nThreads

maximumPoolSize:nThreads

keepAliveTime:0L

unit:TimeUnit.MILLISECONDS,

workQueue:LinkedBlockingQueue<Runnable>

threadFactory

ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory)

3.2 任务队列-LinkedBlockingQueue<Runnable>

  • 队列默认size=Integer.MAX_VALUE即是一个无界队列,底层实现是链表,当添加任务的速度大于线程池处理任务的速度,可能会在队列堆积大量的请求,消耗很大的内存,甚至导致OOM
  • 读和写使用的是两个不同的锁,所以是读写分离的队列

4、SingleThreadExecutor

  • 创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务,如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它
  • 此线程池保证所有任务的执行顺序按照任务的提交顺序执行

4.1 构造方法

构造方法

参数

ExecutorService newSingleThreadExecutor()

corePoolSize:1

maximumPoolSize:1

keepAliveTime:0L

unit:TimeUnit.MILLISECONDS,

workQueue:LinkedBlockingQueue<Runnable>

threadFactory

ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory)

4.2 任务队列-LinkedBlockingQueue<Runnable>

  • 队列默认size=Integer.MAX_VALUE即是一个无界队列,底层实现是链表,当添加任务的速度大于线程池处理任务的速度,可能会在队列堆积大量的请求,消耗很大的内存,甚至导致OOM
  • 读和写使用的是两个不同的锁,所以是读写分离的队列

线程池拒绝策略:

实现java.util.concurrent.RejectedExecutionHandler接口

1,CallerRunsPolicy:当想提交任务的线程池还存活,就由提交task的当前线程来执行

2,AbortPolicy:丢弃任务并抛出RejectedExecutionException异常,(默认拒绝策略)

3,DiscardPolicy:丢弃任务但是不抛异常

4,DiscardOldestPolicy:当想提交任务的线程池还存活,就将丢弃队列最前面的任务,然后重新提交被拒绝的任务

对比

类型

池内线程数量

任务队列

特点

应用场景

newScheduledThreadPool

核心线程:固定

非核心线程:无限制

DelayedWorkQueue

  1. 定时,周期性执行

执行定时/周期性任务

newCachedThreadPool

无限制

SynchronousQueue

  1. 无最大线程数限制
  2. 队列不存储元素,当没有空闲线程时会立即新建线程
  3. 当添加任务的速度大于线程池处理任务的速度,可能会创建大量的线程,消耗资源,甚至导致OOM

执行数量多,耗时少的线程任务

newFixedThreadPool

固定

LinkedBlockingQueue

  1. 每来一个任务就会新建线程,直到线程数到达指定的数量
  2. 核心线程数处于空闲状态也不会被回收,除非线程关闭
  3. 当所有线程都处于活跃状态,新的任务都会处于等待状态,直到有线程空闲出来
  4. 任务队列无限制

控制线程的最大并发数

newSingleThreadExecutor

1个

LinkedBlockingQueue

  1. 保证所有任务按照指定顺序在一个线程中方执行
  2. 不需要处理线程同步的问题

单线程

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

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

相关文章

找不到kotlin.Pair的类文件

需要添加kotlin的依赖&#xff1a; implementation "org.jetbrains.kotlin:kotlin-stdlib:1.8.22"

OpenHarmony上移植memtester

1. 下载源码&#xff1a; wget https://pyropus.ca./software/memtester/old-versions/memtester-4.6.0.tar.gz 2. 解压并指定交叉编译方式 解压 tar -xvf memtester-4.6.0.tar.gz 修改conf-cc和conf-ld&#xff0c;指定交叉编译方式 conf-cc conf-ld 3. 编译 直接运行m…

Ubuntu安装ZLMediaKit

方式一 1、安装vcpkg 在Ubuntu上安装vcpkg的步骤如下&#xff1a; 安装必要的依赖&#xff1a; 首先&#xff0c;你可能需要安装cmake和ninja-build。你可以使用apt包管理器来安装它们&#xff1a; bash复制代码sudo apt install cmake ninja-build下载vcpkg源码&#xff1a;…

后端开发面经系列 -- 阿里C++二面面经

阿里C二面面经 公众号&#xff1a;阿Q技术站 来源&#xff1a;https://www.nowcoder.com/feed/main/detail/fc4a48403b534aafa6a6bce14b542c4e?sourceSSRsearch 1、智能指针&#xff1f; std::shared_ptr&#xff1a; 原理&#xff1a;std::shared_ptr是基于引用计数的智能指…

Stable Diffusion入门使用技巧及个人实例分享--大模型及lora篇

大家好&#xff0c;近期使用Stable Diffusion比较多&#xff0c;积累整理了一些内容&#xff0c;得空分享给大家。如果你近期正好在关注AI绘画领域&#xff0c;可以看看哦。 本文比较适合已经解决了安装问题&#xff0c;&#xff08;没有安装的在文末领取&#xff09; 在寻找合…

【RAG】Linux系统下ppt转pptx,读取解析pptx文本数据

前情提要 检索增强生成&#xff08;RAG&#xff09;技术&#xff0c;作为 AI 领域的尖端技术&#xff0c;能够提供可靠且最新的外部知识&#xff0c;极大地便利了各种任务。在 AI 内容生成的浪潮中&#xff0c;RAG 通过其强大的检索能力为生成式 AI 提供了额外的知识&#xff…

vue3 动态加载页面

首先&#xff0c;通过下面代码告诉编译器要编译哪些页面 static modules import.meta.glob(./views/**/*.vue);然后动态加载函数这样写&#xff1a; static asyncLoadView (path: string) > {return defineAsyncComponent({loader: <any>Global.modules[./views/${…

Redis的跳表:高效实现有序集合

在 Redis 中&#xff0c;跳表&#xff08;Skip List&#xff09;是一种常用的数据结构&#xff0c;用于实现有序集合&#xff08;Sorted Set&#xff09;。跳表是一种基于链表的数据结构&#xff0c;具有快速的查找、插入和删除操作&#xff0c;适用于有序集合的实现。 本文将…

分布式搜索——ElasticSeach简介

一般都用数据库存储数据&#xff0c;然后对数据库进行查询获取数据&#xff0c;但是当数据量很大时&#xff0c;查询效率就会很慢&#xff08;具体下面会讲到&#xff09;&#xff0c;所以这种情况下就会使用到ElasticSeach ElasticSeach的基本介绍 ElasticSeach是一 款非常强…

2024重庆高等教育博览会|2024重庆高教展|全国高等教育博览会

2024重庆高等教育博览会|2024重庆高教展|全国高等教育博览会 第62届全国高等教育博览会&#xff08;2024.秋季重庆&#xff09; 时间&#xff1a;2024年11月15-17日 地点&#xff1a;重庆国际博览中心 组织机构 主办单位&#xff1a;中国高等教育学会 承办单位&#xff1a;国药…

杰发科技AC7801——ADC之Bandgap和内部温度计算

0. 参考 电流模架构Bandgap设计与仿真 bandgap的理解&#xff08;内部带隙电压基准&#xff09; ​ ​ 虽然看不懂这些公式&#xff0c;但是比较重要的一句应该是这个&#xff1a;因为传统带隙基准的输出值为1.2V ​ 1. 使用 参考示例代码。 40002000是falsh控制器寄…

NXP RT1176(一)——二级BootLoader开发(安全引导加载程序SBL)

目录 1. 开发环境 2. 二级BOOT的功能 3. 步骤 3.1 配置源码 3.2 构建项目 3.2.1 MDK 3.2.2 IAR&#xff08;IAR也编译一下工程看看&#xff0c;这样两个平台都可以支持了&#xff09; 单核M7的开发&#xff01;&#xff01; 1. 开发环境 本文Windows下开发&#xff1a;…

【无标题】vo dto

在Java中&#xff0c;VO、PO、DTO都是常用的数据对象模型。 VO&#xff08;Value Object&#xff09;是值对象&#xff0c;通常用于表示一个业务实体或者页面展示的内容。VO通常包含了多个属性&#xff0c;并且这些属性的类型和名称与业务相关。VO并不一定与数据库中的表结构相…

MHD、MQA、GQA注意力机制详解

MHD、MQA、GQA注意力机制详解 注意力机制详解及代码前言&#xff1a;MHAMQAGQA 注意力机制详解及代码 前言&#xff1a; 自回归解码器推理是 Transformer 模型的 一个严重瓶颈&#xff0c;因为在每个解码步骤中加 载解码器权重以及所有注意键和值会产生 内存带宽开销 下图为三…

巩固学习8

在 Pandas 中&#xff0c;sep参数用于指定数据中字段之间的分隔符。常见的参数包括&#xff1a; 逗号&#xff1a;,&#xff0c;常用于CSV文件。 制表符&#xff1a;\t&#xff0c;常用于TSV文件。 空格&#xff1a;’ &#xff0c;用于空格分隔的数据。 分号&#xff1a;;&…

【合成孔径雷达】合成孔径雷达的多视角理解和时/频成像算法的统一解释

文章目录 一、什么是雷达成像&#xff08;1&#xff09;主要的遥感探测手段&#xff1a;光学、红外和雷达&#xff08;2&#xff09;从数学的角度&#xff1a;雷达成像主要研究什么&#xff1f;数据采集&#xff1a; y T x n yTxn yTxn信息提取&#xff1a; y − > x ? y…

编译错误:stray ‘\357’ in program的解决方法

目录 把报错文件更换编码格式&#xff0c;我试的utf-8 bom编码就可以了&#xff0c;可以多换几种试试。 网友的另一种案例&#xff1a; 编译错误&#xff1a;stray ‘\357’ in program的解决方法 把报错文件更换编码格式&#xff0c;我试的utf-8 bom编码就可以了&#xff0c…

LabVIEW做仪器测试不知道是否适用

LabVIEW&#xff08;Laboratory Virtual Instrument Engineering Workbench&#xff09;是一个用于系统工程和测量系统的图形编程平台&#xff0c;由National Instruments开发。它非常适用于仪器控制、数据采集、信号处理以及自动化测试与测量系统的开发。如果您的工作涉及到这…

如何同步管理1000个设备的VLAN数据?

什么是VLAN&#xff1f; VLAN&#xff0c;也就是虚拟局域网&#xff0c;是通过为子网提供数据链路连接来抽象出局域网的概念。在企业网中&#xff0c;一个企业级交换机一般是24口或者是48口&#xff0c;连接这些接口的终端在物理上形成一个广播域。广播域过大&#xff0c;就会导…

【AI智能体】零代码构建AI应用,全网都在喊话歌手谁能应战,一键AI制作歌手信息查询应用

欢迎来到《小5讲堂》 这是《文心智能体平台》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 文心智能体大赛背景创建应用平台地址快速构建【基础配置】…