JAVA多线程(8.0)

目录

线程池

为什么使用线程池

线程池的使用

工厂类Executors(工厂模式)

submit 

实现一个线程池


线程池

为什么使用线程池

在前面我们都是通过new Thread() 来创建线程的,虽然在java中对线程的创建、中断、销毁、等值等功能提供了支持,一个线程的创建和销毁虽然消耗虽然小,但从操作系统角度来看,如果我们频繁的创建和销毁线程,是需要大量的时间和资源的,那么有没有什么开销更小的方法?

第一种是协程,它可以说是轻量级线程,但是java很少用,多用于go和python。

第二种是线程池,java中多用线程池去解决频繁的创建和销毁线程问题。

那么为啥引入线程池就能够提升效率呢?

1.直接创建/销毁线程,是需要在用户态+内核态配合完成的工作,对于线程池,只需要在用户态即可,不需要内核态的配合,这样开销就更小

2.等线程用完之后,线程池不会销毁该线程,而是让其阻塞,等下次用的时候会再次利用它,所以不用频繁的进行创建和销毁。

线程池最核心的设计思路:复用线程,平摊线程的创建与销毁的开销代价

线程池的使用

java 提供了多种方式来创建线程池,主要通过Executors(执行者)工厂类或直接使ThreadPoolExecutor类来完成

工厂类Executors(工厂模式)

使用Executors工厂类:

newFixedThreadPool(int nThreads):创建一个固定大小的线程池,线程数量由nThreads参数确定。
newCachedThreadPool():创建一个线程数量为动态的线程池,线程数量会根据任务数量动态变化,当长时间没有新任务时,空闲线程会被终止。

newSingleThreadExecutor():创建一个单线程的线程池,它只会创建一个线程来执行任务。
newScheduledThreadPool(int corePoolSize):创建一个可以安排任务的线程池,可以指定延迟执行任务或定期执行任务。

后面两个我们用的都不多,主要是用前面两个

下面是使用代码:

​
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadPoolExample {public static void main(String[] args) {// 创建一个固定大小的线程池ExecutorService fixedThreadPool = Executors.newFixedThreadPool(4);// 创建一个可缓存的线程池(线程数量动态调整)ExecutorService cachedThreadPool = Executors.newCachedThreadPool();}
}

这代码我们有个疑点,我们并没有new一个对象,那我们是怎么创建出来对象的呢?

这个问题涉及到工厂模式这种设计模式:

工厂模式是一种常用的设计模式,用于封装对象的创建逻辑。它通过使用方法来创建对象(new在方法内部),而不是直接使用 new 关键字实例化对象。这样可以将对象的创建逻辑与使用逻辑解耦,提高代码的可维护性和可扩展性。

这里就是用方法创建出对象,所以涉及到了工厂模式

ThreadPoolExecutor类(直接new)
对于刚才讲的 Executors 本质上是 ThreadPoolExecutor 类的封装.         

而对于ThreadPoolExecutor类本身我们提供了更多的可选参数, 可以进一步细化线程池行为的设定. 

如下图是 ThreadPoolExecutor类的构造方法:

核心线程数(corePoolSize):线程池中始终保持的线程数量。这是不会被销毁的。

最大线程数(maximumPoolSize):线程池中允许的最大线程数量。这种一般涉及到刚才的动态线程池,如果任务多了则创建一些线程,多了的话过了一段时间则会销毁,但核心线程数不变。

空闲线程存活时间(keepAliveTime):当线程池中的线程数量超过核心线程数时,空闲线程的存活时间。

任务队列(workQueue):其为阻塞队列,用于存储等待执行的任务。要记住,当我们创建线程池时,系统也会同时自动创建一个阻塞队列去存储等待执行的任务,这样效率就更高。

线程工厂(threadFactory):线程工厂是一个用于创建线程的工具类或接口,它允许用户自定义线程的创建逻辑,开发者可以控制线程的名称、优先级、异常处理等属性,从而更好地管理线程资源。

拒绝策略(handler):当线程池已满且阻塞队列也已满时,新任务的处理策略。

下面重点讲述一下拒绝策略:

  • AbortPolicy:直接抛出 RejectedExecutionException 异常。(当导员给我一个任务“统计班级成员中团员个数‘’,但是我现在已经课很多了,我一下子就哭了出来)这个就相当于直接抛异常
  • CallerRunsPolicy:由提交任务的线程直接执行任务。(我直接给导员说,我没空,导员最后只能自己做了)
  • DiscardPolicy:直接丢弃任务,不抛出异常。(导员一听我没空,就直接说,好!那我也不统计了,随便来了)
  • DiscardOldestPolicy:丢弃队列中最老的任务,然后尝试提交新任务。(我听到导员的任务的时候,我选择放弃我最早出现的一节课去帮导员完成任务)

下面是其创建代码 

 ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2,  // 核心线程数4,  // 最大线程数60,  // 空闲线程存活时间TimeUnit.SECONDS,  // 时间单位new ArrayBlockingQueue<>(10),  // 任务队列,容量为 10Executors.defaultThreadFactory(),  // 线程工厂new ThreadPoolExecutor.AbortPolicy()  // 拒绝策略);

总结一下:

  • 工厂模式创建线程:适合简单的线程池创建场景,代码简单,但灵活性有限。

  • 构造方法创建线程:适合需要灵活配置线程池属性的场景,通过自定义线程池,可以更好地管理线程资源,提高代码的可维护性和可扩展性。

submit 

 通过线程池.submit(继承runable的类的对象) 可以提交一个任务到线程池中执行.

ExecutorService pool = Executors.newFixedThreadPool(10);
pool.submit(new Runnable() {@Overridepublic void run() {System.out.println("hello");}
});
实现一个线程池

 这里就直接上代码了,不多说,重点还是使用线程池,不是实现线程池。

/*** 自定义线程池执行器类* 该类通过实现一个具有固定大小的线程池和一个阻塞队列来管理线程,用于异步执行任务*/
class MyThreadPoolExecutor {// 创建阻塞队列,用于存放待执行的任务// 队列大小设为1000,用于控制并发任务的数量,避免过多任务导致资源耗尽BlockingQueue<Runnable>  blockingQueue=new ArrayBlockingQueue<>(1000);/*** 构造函数,初始化线程池* 创建一个线程,该线程循环从阻塞队列中取任务并执行* 这个线程是线程池中的工作线程,负责执行提交的任务*/public MyThreadPoolExecutor(int n) {for (int i = 1; i <= n; i++) {Thread t = new Thread(() -> {// 无限循环,确保线程池可以持续处理任务,直到程序中断或阻塞队列被清空while (true) {try {// 从阻塞队列中取出一个任务,如果队列为空,则线程被阻塞,直到有任务放入队列Runnable task = blockingQueue.take();// 执行取出的任务task.run();} catch (InterruptedException e) {// 如果线程在等待状态时被中断,抛出运行时异常// 这通常会导致程序异常终止throw new RuntimeException(e);}}});// 启动线程池中的工作线程t.start();}}/*** 提交一个任务到线程池* @param task 需要被执行的任务*            任务被放入阻塞队列中,随后由线程池中的工作线程执行*/public void submit(Runnable task){// 将任务放入阻塞队列,如果队列已满,则操作会阻塞,直到有空间可用blockingQueue.offer(task);}
}
class DemoTest1{public static void main(String[] args) throws InterruptedException {MyThreadPoolExecutor ex=new MyThreadPoolExecutor(4);for(int i=0;i<100;i++) {int id = i;ex.submit(()->{System.out.println(Thread.currentThread().getName()+"  任务:"+id);});}}
}

多线程基础知识点到这里就告一段路了,接下来我们将学习多线程(进阶)这部分是主要讲面试中经典题,频繁的题

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

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

相关文章

用go从零构建写一个RPC(仿gRPC,tRPC)--- 版本1

希望借助手写这个go的中间件项目&#xff0c;能够理解go语言的特性以及用go写中间件的优势之处&#xff0c;同时也是为了更好的使用和优化公司用到的trpc&#xff0c;并且作者之前也使用过grpc并有一定的兴趣&#xff0c;所以打算从0构建一个rpc系统&#xff0c;对于生产环境已…

【学习笔记】Stata

一、Stata简介 Stata 是一种用于数据分析、数据管理和图形生成的统计软件包&#xff0c;广泛应用于经济学、社会学、政治科学等社会科学领域。 二、Stata基础语法 2.1 数据管理 Stata 支持多种数据格式的导入&#xff0c;包括 Excel、CSV、文本文件等。 从 Excel 文件导入…

Redis数据结构SDS,IntSet,Dict

目录 1.字符串&#xff1a;SDS 1.1.为什么叫做动态字符串 2.IntSet 2.1.inset如何保存大于当前编码的最大数字&#xff1f; 3.Dict 3.1Dict的扩容 3.2Dict的收缩 3.3.rehash 1.字符串&#xff1a;SDS SDS的底层是C语言编写的构建的一种简单动态字符串 简称SDS&#xff…

Maven的聚合工程与继承

目录 一、为什么需要使用Maven工程 二、聚合工程的结构 三、聚合工程实现步骤 四、父工程统一管理版本 五、编译打包 大家好&#xff0c;我是jstart千语。想着平时开发项目似乎都是用maven来管理的&#xff0c;并且大多都是聚合工程。而且在maven的聚合工程中&#xff0c…

前端职业发展:如何规划前端工程师的成长路径?

前端职业发展:如何规划前端工程师的成长路径? 大家好,我是全栈老李。今天咱们聊聊前端工程师的职业发展路径,这个话题看似简单,实则暗藏玄机。就像打游戏升级一样,你得知道下一关是什么,才能提前准备装备和技能点。 前端之路 一般我们从一个新手到大神,普遍需要经过…

【星海出品】分布式存储数据库etcd

etcd 数据库由 CoreOS 公司创建。 https://github.com/etcd-io/etcd api信息 https://etcd.io/docs/v3.5/dev-guide/api_reference_v3/ etcdctl --help etcd 最初由 CoreOS 公司开发&#xff0c;作为其核心项目之一。 CoreOS 成立于 2013 年&#xff0c;专注于容器化技术&#…

2025新版修复蛇年运势测试风水起名系统源码

2025新版修复蛇年运势测试风水起名系统源码 通过网盘分享的文件&#xff1a;2025xbfsysweb.rar 链接: https://pan.baidu.com/s/1r1MOkJJJMj9s9nQX_GzI3Q 提取码: 9weh 备用下载地址&#xff1a;http://pan.1234f.com:5212/s/JK1uw

Vue3 Pinia

一、Pinia 核心概念 Pinia 是 Vue3 官方推荐的状态管理库&#xff0c;相比 Vuex 4&#xff0c;具有以下优势&#xff1a; 更简洁的 API&#xff08;移除 mutations&#xff09; 完整的 TypeScript 支持 支持组合式 API 自动代码分割 轻量级&#xff08;仅 1KB&#xff09;…

音视频小白系统入门课-4

本系列笔记为博主学习李超老师课程的课堂笔记&#xff0c;仅供参阅 往期课程笔记传送门&#xff1a; 音视频小白系统入门笔记-0音视频小白系统入门笔记-1音视频小白系统入门笔记-2音视频小白系统入门笔记-3 将mp4文件转换为yuv文件 ffmpeg -i demo.mp4 # 输入文件-an …

6.2 内容生成与营销:个性化内容创作与营销策略优化

随着消费者对个性化体验的需求日益增长&#xff0c;传统的内容创作与营销方式已难以满足市场竞争的需要。基于大语言模型&#xff08;LLM&#xff09;与智能代理&#xff08;Agent&#xff09;的技术为企业提供了全新的解决方案&#xff0c;能够实现高效、精准、规模化的内容生…

kafka课后总结

Kafka是由LinkedIn开发的分布式发布 - 订阅消息系统&#xff0c;具备高吞吐量、低延迟、可扩展性、持久性、可靠性、容错性和高并发等特性。其主要角色包括Broker、Topic、Partition、Producer、Consumer、Consumer Group、replica、leader、follower和controller。消息系统中存…

DataStreamAPI实践原理——计算模型

引入 通过前面我们对于Flink的理解&#xff0c;我们知道它吸收了 Dataflow 的理念&#xff0c;以及此前已有的流处理系统&#xff08;如 S4、Storm、MillWheel&#xff09;的经验&#xff0c;实现了批流一体化的高效数据处理&#xff0c;并且通过灵活的窗口机制、事件时间与水…

项目笔记1:通用 Service的常见方法

通用 Service 通常封装了常见的业务逻辑操作&#xff0c;以提高代码的复用性和可维护性。不同的框架和业务场景下&#xff0c;通用 Service 的方法会有所差异&#xff0c;但一般都会包含一些基本的增删改查&#xff08;CRUD&#xff09;操作&#xff0c;以下为你详细介绍&#…

阿里云99机器总是宕机,实测还是磁盘性能差

阿里云99计划总是宕机&#xff0c;经过反复排查&#xff0c;最终确认还是磁盘性能差。 阿里云99机器使用的磁盘类型是Entry云盘40GiB (2120 IOPS) 按照官方的一些数据&#xff0c;这个磁盘最小iops是1800最大是6000,实际使用中发现&#xff0c;这个6000值很虚&#xff0c;这个…

Fedora 43 计划移除所有 GNOME X11 相关软件包

Fedora 43 计划移除所有 GNOME X11 相关软件包&#xff0c;这是 Fedora 项目团队为全面拥抱 Wayland 所做的重要决策。以下是关于此计划的详细介绍&#xff1a; 提案内容&#xff1a;4 月 23 日&#xff0c;Neal Gompa 提交提案&#xff0c;建议从 Fedora 软件仓库中移除所有 G…

魔幻预言手游》:职业介绍!

在《魔幻预言》手游中&#xff0c;共有武玄、魔魅、剑仙三大核心职业&#xff0c;各具特色且定位鲜明&#xff0c;以下为具体介绍&#xff1a; 一、武玄&#xff08;战士&#xff09; 核心定位&#xff1a;近战物理输出与团队增益担当&#xff0c;兼具控制与防御能力。 战斗风…

精益数据分析(27/126):剖析用户价值与商业模式拼图

精益数据分析&#xff08;27/126&#xff09;&#xff1a;剖析用户价值与商业模式拼图 在创业和数据分析的领域中&#xff0c;每一次深入学习都是一次成长的契机。今天&#xff0c;我们继续秉持共同进步的理念&#xff0c;深入研读《精益数据分析》&#xff0c;剖析用户价值的…

【SwitchyOmega安装教程】

目录 一、插件安装 1. 下载安装文件 2. 打开浏览器扩展安装页面 3. 安装插件 二、界面详情 三、配置信息 3.1 设置IP 1、查看IP地址信息 2、批量测试IP是否有效 3、点击扩展程序&#xff0c;选择 Proxy SwitchyOmega 4、 点击选项进行配置 5、配置页面 一、插件安装 1…

矫平机终极指南:特殊材料处理、工艺链协同与全球供应链管理

一、特殊材料矫平&#xff1a;挑战与创新解决方案 1. 高温合金&#xff08;如Inconel 718&#xff09;处理 技术难点&#xff1a; 屈服强度高达1100 MPa&#xff0c;传统矫平力不足 高温下易氧化&#xff0c;需惰性气体保护环境 解决方案&#xff1a; 采用双伺服电机驱动&a…

反事实——AI与思维模型【82】

一、定义 反事实思维模型是一种心理认知模型,它指的是人们在头脑中对已经发生的事件进行否定,然后构建出一种可能性假设的思维活动。简单来说,就是思考“如果当时……,那么就会……”的情景。这种思维方式让我们能够超越现实的限制,设想不同的可能性和结果,从而对过去的…