Java并发篇--线程池

线程池

在这里插入图片描述

为什么要创建线程池

因为CPU核心数量有限,如果每来一个任务就创建一个线程,就会使线程数远远多于CPU核心数,使线程上下文切换过于频繁,会导致系统性能降低。而且每创建一个线程都会占用一定的内存,如果每来一个任务就创建一个线程,内存消耗太大了。

ThreadPoolExecutor

在这里插入图片描述

1.线程池状态

ThreadPoolExecutor使用int的高3位来表示线程状态,低29位表示线程数量

在这里插入图片描述

从数字上比较,TERMINATED>TIDYING>STOP>SHUTDOWN>RUNNING(因为高3位所以111最小)

这些信息存储在一个原子变量ctl中,目的是将线程状态与线程个数合二为一,这样就可以用一次cas原子操作进行赋值

// c为旧值,ctlOf返回结果为新值
ctl.compareAndSet(c,ctlOf(targetState,workerCountOf(c)));
// rs 为高 3 位代表线程状态,wc为低29位代表线程个数,ctl是合并它们
private static int ctlOf(int res,int wc){return res | wc;
}

2.构造方法

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

· corePoolSize核心线程数目(最多保留的线程数)

· maximumPoolSize 最大线程数目(核心线程数加救急线程数)

· keepAliveTime 生存时间 - 针对救急线程

· unit 时间单位 - 针对救急线程

· workQueue 阻塞队列

· threadFactory 线程工厂 - 可以为线程创建时起个好名字

· handler 拒绝策略

工作方式

在这里插入图片描述

当核心线程数不够用,新来的任务就会进入阻塞队列中等待执行。在这里插入图片描述

当阻塞队列达到上限时,还新来任务,这时救急线程就会将新来的任务执行在这里插入图片描述

当任务5执行完后(过完生存时间)救急线程就会被回收,等到下回需要时再重新创建。核心线程被创建后就不会被回收了,一直存在于线程池中。

如果拒绝队列选择了有界队列,那么任务超过了队列大小时,会创建救急线程

当急救线程也被占满时,这时再来的任务就会采取拒绝策略了,jdk提供了四种拒绝策略(前四种)

· AbortPolicy 让调用者抛出 RejecedtExecutionException异常,这是默认策略

· CallerRunsPolicy 让调用者运行任务

· DiscardPolicy 放弃本次任务

· DiscardOldestPolicy 放弃队列中最早的任务,本任务取而代之

· Dubbo 的实现,在抛出RejectedExecutionException 异常之前会记录日志,并dump线程栈信息,方便定位问题

· Netty 的实现,是创建一个新线程来执行任务

· AcitveMQ的实现,带超时等待(60s)尝试放入队列,类似我们之前自定义的拒绝策略(自定义线程池的文章有)

· PinPoint的实现,它使用了一个拒绝策略链,会逐一尝试策略链中每种拒绝策略

当高峰过去后,超过corePoolSize的急救线程如果一段时间没有任务做,需要结束节省资源,这个时间由keepAliveTime 和 unit来控制。

在这里插入图片描述

根据这个构造方法,JDK Executors类中提供了众多工厂方法来创建各种用途的线程池

3.newFixedThreadPool

public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
}

特点

· 核心线程数 == 最大线程数(没有救急线程被创建),因此也无需超时时间

· 阻塞队列是无界的,可以放任意数量的任务

测试代码

public static void main(String[] args) {ExecutorService pool = Executors.newFixedThreadPool(2, new ThreadFactory() {AtomicInteger arr = new AtomicInteger(1);@Overridepublic Thread newThread(Runnable r) {// 通过线程工厂对线程进行改名return new Thread(r,"mypool_t "+arr.getAndIncrement());}});pool.execute(()->{log.debug("1");});pool.execute(()->{log.debug("2");});pool.execute(()->{log.debug("3");});}

评价

适用于任务量已知,相对耗时的任务

4.newCachedThreadPool

public static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());
}

特点

核心线程数是0,最大线程数是Integer.MAX_VALUE,救急线程的空闲生存时间是60s。(意味着全部都是急救线程,60后可以回收。急救线程可以无限创建)

队列采用了SynchronousQueue实现特点,它没有容量,没有线程来取是放不进去的(一手交钱、一手交货)

SynchronousQueue代码实现

public static void main(String[] args) throws InterruptedException {SynchronousQueue<Integer> integers = new SynchronousQueue<>();new Thread(()->{try {log.debug("putting {}",1);integers.put(1);log.debug("{} putted...",1);log.debug("putting {}",2);integers.put(2);log.debug("{} putted...",2);} catch (InterruptedException e) {e.printStackTrace();}},"t1").start();Thread.sleep(1000);new Thread(()->{try {log.debug("take {}",1);integers.take();} catch (InterruptedException e) {e.printStackTrace();}},"t2").start();Thread.sleep(1000);new Thread(()->{try {log.debug("take {}",2);integers.take();} catch (InterruptedException e) {e.printStackTrace();}},"t3").start();
}

输出结果

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

评价

整个线程池表现为线程数会根据任务量不断增长,没有上限,当任务执行完毕,空闲1分钟后释放线程。

适合任务数比较密集,但每个任务执行时间较短的情况

5.newSingleThreadExecutor

public static ExecutorService newSingleThreadExecutor() {return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()));
}

使用场景

希望多个任务排队执行。线程数固定为1,任务数多于1时,会放入无界队列排队。任务执行完毕,这唯一的线程也不会被释放。

与自己创建一个线程的区别

自己创建一个单线程穿行执行任务,如果任务执行失败而终止那么没有任何补救措施,而线程池还会新建一个线程,保证池的正常工作

Executors.newSingleThreadExecutor()线程个数始终为1,不能修改

​ · FinalizeableDelegatedExecutorService 应用的是装饰器模式,只对外暴露了ExecutorService接口,因此不能调用ThreadPoolExecutor 中特有的方法

Executors.newFixedThreadPool(1) 初始时为1,以后还可以修改

​ · 对外暴露的是ThreadPoolExecutor对象,可以强制后调用setCorePoolSize 等方法进行修改

6.提交任务

// 执行任务
void execute(Runnable command);
// 提交任务task,用返回值Future获得任务执行结果
<T> Future<T> submit(Callable<T> task);
// 提交 tasks 中所有任务
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)throws InterruptedException;
// 提交tasks 中所有任务,带超时时间
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,long timeout, TimeUnit unit)throws InterruptedException;
//提交tasks中所有任务,哪个任务先成功执行完毕,返回此任务执行结果,其它任务取消
<T> T invokeAny(Collection<? extends Callable<T>> tasks)throws InterruptedException,ExecutionException;
// 提交tasks中所有任务,哪个任务先成功执行完毕,返回此任务执行结果,其它任务取消,带超时时间
<T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout,TimeUnit unit)throws InterruptedException,ExecutionException,TimeoutException;

7.关闭线程池

shutdown

让线程执行完shutdown之前的任务再停止。

/*线程池状态变为SHUTDOWN- 不会接收新方法- 但已经提交任务会执行完- 此方法不会阻塞调用线程的执行
*/
void shutdown();
public void shutdown() {final ReentrantLock mainLock = this.mainLock;mainLock.lock();try {checkShutdownAccess();// 修改线程状态advanceRunState(SHUTDOWN);// 仅会打断空空闲线程interruptIdleWorkers();onShutdown(); // 扩展点 ScheduledThreadPoolExecutor} finally {mainLock.unlock();}// 尝试终结(没有运行的线程可以立刻终结,如果还有运行的线程也不会等)tryTerminate();
}

shutdownNow

让所有任务都终止,就连当前执行的线程也终止,阻塞队列中的任务会当作返回值返回。

/*线程池状态变为STOP- 不会接收新任务- 会将队列中的任务返回- 并用interrupt的方式中断正在执行的任务
*/
List<Runnable> shutdownNow();
 public List<Runnable> shutdownNow() {List<Runnable> tasks;final ReentrantLock mainLock = this.mainLock;mainLock.lock();try {checkShutdownAccess();// 修改线程状态advanceRunState(STOP);// 打断所有线程interruptWorkers();// 获取队列中剩余任务tasks = drainQueue();} finally {mainLock.unlock();}// 尝试终结tryTerminate();return tasks;}

其它方法

// 不在 RUNNING 状态的线程池,此方法就返回true
public boolean isShutdown();
// 线程池状态是否是TERMINATED
public boolean isTerminated();
//调用 shutdown 后,由于调用线程并不会等待所有任务运行结束,因此如果它想在线程池TERMINATED后做些事情,可以利用此方法等待
public boolean awaitTermination(long timeout, TimeUnit unit);

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

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

相关文章

ubontu--cuDNN安装

1. 下载 cuDNN https://developer.nvidia.com/cudnn 2. 拷贝到服务器/home/<username>文件夹下 解压缩到当前文件夹&#xff1a; tar -xvf cudnn-linux-x86_64-9.5.1.17_cuda11-archive.tar.xz复制头文件和库文件到cuda安装目录/usr/local/cuda/ sudo cp /home/usern…

Mac终端使用brew命令报错:zsh: command not found: brew

当在终端中出现 zsh: command not found: brew 这个错误时&#xff0c;可能是因为 Homebrew 没有被正确安装&#xff0c;或者它的路径没有被添加到环境变量中。 1. 检查 Homebrew 是否已安装&#xff1a; 打开终端&#xff0c;运行以下命令来检查 Homebrew 是否已安装&#xf…

斯坦福iDP3——改进3D扩散策略以赋能人形机器人的训练:不再依赖相机校准和点云分割(含源码解析)

前言 今天10.23日&#xff0c;明天1024则将作为长沙程序员代表&#xff0c;在CSDN和长沙相关部门举办的1024程序员节开幕式上发言&#xff0c;欢迎广大开发者来长工作 生活 考察 创业&#xff0c;​包括我司七月也一直在招聘大模型与机器人开发人员 后天&#xff0c;则将和相关…

Vue3 -- 项目配置之eslint【企业级项目配置保姆级教程1】

下面是项目级完整配置1➡eslint:【吐血分享,博主踩过的坑你跳过去!!跳不过去?太过分了给博主打钱】 浏览器自动打开项目: 你想释放双手吗?你想每天早上打开电脑运行完项目自动在浏览器打开吗?不要9998,不要998,只要你在我们爱的 package.json 中配置一下即可显示。如…

DataWorks on EMR StarRocks,打造标准湖仓新范式

在大数据领域&#xff0c;数据仓库和实时分析系统扮演着至关重要的角色。DataWorks 基于大数据引擎&#xff0c;为数据仓库/数据湖/湖仓一体等解决方案提供统一的全链路大数据开发治理平台&#xff0c;为用户带来智能化的数据开发和分析体验。而阿里云提供的 EMR Serverless St…

谷歌浏览器的实验性功能介绍

谷歌浏览器&#xff08;Google Chrome&#xff09;作为全球最受欢迎的网络浏览器之一&#xff0c;以其快速、稳定和丰富的扩展功能而闻名。除了常见的功能外&#xff0c;Chrome还提供了许多实验性功能&#xff0c;这些功能可以通过启用一些隐藏的标志来访问。本文将详细介绍如何…

Acrobat Pro DC 2023(pdf免费转化word)

所在位置 通过网盘分享的文件&#xff1a;Acrobat Pro DC 2023(64bit).tar 链接: https://pan.baidu.com/s/1_m8TT1rHTtp5YnU8F0QGXQ 提取码: 1234 --来自百度网盘超级会员v4的分享 安装流程 打开安装所在位置 进入安装程序 找到安装程序 进入后点击自定义安装&#xff0c;这里…

【论文复现】STM32设计的物联网智能鱼缸

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀STM32设计的物联网智能鱼缸 【1】项目功能介绍【2】设计需求总结【3】项目硬件模块组成 1.2 设计思路【1】整体设计思路【2】ESP8266工作模式…

Elasticsearch 和 Kibana 8.16:Kibana 获得上下文和 BBQ 速度并节省开支!

作者&#xff1a;来自 Elastic Platform Product Team Elastic Search AI 平台&#xff08;Elasticsearch、Kibana 和机器学习&#xff09;的 8.16 版本包含大量新功能&#xff0c;可提高性能、优化工作流程和简化数据管理。 使用更好的二进制量化 (Better Binary Quantizatio…

ubuntu20.04安装FLIR灰点相机BFS-PGE-16S2C-CS的ROS驱动

一、Spinnaker 安装 1.1Spinnaker 下载 下载地址为&#xff1a; https://www.teledynevisionsolutions.com/support/support-center/software-firmware-downloads/iis/spinnaker-sdk-download/spinnaker-sdk–download-files/?pnSpinnakerSDK&vnSpinnakerSDK 在上述地址中…

OCR+多模态数据技术,赋能海洋数据智能处理

海洋是推动高质量发展的关键区域&#xff0c;也是人类未来发展的宝库。然而&#xff0c;我们对海洋生态系统的深入理解尚不足5%。海洋大数据&#xff0c;通过观测、监测、调查、分析和统计等手段获得&#xff0c;已成为我们探索海洋世界的主要工具。 如图1所示&#xff0…

JUC学习笔记

文章目录 锁生产者消费者问题8锁现象集合类不安全Callable创建线程的三种方式 常用辅助类CountDownLatchCyclibarrierSamphore 本篇博客是之前学习JUC时记录的内容&#xff0c;对于并发编程知识只是浅浅谈及&#xff0c;并不深入。也算是给自己开新坑。建一个JUC的专栏&#xf…

集合卡尔曼滤波(EnsembleKalmanFilter)的MATLAB例程(三维、二维)

本 M A T L A B MATLAB MATLAB代码实现了一个三维动态系统的集合卡尔曼滤波&#xff08;Ensemble Kalman Filter, EnKF&#xff09;示例。代码的主要目的是通过模拟真实状态和测量值&#xff0c;使用 EnKF 方法对动态系统状态进行估计。 文章目录 参数设置初始化真实状态定义状…

OpenGL ES 共享上下文实现多线程渲染

OpenGL ES 共享上下文时,可以共享哪些资源? 共享上下文实现多线程渲染 EGL 概念回顾 EGL 是 OpenGL ES 和本地窗口系统(Native Window System)之间的通信接口,它的主要作用: 与设备的原生窗口系统通信; 查询绘图表面的可用类型和配置; 创建绘图表面; 在OpenGL ES 和…

如何安装和使用SSH远程连接工具MobaXterm

文章目录 一、下载二、安装三、使用四、配置1、配置默认编辑器2、配置右键粘贴3、SSH配置4、关闭X-Server服务 一、下载 1、进入官网&#xff1a;https://mobaxterm.mobatek.net/download-home-edition.html 2、Download——>Home Edition。 3、下载绿色安装版本。 二、安…

Java项目实战II基于微信小程序的原创音乐小程序(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 随着移动互…

linux-文件的读写

操作系统一切皆文件&#xff0c;访问文件实际上就是访问硬件&#xff0c;因为文件都保存在硬件上&#xff0c;或者文件就是硬件&#xff0c;而要访问硬件&#xff0c;就需要操作系统提供的系统调用&#xff0c;所以c/c函数中关于访问硬件设备&#xff0c;基本上是由系统调用封装…

「实战应用」如何可视化 DHTMLX Scheduler 中的资源工作量?

DHTMLX Scheduler是一个全面的 UI 组件&#xff0c;用于处理面向业务的 Web 应用程序中复杂的调度和任务管理需求。但是&#xff0c;某些场景可能需要自定义解决方案。例如&#xff0c;如果项目的资源&#xff08;即劳动力&#xff09;有限&#xff0c;则需要确保以更高的精度分…

RNA-seq 差异分析的点点滴滴(2)

引言 本系列[1]将开展全新的转录组分析专栏&#xff0c;主要针对使用DESeq2时可能出现的问题和方法进行展开。 Tximeta&#xff1a;自动导入并附加元数据 Bioconductor 家族中的 tximeta 包&#xff0c;在 tximport 的基础上进行了扩展&#xff0c;不仅保留了原有功能&#xff…

Pycharm PyQt5 环境搭建创建第一个Hello程序

第一步: 创建Pycharm项目,下载包: pip install PyQt5 -i https://pypi.tuna.tsinghua.edu.cn/simple/pip install PyQt5-tools -i https://pypi.tuna.tsinghua.edu.cn/simple/下载好了之后,可以看到相应包: PyQt5:PyQt5是一套Python绑定Digia QT5应用的框架。Qt库是最…