线程池ThreadPoolExecutor使用
文章目录
- 一、基础-Java中线程创建的方式
- 1.1、继承Thread类创建线程
- 1.2、实现Runnable接口创建线程
- 1.3、实现Calable接口创建线程
- 1.4、使用线程池创建线程
- 二、概念-线程池基本概念
- 2.1、并发和井行的主要区别
- 2.1.1、处理任务不同
- 2.1.2、存在不同
- 2.1.3、CPU资源不同
- 2.2、什么是线程池?
- 2.3、为什么使用线程池?
- 三、源码解读·线程池源码
- 3.1、 线程池的核心参数
- 3.2、线程池线程增长策略
- 线程池创建
- 3.3、线程池处理任务流程
- 3.4、线程池执行过程解读
- 四、案例-使用线程池异步处理百万级数据
- 4.1、创建springboot项目导入依赖
- 4.2、创建数据表
- 4.3、配置ym
- 4.4、创建实体类
- 4.5、创建Mapper接口
- 4.6、创建Service接口及实现类
- 4.7、创建Controller
- 4.8、创建线程池配置类
- 4.9、创建异步任务接口及实现类
- AsyncService.java
- AsyncServiceImpl.java
- 4.10、创建拆分集合的工具类
- 4.12、改造Controller调用异步任务
- 五、同步工具CountDownLatch解析
- 5.1、介绍
- 5.2、特性
- 5.3、应用案例
一、基础-Java中线程创建的方式
1.1、继承Thread类创建线程
通过继承Thread类来创建并启动多线程的一般步骤如下
1、定义Thread类的子类,并重写该类的run0)方法,该方法的方法体就是线程需要完成的任务,run()方法也称为线程执行体。
2、创建Thread子类的实例,也就是创建了线程对象
3、启动线程,即调用线程的start()方法
示例:
package org.example;/*** @Author Js* @Description* @Date 2024-07-30 20:35* @Version 1.0**/
public class MyThread extends Thread {@Overridepublic void run() {String name = Thread.currentThread().getName();switch (name) {case "xcl":for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName() + ":" + i);}break;case "xc2":for (int i = 0; i < 10; i++) {System.out.println("好好学习java" + i);}break;}}
}
创建线程对象
package org.example;public class Main {public static void main(String[] args) {MyThread myThread1=new MyThread();//创建线程对象myThread1.setName("xc1");myThread1.start();//启动线程MyThread myThread2=new MyThread();//创建线程对象myThread2.setName("xc2");myThread2.start();//启动线程}
}
1.2、实现Runnable接口创建线程
通过实现Runnable接口创建并启动线程一般步骤如下:
1、定义Runnable接口的实现类,一样要重写run0)方法,这个run()方法和Thread中的run()方法一样是线程的执行体
2、创建Runnable实现类的实例,并用这个实例作为Thread的target来创建Thread对象,这个Thread对象才是真正的线程对象
3、第二步依然三通过调田纤程对象的:ttar0方法来启动线程
package org.example;/*** @Author Js* @Description* @Date 2024-07-30 20:53* @Version 1.0**/
public class MyRunable implements Runnable{@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName()+": "+i);}}
}
创建线程对象
package org.example;/*** @Author Js* @Description* @Date 2024-07-30 20:54* @Version 1.0**/
public class TestRunable {public static void main(String[] args) {Runnable myRunable=new MyRunable();//1、实例化对象Thread thread=new Thread(myRunable);//2、构建一个线程对象thread.setName("线程1");thread.start();//3、启动线程Thread threadl=new Thread(myRunable);threadl.setName("线程2");threadl.start();}
}
1.3、实现Calable接口创建线程
使用Callable和Future创建线程
创建并启动有返回值的线程的步骤如下:
步骤:
1、创建Callable接口的实现类,并重写call()'方法,该方法具有返回值
2、实例化实现类对象,通过实现类对象进行入参来构建一个FutureTask对象,FutureTask对象实现了Runable接口,Future也是Runable和Future接口的实现类
3、通过FutureTask对象入参构建一个线程对象,并调用start()方法来启动执行线程
4、适用FutureTask对象的get()方法来获得线程执行的结果
示例:
package org.example;import java.util.concurrent.Callable;/*** @Author Js* @Description* @Date 2024-07-30 21:01* @Version 1.0**/
public class MyCallable implements Callable<Integer> {@Overridepublic Integer call() throws Exception {int num1=11;int num2=22;int sum=num1+num2;return sum;}
}
创建线程对象
package org.example;import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;/*** @Author Js* @Description* @Date 2024-07-30 21:03* @Version 1.0**/
public class CallableTest {public static void main(String[] args) {MyCallable m3 = new MyCallable();//实例化对象FutureTask<Integer> futureTask = new FutureTask(m3); //Runable对象//创建线程Thread t1 = new Thread(futureTask);t1.setName("线程一");t1.start();//new Thread(futureTask,"线程一").start();try {System.out.println("线程的执行结果为:" + futureTask.get());//获得线程的返回值} catch (InterruptedException e) {throw new RuntimeException(e);} catch (ExecutionException e) {e.printStackTrace();}}
}
1.4、使用线程池创建线程
下面就是…
二、概念-线程池基本概念
2.1、并发和井行的主要区别
2.1.1、处理任务不同
并发(Concurrent)
并发是一个CPU处理器同时处理多个线程任务。(宏观上是同时处理多个任务,微观上其实是CPU在多个线程之间快速的交替执行。操作系统中有一个组件叫做任务调度器,它将CPU的时间片(windows下时间片最小约为15毫秒) 配给各个线程使用,在一个时间段的线程运行时,其他线程处于挂起状态,这种就称之为并发。)
并行(parallel)
并行是多个CPU处理器同时处理多个线程任务。(当一个CPU执行一个线程时,另一个CPU可以执行另一个线程,两个线程互不抢占CPU资源,可以同时进行,这就被称之为并行。)
2.1.2、存在不同
并发(concurrent)
并发可以在一个CPU处理器和多个CPU处理器系统中都存在。(多个CPU处理器系统其中的一个CPU也可以进行并发操作)
并行(parallel)
并行在多个CPU处理器系统存在。
2.1.3、CPU资源不同
并发(Concurrent)
并发过程中,线程之间会去抢占CPU资源,轮流使用,(其实CPU会多个各个线程公平的分配时间片和进行执行。)
并行(parallel)
并行过程中,线程间不会抢占CPU资源,(因为是多个CPU处理器,各做各的。)
2.2、什么是线程池?
首先要理解什么是线程,线程池(thread pool),是一种线程使用模式,线程池维护着多个线程,等待着监督管理者分配可并发执行的任务,就是可管理和维护以及分配线程的"池子
2.3、为什么使用线程池?
为了减少创建和销毁线程的次数,让每个线程都可以多次的使用,可以根据系统情况调整线程的数量,防止消耗过多内存。在实际使用中,服务器在创建和销毁线程上花费的时间和消耗的系统资源都相当大,使用线程池就可以优化。
通俗的说:目的就是为了让线程对象可以反复的复用,不需要每次执行任务时构建一个新的线程,等到任务处理完再销毁。
三、源码解读·线程池源码
3.1、 线程池的核心参数
先看源码
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler){}//参数说明:
int corePoolSize,//核心线程数
int maximumPoolSize,//最大线程数
long keepAliveTime,//线程最大空闲时间,默认针对非核心线程
TimeUnit unit,//线程最大空闲时间单位
BlockingQueue<Runnable> workQueue,//阻塞队列
ThreadFactory threadFactory,//线程工厂
RejectedExecutionHandler handler//拒绝策略
3.2、线程池线程增长策略
问题:
1、当向一个新创建的线程池中提交任务时候,线程池何时创建新线程,何时把任务放入等待队列,何时执行拒绝策略?
2、当一个线程池达到最大线程后,没有任务执行,哪些线程会被销毁?
3、线程池中的最大线程可以设置为多少?
4、线程池中如何来复用一个线程?
任务提交流程
线程池按以下行为执行任务:
1、当线程数小于核心线程数时,创建线程。
2、当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务(阻塞)队列。
3、当线程数大于等于核心线程数,且任务队列已满,若线程数小于最大线程数,创建工作(普通)线程。
4、若线程数等于最大线程数,则执行拒绝策略
核心线程数通常设置为CPU核心数的一个合理倍数,以充分利用系统资源并提高并发能力。最大线程数则通常设置为一个合理的上眼值,避免过多的线程竞争系统资源导致性
能下降或系统崩溃。
ThreadPoolExecutor提供了四种默认的拒绝策略:
AbortPolicy(默认): 当工作队列已满并且无法再添加新任务时,抛出RejectedExecutionException异常。
CallerRunsPollcy: 当工作队列已满并且无法再添加新任务时,由提交任务的线程来执行该任务。也就是说,任务将在提交线程的上下文中执行。
DiscardOldestPolcy: 当工作队列已满并且无法再添加新任务时,丢弃队列中最早的任务(即等待时间最长的任务),然后尝试里新提交新任务。
DiscardPolicy: 当工作队列已满并且无法再添加新任务时,直接丢弃新任务,不做任何处理。
线程池创建
package org.example;import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;/*** @Author Js* @Description* @Date 2024-07-30 22:03* @Version 1.0**/
public class ThreadPoolExecutorTest {public static void main(String[] args) {ThreadFactory factory = new ThreadFactory() {@Overridepublic Thread newThread(Runnable r) {ThreadFactory threadFactory = Executors.defaultThreadFactory();Thread thread = threadFactory.newThread(new MyRunable());return thread;
相关文章:

线程池ThreadPoolExecutor使用
文章目录 一、基础-Java中线程创建的方式1.1、继承Thread类创建线程1.2、实现Runnable接口创建线程1.3、实现Calable接口创建线程1.4、使用线程池创建线程二、概念-线程池基本概念2.1、并发和井行的主要区别2.1.1、处理任务不同2.1.2、存在不同2.1.3、CPU资源不同2.2、什么是线…...

Codeforces Round 963 (Div. 2)
A题:Question Marks 题目: Tim正在做一个由 4n 个问题组成的测试,每个问题都有 4 个选项:“A”、“B”、“C”和“D”。对于每个选项,有 n 个正确答案对应于该选项,这意味着有 n 个问题的答案为“A”。 n…...
Mysql函数学习笔记
MySQL 字符串函数 ASCII(s) 返回字符串 s 的第一个字符的 ASCII 码。 //返回 CustomerName 字段第一个字母的 ASCII 码 SELECT ASCII(CustomerName) AS NumCodeOfFirstChar FROM Customers;CHAR_LENGTH(s)-返回字符串 s 的字符数 //返回字符串 RUNOOB 的字符数 SELECT CHAR…...

【Linux基础】Linux基本指令(一)
目录 前言1, ls指令2,pwd指令三,cd指令3.1 当前目录与上级目录3.2 绝对路径和相对路径 四,创建一个普通文件或目录4.1 touch指令4.2 mkdir指令 五,删除目录或文件5.1 rmdir指令5.2 rm 指令 前言 从本章开始࿰…...

全球视野:航空蓄电池的国际标准与技术创新
航空蓄电池是一种专门为满足航空工业独特要求而设计的高性能储能设备。由于航空环境的特殊性,如高海拔、极端温度变化、频繁的充放电需求、以及对于设备重量和体积的严格限制,航空蓄电池需要具备一系列高级特性以确保飞机在各种飞行条件下能够安全有效地…...
11-初识python的函数——定义和调用
1 函数简介 function input()、print()、range()、len()都是python的内置函数,可以直接使用的 函数:可以用来保存代码,在需要的时候对这些语句进行重复调用 优点: 1. 遇到重复功能的时候,直接调用即可,…...

Windows安装Swoft框架
实现方式: 安装虚拟机,在虚拟机里用宝塔搭建环境后安装Swoft, 然后用Phpstorm SSH方式开发,用Apipost调用 websocket服务。 1、安装虚拟机,下载和安装参见 : https://blog.csdn.net/2401_84297265/article…...

阅读台灯什么品牌好?一文带你了解热门阅读台灯推荐
阅读台灯最终都绕不开护眼这个话题。护眼灯作为保护视力的辅助工具,以有效护眼的价值深受大众青睐。学生长时间用眼,普通台灯的伤害大,而阅读台灯的出现,通过其先进的技术和设计,能为学生提供了一个既舒适又健康的照明…...

1、.Net UI框架:Xamarin Forms - .Net宣传系列文章
Xamarin.Forms是一个跨平台移动应用开发框架,它允许开发者使用C#和.NET进行一次编码,然后在iOS、Android、macOS和Windows等多个平台上运行。Xamarin.Forms是Xamarin的一部分,而Xamarin是微软的.NET跨平台开发工具集,它提供了一套…...

Tomcat 最大连接数实现原理
spring boot 内置tomcat设置连接数 max-connections: 5 server:port: 9898servlet:context-path: /testtomcat:connection-timeout: 5000max-connections: 5accept-count: 5 ##初始化连接数量connectionLimitLatch protected LimitLatch initializeConnectionLatch() {if (ma…...

大数据应用【大数据导论】
各位大佬好 ,这里是阿川的博客,祝您变得更强 个人主页:在线OJ的阿川 大佬的支持和鼓励,将是我成长路上最大的动力 阿川水平有限,如有错误,欢迎大佬指正 目录 大数据在许多领域应用互联网领域应用生物医学…...

IP地址申请SSL证书实现https访问
为IP地址申请SSL证书以实现HTTPS访问,可以确保通过网络传输的数据得到加密保护。下面是为IP地址申请并安装SSL证书一般的步骤: 1 访问CA 打开JoySSL官网,注册一个账号用于申请证书,注册时会有选填项注册码,填写后可获…...

未授权访问漏洞上(漏洞复现合集)
目录 一:Redis未授权访问漏洞 * 步骤一:进入vulhub目录使用以下命令启动靶机... 步骤二:在Kali上安装redis程序进行服务的链接 步骤三:可以直接连接执行命令且不需要认证说明存在未授权访问漏洞...下载以下攻击项目... 步骤四:使用工具执行以下命令获取目标的命…...

多久没有清理你的电脑磁盘了?轻松解锁免费轻量磁盘清理工具
随着我们日常使用电脑的时间越来越长,磁盘上积累的无用文件和垃圾数据也越来越多。这些文件不仅占用宝贵的存储空间,还可能拖慢电脑的运行速度。 那么,你多久没有清理过你的电脑磁盘了呢? 今天,我将为大家推荐几款免…...

高精度加法c++
题目描述 计算ab的值,a,b皆为不超过240位的正整数。 输入 两个正整数,每行一个 输出 一个数,代表两个整数的和 样例输入 111111111111111111111111111111111111 222222222222222222222222222222222222 样例输出 3333333333333333333…...

SQL布尔盲注
目录 1 布尔盲注 2布尔盲注流程 2.1输入id进行测试 2.2判断注入类型 2.3爆数据库名 2.4爆表名 2.5爆字段名 2.6查询数据 1 布尔盲注 布尔盲注就是在SQL注入过程中,SQL语句执行后,查询到的数据不能回显到前端页面,如果正确执行了构造的…...

OpenGL实现3D游戏编程【连载3】——3D空间模型光照初步
1、本节实现的内容 上一节课,我们建立了简单的坐标系,同时也显示了一个正方体,但正方体的颜色为纯红色,好像一个平面物体一样,我们这节课就可以加一些光照,并创建更多的模型,使这些物体变得更加…...

Python 进行反射和元编程
反射和元编程是Python中两种强大且高级的编程技术。反射允许程序在运行时检查和修改自身结构和行为,而元编程则是编写可以操作其他代码的代码,通常通过使用元类、装饰器等技术来实现。 1. 反射 反射是指程序在运行时检查和操作自身结构的能力。Python通…...

Please refer to dump files (if any exist) [date].dump, [date]-jvmRun[N]……解决
一、问题 Please refer to dump files (if any exist) [date].dump, [date]-jvmRun[N].dump and [date].dumpstream.二、解决方案 1、当打包构建的时候出现这个问题,如果你只是打包部署,那么就是将maven的test禁止可以成功打包 2、当你是本地服务器启动…...
如何看待“低代码”开发平台的兴起
目录 如何看待“低代码”开发平台的兴起?新机遇:效率与质量并进的新篇章1. 提升开发效率:2. 降低技术门槛:3. 创新加速: 挑战:质量和定制化需求的考量1. 定制能力受限:2. 依赖性和迁移成本 &…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?
编辑:陈萍萍的公主一点人工一点智能 未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战,在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统
医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上,开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识,在 vs 2017 平台上,进行 ASP.NET 应用程序和简易网站的开发;初步熟悉开发一…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...

如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...
【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error
在前端开发中,JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作(如 Promise、async/await 等),开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝(r…...
土建施工员考试:建筑施工技术重点知识有哪些?
《管理实务》是土建施工员考试中侧重实操应用与管理能力的科目,核心考查施工组织、质量安全、进度成本等现场管理要点。以下是结合考试大纲与高频考点整理的重点内容,附学习方向和应试技巧: 一、施工组织与进度管理 核心目标: 规…...

从零开始了解数据采集(二十八)——制造业数字孪生
近年来,我国的工业领域正经历一场前所未有的数字化变革,从“双碳目标”到工业互联网平台的推广,国家政策和市场需求共同推动了制造业的升级。在这场变革中,数字孪生技术成为备受关注的关键工具,它不仅让企业“看见”设…...
写一个shell脚本,把局域网内,把能ping通的IP和不能ping通的IP分类,并保存到两个文本文件里
写一个shell脚本,把局域网内,把能ping通的IP和不能ping通的IP分类,并保存到两个文本文件里 脚本1 #!/bin/bash #定义变量 ip10.1.1 #循环去ping主机的IP for ((i1;i<10;i)) doping -c1 $ip.$i &>/dev/null[ $? -eq 0 ] &&am…...