当前位置: 首页 > news >正文

Java之线程池

目录

一.上节复习

1.阻塞队列

二.线程池

1.什么是线程池

2.为什么要使用线程池

3.JDK中的线程池

三.工厂模式

1.工厂模式的目的

四.使用线程池

1.submit()方法

2.模拟两个阶段任务的执行

五.自定义一个线程池

 六.JDK提供线程池的详解

1.如何自定义一个线程池?

 2.创建线程池的构造方法的参数及含义

3.描述线程池的工作原理

4.拒绝策略

5.为什么不推荐使用系统自带的线程池

七.自定义线程池

1.自定义线程池

 2.拒绝策略测试


一.上节复习

上节内容指路:Java之阻塞队列和消息队列

1.阻塞队列

基于阻塞队列和生产者消费者模型可以实现消息队列

wait()和notify()使用的时机

虚假唤醒:把wait()的判断条件放在一个while循环里面,唤醒之后需要重新检查等待条件

二.线程池

1.什么是线程池

JDBC编程中,通过DataSource获取Connection就用到了池(数据库连接池)的概念                          数据库连接池中有一些已经建立了连接(输入完账号密码的状态)的connection

 当Java程序需要数据库连接时,只需要从数据库连接池中获取到一个空闲的连接进行使用

当Java程序使用完连接之后,就会将当前连接返还给数据库连接池

线程池里放的是线程本身,当程序启动时就创建若干个线程,如果有任务就处理,没有任务就阻塞等待.

2.为什么要使用线程池

为了减少系统创建线程的开销

如果我们不使用线程池,每一次使用创建线程,销毁线程(用户态到内核态),很浪费系统的资源,而且再多线程的环境下,我们一次使用可能是多个线程,多个一起创建很浪费系统的资源,大大减少了系统执行的效率.使用线程池,每一次到池中拿到一个线程,只需要涉及到用户态的操作.

3.JDK中的线程池

1. 用来处理大量短时间工作任务的线程池,如果池中没有可用的线程将创建新的线程,如果线程空闲60秒将收回并移出缓存
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

2. 创建一个操作无界队列且初始线程数为n的线程池
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);

无界队列: 指的是对队列中的元素个数不加限制,可能出现内存被消耗殆尽的情况

3. 创建一个操作无界队列且只有一个工作线程的线程池
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();

4. 创建一个单线程执行器,可以在给定时间后执行或定期执行。
 ScheduledExecutorService singleThreadScheduledExecutor = Executors.newSingleThreadScheduledExecutor();

5. 创建一个指定大小的线程池,可以在给定时间后执行或定期执行。
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);

6. 创建一个指定大小(不传入参数,为当前机器CPU核心数)的线程池,并行地处理任务不保证处理顺序
ExecutorService executorService = Executors.newWorkStealingPool();

三.工厂模式

1.工厂模式的目的

解决构造方法创建对象的缺陷

以下情况会发生问题,(id,name)和(age,name)会出现相同的参数列表不能够重载,因此不能同时书写这两个构造方法

 我们可以通过两个静态方法来进行创建

class Student {private int id;private int age;private String name;public static Student createByIdAndName(int id, String name) {Student student = new Student();student.setId(id);student.setName(name);return student;}public static Student createByAgeAndName(int age, String name) {Student student = new Student();student.setAge(age);student.setName(name);return student;}public int getId() {return id;}public void setId(int id) {this.id = id;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}

四.使用线程池

1.submit()方法

通过submit方法可以看出我们可以提交任务到线程池,线程池中提供线程进行执行任务.

2.模拟两个阶段任务的执行

public class Demo03_ThreadPoolUse {public static void main(String[] args) throws InterruptedException {//创建一个初始大小为3的线程池ExecutorService threadPool = Executors.newFixedThreadPool(3);for (int i = 0; i < 10; ++i) {int taskId = i;threadPool.submit(() -> {System.out.println("我是任务:" + taskId+","+Thread.currentThread().getName());});}//模拟线程等待一段时间TimeUnit.SECONDS.sleep(5);System.out.println("第二阶段开始");for (int i = 10; i < 20; ++i) {int taskId = i;threadPool.submit(() -> {System.out.println("我是任务:" + taskId+","+Thread.currentThread().getName());});}}
}

打印的内容:

注意:此时程序并没有结束,在等待其他任务提交到线程池进行执行

五.自定义一个线程池

1.可以提交任务到线程池,那么就需要一种数据结构来保存任务----可以考虑使用阻塞队列
2.创建线程池需要指定初始的线程数量,这些线程不断的扫描阻塞队列,如果有任务就立即执行.

可以考虑使用线程池对象的构造方法,接收要创建线程的数据并在构造方法中完成线程的创建

public class MyThreadPool {//定义一个阻塞队列来保存要执行的任务BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(3);//提供一个方法,用来提交任务public void submit(Runnable runnable) throws InterruptedException {queue.put(runnable);}//构造方法完成线程的初始化public MyThreadPool(int capacity) {if (capacity <= 0) {throw new IllegalArgumentException("capacity is illegal");}//完成线程的创建,扫描队列,取出任务并执行for (int i = 0; i < capacity; i++) {Thread thread = new Thread(() -> {while (true) {//取出任务try {Runnable take = queue.take();take.run();} catch (InterruptedException e) {throw new RuntimeException(e);}}});thread.start();}}
}

测试自定义的线程池:

public class Demo04_MyThreadPool {public static void main(String[] args) throws InterruptedException {//创建一个初始大小为3的线程池MyThreadPool threadPool = new MyThreadPool(3);for (int i = 0; i < 10; ++i) {int taskId = i;threadPool.submit(() -> {System.out.println("我是任务:" + taskId + "," + Thread.currentThread().getName());});}//模拟线程等待一段时间TimeUnit.SECONDS.sleep(2);System.out.println("第二阶段开始");for (int i = 10; i < 20; ++i) {int taskId = i;threadPool.submit(() -> {System.out.println("我是任务:" + taskId + "," + Thread.currentThread().getName());});}}
}

打印结果:

 六.JDK提供线程池的详解

1.如何自定义一个线程池?

通过工厂方法获得的线程池最终都是创建一个ThreadPoolExecutor对象

 2.创建线程池的构造方法的参数及含义

  1. int corePoolSize  核心线程数,创建线程是包含的最小线程数
  2. int maximumPoolSize  最大线程数,也叫临时线程数(核心线程数不够时,允许创建最大的线程数)
  3. long keepAliveTime  临时空闲时长,超过这个时间自动释放
  4. TimeUnit unit   空闲的时间单位,和keepAliveTime一起使用
  5. BlockingQueue<Runnable> workQueue 用来保存任务的阻塞队列
  6. ThreadFactory threadFactory  线程工厂,如何去创建线程
  7. RejectedExecutionHandler handler  拒绝策略,触发的时机,当线程池处理不了过多的任务

3.描述线程池的工作原理

即上面七个参数如何搭配使用

先来举一个现实中的例子帮助我们理解工作原理:饭店老板根据人流量安排桌子数(线程数)

1.饭店里面初始有五张桌子(核心线程数为5)

2.下午3点,人数少于5,5张桌子足够接待顾客(核心线程数大于任务数)

3.到了晚饭点,人数大于5,不够接待顾客,顾客需要拿号排队等待(向阻塞队列加入任务)

4.排号人数过多,老板在饭店门口临时加了10张桌子(创建10个临时线程)

5.在用餐高峰期,门口10张桌子全部用完,排号也特别多,就让新来的顾客下次再来(执行拒绝策略)

6.当人数减少,门口10张桌子空了下来,过了半小时还没人来,将10张桌子回收(临时线程达到空闲时常,回收临时线程)

  1. 当任务添加到线程池中时,先判断任务数是否大于核心线程数,如果不大于,直接执行任务
  2. 任务数大于核心线程数,则加入阻塞队列
  3. 当阻塞队列满了之后,会创建临时线程,会按照最大线程数,一次性创建到最大线程数
  4. 当阻塞队列满了并且临时线程也创建完成,再提交任务,就会执行拒绝策略.
  5. 当任务减少,临时线程达到空闲时长时,会被回收.

4.拒绝策略

AbortPolicy:直接拒绝任务的加入,并且抛出RejectedExecutionException异常

CallerRunsPolicy:返回给提交任务的线程执行

DiscardOldestPolicy:舍弃最老的任务

DiscardPolicy:舍弃最新的任务

根据自己的业务场景选择合适的拒绝策略

5.为什么不推荐使用系统自带的线程池

1.由于使用了无界队列,可能会有内存耗尽的风险

默认是长度最大的阻塞队列


2.临时线程数无法控,也可能会存在资源耗尽

七.自定义线程池

1.自定义线程池

public class Demo_05_Create {public static void main(String[] args) throws InterruptedException {//创建线程池并指定参数ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 5, 1, TimeUnit.SECONDS,new LinkedBlockingQueue<>(10), new ThreadPoolExecutor.AbortPolicy());for (int i = 0; i < 10; ++i) {int taskId = i;threadPool.submit(() -> {System.out.println("我是任务:" + taskId + "," + Thread.currentThread().getName());});}//模拟线程等待一段时间TimeUnit.SECONDS.sleep(5);System.out.println("第二阶段开始");for (int i = 10; i < 20; ++i) {int taskId = i;threadPool.submit(() -> {System.out.println("我是任务:" + taskId + "," + Thread.currentThread().getName());});}}
}

 2.拒绝策略测试

1.AbortPolicy

将阻塞队列的大小改为1,然后在执行方法

2.CallerRunsPolicy

返回给调用者main方法线程

3.DiscardOldestPolicy

抛弃了一部分的任务,老的

4.DiscardPolicy

抛弃了一部分的任务,新的

相关文章:

Java之线程池

目录 一.上节复习 1.阻塞队列 二.线程池 1.什么是线程池 2.为什么要使用线程池 3.JDK中的线程池 三.工厂模式 1.工厂模式的目的 四.使用线程池 1.submit()方法 2.模拟两个阶段任务的执行 五.自定义一个线程池 六.JDK提供线程池的详解 1.如何自定义一个线程池? 2.创…...

让你的网站变得更智能 - B2 Pro主题问答模块新增OpenAI ChatGPT机器人自动回答功能

作为一个网站管理员,你一定会希望能够给你的用户提供更多、更好的服务。那么,你是否曾经想过为你的B2 Pro主题问答模块新增一个智能机器人自动回答功能呢?相信你一定想要这个功能,因为它能够大大提升你网站的用户体验。 现在,我们为你提供了一个好消息。我们已经为B2 Pro…...

仓库信息管理系统设计与实现

一、数据库设计 1.数据库模型设计概览 2.数据库表设计 ①depository 描述&#xff1a; 该表存储仓库的信息&#xff0c;比如仓库名称&#xff0c;仓库地址和仓库介绍 表结构&#xff1a; 序号 字段名 数据类型 主键 非空 默认值 描述 1 id INT(10) 是 是 2…...

初识Java多线程编程

文章目录 一、线程的状态二、线程的常见属性三、多线程编程Thread类常用构造方法1.继承Thread类2.实现Runnable接口3.匿名内部类实现4.lambda 表达式创建 Runnable 子类对象 四、线程的常见方法 一、线程的状态 //线程的状态是一个枚举类型 Thread.State public class ThreadS…...

最新入河排污口设置论证、水质影响预测与模拟、污水处理工艺分析及典型建设项目入河排污口方案报告书实例分析

随着水资源开发利用量不断增大&#xff0c;全国废污水排放量与日俱增&#xff0c;部分河段已远远超出水域纳污能力。近年来,部分沿岸入河排污口设置不合理&#xff0c;超标排污、未经同意私设排污口等问题逐步显现&#xff0c;已威胁到供水安全、水环境安全和水生态安全&#x…...

awk指令的详细指南

目录 工作原理 命令格式 awk常见的内建变量&#xff08;可直接用&#xff09;如下所示 按行输出文本 按字段输出文本 通过管道、双引号调用 Shell 命令 示例 CPU使用率 数组 ​编辑统计文件的内容出现的次数 使用awk 统计secure 访问日志中每个客户端IP的出现次数? …...

解密Netty中的Reactor模式

文章目录 单线程Reactor模式多线程Reactor模式Reactor模式中IO事件的处理流程Netty中的通道ChannelNetty中的反应器ReactorNetty中的处理器HandlerNetty中的通道Channel和处理器Handler的协作组件Pipeline Reactor(反应器)模式是高性能网络编程在设计和架构方面的基础模式.Doug…...

这是一个黑科技:C++爬虫~(文末报名C/C++领域新星计划)

目录 写在前面 完整代码 这里必看!! 写在最后 写在前面 现在所有人都知道万能的Python可以做机器学习,可以做人工智能,可以爬取各种小网站,但是你不知道,基于C++的正则表达式早就能够爬取各种网络数据啦!!你没猜错,阿玥将在这篇文章中简介怎么用C...

2023 年第八届数维杯数学建模挑战赛 赛题浅析

为了更好地让大家本次数维杯比赛选题&#xff0c;我将对本次比赛的题目进行简要浅析。本次比赛的选题中&#xff0c;研究生、本科组请从A、B题中任选一个 完成答卷&#xff0c;专科组请从B、C题中任选一个完成答卷。这也暗示了本次比赛的难度为A>B>C 选题人数初步估计也…...

Spring Boot单元测试

什么是单元测试&#xff1f; 单元测试(unit testing)&#xff0c;是指对软件中的最小可测试单元进行检查和验证的过程就叫单元测试。 单元测试是开发人员编写的一小段代码&#xff0c;用于检验被测代码的一个很小的、很明确的(代码) 功能是否正确。执行单元测试就是为了证明某…...

实景三维浪潮翻涌,新技术“席卷”石家庄!

5月11日&#xff0c;“全自主、全流程、全覆盖”2023实景三维新技术研讨会石家庄站暨航测与遥感学术交流会在石家庄凯旋金悦大酒店圆满举行。 本次会议由中国测绘学会、中国地理信息产业协会指导&#xff0c;河北省测绘学会、河北省地理信息产业协会主办&#xff0c;武汉大势智…...

【Python】使用小脚本

本文整理了我在学习和工作中用到的实用python脚本&#xff0c;希望也能帮助到需要的小伙伴~ 文章目录 视频格式转换顺序遍历文件夹中的文件 视频格式转换 安装视频处理库moviepy pip install moviepy安装FFmpeg&#xff08;FFmpeg是一个开源的多媒体框架&#xff0c;moviepy…...

技术日志2023-5-18

1、Java远程调试 可参考&#xff1a;https://kefeng.wang/2018/03/06/idea-remote-debug/ 2、用户中心这样的基础项目有什么用&#xff0c;感觉非常鸡肋。 今天开发讨论中涉及到了用户中心&#xff0c;感觉在项目中使用用户中心只是给业务系统发一个token&#xff0c;业务系…...

JUC之锁

公平锁、非公平锁 公平锁指的是多线程按照申请锁的顺序来获取锁&#xff1b; 非公平锁指的是多线程不按照申请锁的顺序来获取锁。可能会出现优先级反转&#xff08;后者居上&#xff09; 公平锁为了保证线程申请顺序&#xff0c;势必要付出一定的性能代价&#xff0c;因此其吞…...

C++中的 cout 和 printf 用法

文章目录 前言cout & printfexampleprintf输出string字符串总结 前言 C是一种面向对象的编程语言&#xff0c;它继承了C语言的特点&#xff0c;同时也增加了许多新的特性。在C中的cout 和 printf是两种常用的输出函数&#xff0c;它们都可以将数据显示在屏幕上&#xff0c…...

Maven基础使用

Maven 学习目标 理解Maven的用途掌握Maven的基本操作掌握Maven如何创建Web项目 Maven是什么 面临问题 在学习Maven之前&#xff0c;我们先来看一下我们现在做的项目都有哪些问题。假设你现在做了一个crm的系统&#xff0c;项目中肯定要用到一些jar包&#xff0c;比如说myb…...

【C++ 入坑指南】(06)运算符

文章目录 一、算术运算符二、赋值运算符三、比较运算符四、逻辑运算符五、算法题5.1、拆分位数 运算符是一种告诉编译器执行特定的数学或逻辑操作的符号。C 内置了丰富的运算符&#xff0c;并提供了以下类型的运算符&#xff1a; 运算符类型作用算术运算符用于处理四则运算赋值…...

了解一下js中的函数式编程

js中的函数式编程是一种编程范式&#xff0c;它将函数作为一等公民来使用。 在函数式编程中&#xff0c;函数是一种特殊的对象&#xff0c;可以赋值给变量、作为参数传递给其他函数、或作为其他函数的返回值。 函数式编程强调了函数的纯函数性&#xff0c;即函数输入相同时&a…...

动态HTTP代理在linux里的使用

动态HTTP代理是一种可以自动切换代理IP地址的代理方式&#xff0c;可以有效地绕过一些限制访问的网站。在Linux系统中&#xff0c;可以使用Privoxy和Proxychains来实现动态HTTP代理。 以下是在Linux中使用动态HTTP代理的步骤&#xff1a; 1. 安装Privoxy和Proxychains 在终端中…...

软考证书值得考吗?怎么考?

软考证书是什么&#xff1f;有什么用处&#xff1f;必须先明确这两个问题&#xff0c;才能有复习和考取的动力。怎么考过&#xff1f;这是第二步要着重解决的问题。今天详细帮助大家分析一下。 软考是国家级考试&#xff0c;具有强大的权威性与公信力。 软考全称为计算机技术…...

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?

一、核心优势&#xff1a;专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发&#xff0c;是一款收费低廉但功能全面的Windows NAS工具&#xff0c;主打“无学习成本部署” 。与其他NAS软件相比&#xff0c;其优势在于&#xff1a; 无需硬件改造&#xff1a;将任意W…...

【杂谈】-递归进化:人工智能的自我改进与监管挑战

递归进化&#xff1a;人工智能的自我改进与监管挑战 文章目录 递归进化&#xff1a;人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管&#xff1f;3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...

51c自动驾驶~合集58

我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留&#xff0c;CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制&#xff08;CCA-Attention&#xff09;&#xff0c;…...

安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件

在选煤厂、化工厂、钢铁厂等过程生产型企业&#xff0c;其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进&#xff0c;需提前预防假检、错检、漏检&#xff0c;推动智慧生产运维系统数据的流动和现场赋能应用。同时&#xff0c;…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具

文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...

Cinnamon修改面板小工具图标

Cinnamon开始菜单-CSDN博客 设置模块都是做好的&#xff0c;比GNOME简单得多&#xff01; 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

Linux云原生安全:零信任架构与机密计算

Linux云原生安全&#xff1a;零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言&#xff1a;云原生安全的范式革命 随着云原生技术的普及&#xff0c;安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测&#xff0c;到2025年&#xff0c;零信任架构将成为超…...

Mysql8 忘记密码重置,以及问题解决

1.使用免密登录 找到配置MySQL文件&#xff0c;我的文件路径是/etc/mysql/my.cnf&#xff0c;有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...

GitFlow 工作模式(详解)

今天再学项目的过程中遇到使用gitflow模式管理代码&#xff0c;因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存&#xff0c;无论是github还是gittee&#xff0c;都是一种基于git去保存代码的形式&#xff0c;这样保存代码…...