java干货 线程池的分析和使用

文章目录

    • 一、了解线程池
      • 1.1 什么是线程池
      • 1.2 为什么需要线程池
    • 二、四种线程池的使用
      • 2.1 newFixedThreadPool
      • 2.2 newCachedThreadPool
      • 2.3 newSingleThreadExecutor
      • 2.4 newScheduledThreadPool
    • 三、自定义线程池
      • 3.1 线程池七大核心参数
      • 3.2 线程池内部处理逻辑

一、了解线程池

1.1 什么是线程池

线程池就是一个装有多个线程的容器,我们不需要关心线程的创建,在需要时从线程池获取线程来执行即可。线程池提前创建和维护了一定数量的线程,避免线程频繁创建和销毁带来的性能损耗,同时能提高响应速度。

1.2 为什么需要线程池

我们需要一个线程来执行任务,直接 new 一个不就好了吗?确实是这样,写个demo直接创建线程就好,没必要线程池。但是在并发环境下需要创建多个线程来执行任务,每个线程执行的时间都很短,频繁的创建和销毁线程会耗费时间,因此需要线程池

二、四种线程池的使用

2.1 newFixedThreadPool

创建固定线程数量的线程池

  • newFixedThreadPool(int nThreads) 源码
public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());}
  • 实际调用 ThreadPoolExecutor,七大参数
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue) {this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,Executors.defaultThreadFactory(), defaultHandler);}
  • 特点

    • 每个线程都是核心线程
    • 使用默认的线程工厂
    • 使用默认的拒绝策略
  • 使用

class TaskRunnable implements Runnable{private static int ticketCount = 5;@Overridepublic synchronized void run() {if(ticketCount > 0){System.out.println(Thread.currentThread().getName() + " 售出第" + ticketCount + "张票");ticketCount--;}else {System.out.println(Thread.currentThread().getName()  + "没票了");}}
}
public class Demo12 {public static void main(String[] args) {TaskRunnable taskRunnable = new TaskRunnable();ExecutorService executorService = Executors.newFixedThreadPool(3);for (int i = 0; i < 8; i++) {executorService.submit(taskRunnable);}}
}
pool-1-thread-2 售出第5张票
pool-1-thread-1 售出第4张票
pool-1-thread-3 售出第3张票
pool-1-thread-3 售出第2张票
pool-1-thread-3 售出第1张票
pool-1-thread-1没票了
pool-1-thread-2没票了
pool-1-thread-3没票了

分析:提交八个任务,由三个线程完成。

2.2 newCachedThreadPool

只要有任务需要处理,线程池可以无限制地创建新线程,如果有空闲的线程可以复用,则不会创建新线程。

  • newCachedThreadPool() 源码
public static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());}
  • 实际调用 ThreadPoolExecutor 七大参数
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue) {this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,Executors.defaultThreadFactory(), defaultHandler);}
  • 特点

    • 无核心线程
    • 根据需要动态扩缩容
    • 默认情况下,空闲线程的存活时间为 60 秒。如果线程在 60 秒内没有被使用,将被终止并从缓存中移除
  • 使用

class TaskRunnable implements Runnable{private static int ticketCount = 5;@Overridepublic synchronized void run() {if(ticketCount > 0){System.out.println(Thread.currentThread().getName() + " 售出第" + ticketCount + "张票");ticketCount--;}else {System.out.println(Thread.currentThread().getName()  + "没票了");}}
}
public class Demo12 {public static void main(String[] args) throws InterruptedException {TaskRunnable taskRunnable = new TaskRunnable();ExecutorService executorService = Executors.newCachedThreadPool();for (int i = 0; i < 10; i++) {executorService.submit(taskRunnable);}Thread.sleep(2000);System.out.println("-----------------------------继续提交-----------------------------------");for (int i = 0; i < 15; i++) {executorService.submit(taskRunnable);}}
}
pool-1-thread-3 售出第5张票
pool-1-thread-10 售出第4张票
pool-1-thread-9 售出第3张票
pool-1-thread-8 售出第2张票
pool-1-thread-7 售出第1张票
pool-1-thread-6没票了
pool-1-thread-2没票了
pool-1-thread-4没票了
pool-1-thread-5没票了
pool-1-thread-1没票了
-----------------------------继续提交-----------------------------------
pool-1-thread-7没票了
pool-1-thread-1没票了
pool-1-thread-6没票了
pool-1-thread-7没票了
pool-1-thread-9没票了
pool-1-thread-3没票了
pool-1-thread-8没票了
pool-1-thread-2没票了
pool-1-thread-12没票了
pool-1-thread-10没票了
pool-1-thread-4没票了
pool-1-thread-7没票了
pool-1-thread-11没票了
pool-1-thread-1没票了
pool-1-thread-5没票了

分析:可以发现提交十个任务,就创建了十个线程。在继续提交十五个任务时,会复用之前的十个线程,由于线程不够,继续创建了第十一和第十二个线程。

2.3 newSingleThreadExecutor

线程池中只有一个线程

  • newSingleThreadExecutor() 源码
public static ExecutorService newSingleThreadExecutor() {return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()));}
  • 实际调用 ThreadPoolExecutor 七大参数
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue) {this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,Executors.defaultThreadFactory(), defaultHandler);}
  • 特点

    • 只有一个线程,该线程也是核心线程
    • 适用于同步场景
  • 使用

class TaskRunnable implements Runnable{private static int ticketCount = 5;@Overridepublic synchronized void run() {if(ticketCount > 0){System.out.println(Thread.currentThread().getName() + " 售出第" + ticketCount + "张票");ticketCount--;}else {System.out.println(Thread.currentThread().getName()  + "没票了");}}
}
public class Demo12 {public static void main(String[] args) throws InterruptedException {TaskRunnable taskRunnable = new TaskRunnable();ExecutorService executorService = Executors.newSingleThreadExecutor();for (int i = 0; i < 10; i++) {executorService.submit(taskRunnable);}}
}
pool-1-thread-1 售出第5张票
pool-1-thread-1 售出第4张票
pool-1-thread-1 售出第3张票
pool-1-thread-1 售出第2张票
pool-1-thread-1 售出第1张票
pool-1-thread-1没票了
pool-1-thread-1没票了
pool-1-thread-1没票了
pool-1-thread-1没票了
pool-1-thread-1没票了

分析:可以看出只有一个线程在执行任务,是串行

2.4 newScheduledThreadPool

延迟执行、定时执行

  • newScheduledThreadPool(核心线程数) 源码
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {return new ScheduledThreadPoolExecutor(corePoolSize);}
  • 实际调用 ScheduledThreadPoolExecutor(int corePoolSize)
public ScheduledThreadPoolExecutor(int corePoolSize) {super(corePoolSize, Integer.MAX_VALUE,DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,new DelayedWorkQueue());}
  • 使用
class TaskRunnable implements Runnable{private static int ticketCount = 5;@Overridepublic synchronized void run() {if(ticketCount > 0){System.out.println(Thread.currentThread().getName() + " 售出第" + ticketCount + "张票");ticketCount--;}else {System.out.println(Thread.currentThread().getName()  + "没票了");}}
}
public class Demo12 {public static void main(String[] args) throws InterruptedException {TaskRunnable taskRunnable = new TaskRunnable();ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);for (int i = 0; i < 10; i++) {scheduledExecutorService.schedule(taskRunnable,3, TimeUnit.SECONDS);}}
}

分析:延迟,3 秒后执行。

  • scheduleAtFixedRate,1 秒后执行,每两秒执行一次
scheduledExecutorService.scheduleAtFixedRate(taskRunnable,1,2,TimeUnit.SECONDS);
  • 初始延迟为 0 秒。每次任务执行完成后,等待 2 秒再开始下一次执行。任务模拟执行时间为 2 秒。
scheduledExecutorService.scheduleWithFixedDelay(taskRunnable,0,2,TimeUnit.SECONDS);

-shutdown() :线程池不再接受新任务,但会继续执行已经提交的任务,直到所有任务执行完毕。

  • awaitTermination(2,TimeUnit.SECONDS) 判断2 秒内是否能完成全部任务

三、自定义线程池

3.1 线程池七大核心参数

  • 源码
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) {if (corePoolSize < 0 ||maximumPoolSize <= 0 ||maximumPoolSize < corePoolSize ||keepAliveTime < 0)throw new IllegalArgumentException();if (workQueue == null || threadFactory == null || handler == null)throw new NullPointerException();this.corePoolSize = corePoolSize;this.maximumPoolSize = maximumPoolSize;this.workQueue = workQueue;this.keepAliveTime = unit.toNanos(keepAliveTime);this.threadFactory = threadFactory;this.handler = handler;}

参数说明

  • 1.corePoolSize :核心线程数
  • 2.maximumPoolSize:最大线程数(核心线程数 + 核心线程数)
  • 3.keepAliveTime :非核心线程空闲时间,没有任务处理空闲超过该时间,线程会处于终止状态
  • 4.TimeUnit : 空闲时间单位
  • 5.BlockingQueue workQueue :任务队列
  • 6.ThreadFactory :线程工厂
  • 7.RejectedExecutionHandler :拒绝策略

3.2 线程池内部处理逻辑

三问:

  • 先问核心线程还够不够用
  • 再问任务队列是否已满
  • 最后问是否已达到最大线程数
  • 如果任务队列已满,那么创建非核心线程
  • 如果任务队列已满,同时达到最大线程数,再添加任务,则执行拒绝策略。

创建和使用自定义线程池

class TaskRunnable implements Runnable{private static int ticketCount = 5;@Overridepublic synchronized void run() {if(ticketCount > 0){System.out.println(Thread.currentThread().getName() + " 售出第" + ticketCount + "张票");ticketCount--;}else {System.out.println(Thread.currentThread().getName()  + "没票了");}try {Thread.sleep(1000); // 模拟做其他事情} catch (InterruptedException e) {e.printStackTrace();}}
}
public class Demo12 {public static void main(String[] args) throws InterruptedException {// 核心线程数int corePoolSize = 2;// 最大线程数int maximumPoolSize = 4;// 线程空闲时间long keepAliveTime = 10;// 时间单位TimeUnit unit = TimeUnit.SECONDS;// 工作队列BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(2);// 线程工厂ThreadFactory threadFactory = Executors.defaultThreadFactory();// 拒绝策略RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();// 创建自定义线程池ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);TaskRunnable taskRunnable = new TaskRunnable();for (int i = 0;i < 6; i++){executor.execute(taskRunnable);}}
}
  • 当提交的任务数 <= (最大线程数 + 任务队列大小),能正常工作
pool-1-thread-1 售出第5张票
pool-1-thread-4 售出第4张票
pool-1-thread-3 售出第3张票
pool-1-thread-2 售出第2张票
pool-1-thread-4 售出第1张票
pool-1-thread-1没票了
  • 当提交的任务数 > (最大线程数 + 任务队列大小),触发拒绝策略
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task com.binbin.usethread.TaskRunnable@34a245ab rejected from java.util.concurrent.ThreadPoolExecutor@7cc355be[Running, pool size = 4, active threads = 4, queued tasks = 2, completed tasks = 0]at java.base/java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2065)at java.base/java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:833)at java.base/java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1365)at com.binbin.usethread.Demo12.main(Demo12.java:50)
pool-1-thread-1 售出第5张票
pool-1-thread-4 售出第4张票
pool-1-thread-3 售出第3张票
pool-1-thread-2 售出第2张票
pool-1-thread-4 售出第1张票
pool-1-thread-1没票了

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

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

相关文章

Leetcode - 132双周赛

目录 一、3174. 清除数字 二、3175. 找到连续赢 K 场比赛的第一位玩家 三、3176. 求出最长好子序列 I 四、3177. 求出最长好子序列 II 一、3174. 清除数字 本题可以使用栈来模拟&#xff0c;遇到数字弹出栈顶元素&#xff0c;遇到字母入栈。 代码如下&#xff1a; //使用字…

VMware虚拟机卡顿(虚拟机卡死)(调整所有虚拟机内存使其适应预留的主机 RAM (F)、默认进程优先级、不允许使用内存页面修整功能(M))

文章目录 设置编辑——首选项——内存——额外内存——调整所有虚拟机内存使其适应预留的主机 RAM (F)&#xff08;我把这个勾上了&#xff09;编辑——首选项——优先级——默认进程优先级虚拟机——设置——选项——高级——不允许使用内存页面修整功能(M) 参考文章&#xff…

数据结构和算法之复杂度比较

数据结构和算法之复杂度比较 参考如下网址&#xff1a;https://www.bigocheatsheet.com/ 方便快速查询 1. 复杂度比较 2. 常见数据结构复杂度 3. 常见算法复杂度

【AI应用探讨】— 通义千问模型应用场景

目录 一、文字创作 二、文本处理 三、编程辅助 四、翻译服务 五、对话模拟 六、数据可视化 七、电商行业应用 八、教育行业应用 九、开发者与科研工作者应用 一、文字创作 故事、公文、邮件撰写&#xff1a;通义千问能够基于用户的指令和需求&#xff0c;生成符合要求…

如何用命令行方式便捷组合调用 AI 工作流?

&#xff08;注&#xff1a;本文为小报童精选文章。已订阅小报童或加入知识星球「玉树芝兰」用户请勿重复付费&#xff09; 我给你演示的总结长视频、起草博客文章&#xff0c;只是其中的冰山一角。 焦虑 有些小伙伴最近跟我反馈&#xff0c;看到他人演示的样例&#xff0c;见识…

VScode中js关闭烦人的ts检查

类似如下的代码在vscode 会报错&#xff0c;我们可以在前面添加忽略检查或者错误&#xff0c;如下&#xff1a; 但是&#xff01;&#xff01;&#xff01;这太不优雅了&#xff01;&#xff01;&#xff01;&#xff0c;js代码命名没有问题&#xff0c;错在ts上面&#xff0c;…

文案生成器,免费的文案生成器

在如今这个高速发展的社会&#xff0c;内容创作已经成为许多人工作和生活中不可或缺的一部分。然而&#xff0c;随之而来的就是“内卷”。不仅要高质量的内容还要写作效率。为了在内卷中脱颖而出&#xff0c;我们就需要使用文案生成器&#xff0c;一款能够帮助我们提升写作效率…

element-plus的Tour 漫游式引导怎么去绑定Cascader 级联选择器或者它的内容 popper

首先官方例子是用的button 官方.$el这个log出来是&#xff1a; 知道是以元素为准就拿对应的元素就行 级联选择器.$el是这样的&#xff1a; 你可以移入这个元素部分去看看是哪个要用的&#xff08;好像谷歌还是狐火直接放上去就可以看到元素表示&#xff0c;但是我有时用谷歌只…

16.RedHat认证-Ansible自动化运维(中)

16.RedHat认证-Ansible自动化运维(中) 部署Ansible Ansible的Inventory文件 Inventory文件定义了ansible管理的主机&#xff0c;说白了就是Inventory文件中的内容是记录被管理的主机。 Inventory文件分为两种&#xff0c;一种是静态的Inventory文件&#xff0c;一种是动态的…

家有老人小孩,室内灰尘危害大!资深家政教你选对除尘空气净化器

哈喽&#xff0c;各位亲爱的朋友们&#xff01;今天我们来聊聊每次大扫除时最让人头疼的问题——灰尘。你有没有发现&#xff0c;两天不打扫&#xff0c;桌子上就能积上一层灰&#xff1b;阳光一照&#xff0c;地板上的灰尘都在跳舞&#xff1b;整理被子的时候&#xff0c;空气…

板凳-------第58章SOCKET:TCP/IP网络基础

58.1 互联网 互联网会将不同的计算机网络连接起来并允许位于网络中的主机相互之间进行通信。互联网的目标是隐藏不同物理网络的细节以便向互联网中的所有主机呈现一个统一的网络架构&#xff0c;TCP/IP已经成了使用最为广泛的协议套件了&#xff0c; 术语Internet被用来指将全球…

根据多个后缀类型筛选文件

多个后缀类型筛选文件 前言解决方法使用 grep -E 和扩展正则表达式使用 bash 的扩展模式&#xff08;extglob&#xff09;具体解释 前言 根据文件的后缀进行筛选&#xff0c;如下&#xff1a; 有.rc 、.sql、.txt 三种后缀文件&#xff0c; 如何筛选出&#xff1a;.sql 和 .tx…

2-7 基于matlab实现声纹识别

基于matlab实现声纹识别&#xff0c;通过提取声音信号的MFCC特征&#xff0c;然后形成特征向量&#xff0c;通过训练语音&#xff0c;对测试语音进行识别&#xff0c;可以识别训练库内的声音&#xff0c;也可以识别出训练库外的声音。程序已调通&#xff0c;可直接运行。 2-7 m…

Redis持久化主从哨兵分片集群

文章目录 1. 单点Redis的问题数据丢失问题并发能力问题故障恢复问题存储能力问题 2. Redis持久化 -> 数据丢失问题RDB持久化linux单机安装Redis步骤RDB持久化与恢复示例RDB机制RDB配置示例RDB的fork原理总结 AOF持久化AOF配置示例AOF文件重写RDB与AOF对比 3. Redis主从 ->…

Meta FAIR研究新成果:图像到文本、文本到音乐的生成模型,多标记预测模型以及AI生成语音检测技术

Meta AI研究实验室(FAIR)公开发布了多项新研究成果&#xff0c;包括图像到文本和文本到音乐的生成模型&#xff0c;多词预测模型&#xff0c;以及检测AI生成语音的技术。发布的成果体现了开放性、协作、卓越和规模化等核心原则。公开早期研究工作旨在激发迭代&#xff0c;推动A…

AI写论文网站,提升论文写作效率

学术研究与论文写作是一个衡量学者专业水平的重要标准。但是&#xff0c;论文写作过程中繁琐的文献检索、资料整理、数据分析等工作往往耗时费力。幸运的是&#xff0c;随着人工智能技术的发展&#xff0c;一系列AI写论文网站应运而生&#xff0c;它们极大地提升了我们论文写作…

代码随想录刷题复习day01

day01 数组-二分查找 class Solution {public int search(int[] nums, int target) {// 左闭右闭int left 0;int right nums.length - 1;int mid 0;while (right > left) {mid left (right - left) / 2;if (nums[mid] > target)right mid - 1;else if (nums[mid]…

vscode如何将已安装的插件下载本地

在线安装&#xff1a;直接在VSCode的扩展商店中搜索并安装插件。这是最直接的方法&#xff0c;适用于网络连接稳定的情况。 离线安装&#xff08;.vsix文件&#xff09;&#xff1a; 首先&#xff0c;访问VSCode插件市场&#xff08;https://marketplace.visualstudio.com/&a…

AOSP开发环境搭建

目录 一、安装虚拟机 二、安装Ubuntu 三、安装VMware tools 3.1、通用安装 3.2、Ubuntu22.04 中Drag and drop is not supported问题 四、安装依赖环境 4.1、安装git 4.2、下载Python3 4.3、解压Python3 4.4、编译与安装Python3 3.sudo make install 4.5、安装Pyth…

ATFX汇市:英央行6月利率决议来袭,大概率按兵不动

ATFX汇市&#xff1a;昨日英国统计局刚公布5月CPI年率数据&#xff0c;今日英国央行就要公布利率决议结果&#xff0c;两项重磅数据同一周出现&#xff0c;GBPUSD或迎来高波动期。今日19:00&#xff0c;英国央行将公布6月利率决议结果&#xff0c;市场普遍预期其将维持5.25%的基…