多线程4:线程池、并发、并行、综合案例-抢红包游戏

欢迎来到“雪碧聊技术”CSDN博客!

在这里,您将踏入一个专注于Java开发技术的知识殿堂。无论您是Java编程的初学者,还是具有一定经验的开发者,相信我的博客都能为您提供宝贵的学习资源和实用技巧。作为您的技术向导,我将不断探索Java的深邃世界,分享最新的技术动态、实战经验以及项目心得。

让我们一同在Java的广阔天地中遨游,携手提升技术能力,共创美好未来!感谢您的关注与支持,期待在“雪碧聊技术”与您共同成长!

目录

一、认识线程池

1、什么是线程池?

2、不复用线程的问题

3、线程池的工作原理

①工作线程

②任务队列

二、创建线程池

1、如何创建线程池?

方式一:JDK5.0开始,提供了代表线程池的接口:ExecutorService。使用ExecutorService的实现类ThreadPoolExecutor自创建一个线程池对象。

        举例:

方式二:使用Executors(线程池的工具类)调用方法返回不同特点的线程池对象。

2、线程池的注意事项

①什么时候开始创建临时线程?

②什么时候会拒绝新任务?

3、任务拒绝策略

三、处理Runnable任务

1、ExecutorService的常用方法

2、总结

四、处理Callable任务

1、ExecutorService的常用方法

2、总结

五、通过Executors工具类,创建线程池

1、该工具类中有哪些静态方法?

2、Executors工具类使用时可能存在的风险

3、总结

六、并发、并行

1、什么是进程?

举例

2、什么是线程?

3、什么是并发?

举例

4、什么是并行?

举例

 5、总结

举例

六、综合案例-抢红包游戏

1、介绍

2、编码


一、认识线程池

1、什么是线程池?

        线程池就是一个可以复用线程的技术。

2、不复用线程的问题

        用户每发起一个请求,后台就需要创建一个新线程来处理,下次新任务来了肯定又要创建新线程处理,创建新线程的开销是很大的,并且请求过多时,肯定会产生大量的线程出来,这样会严重影响系统的性能。

        就好比:每次吃完饭都扔一个碗,长期以来肯定吃不消这么大的消耗。

3、线程池的工作原理

①工作线程

        工作线程:就是线程池里面的线程,来处理任务队列里面的任务,有点类似于饭店的服务员。

②任务队列

        任务队列:里面存放的都是实现了Runnable/Callable接口的任务类,等待工作线程的完成。

二、创建线程池

1、如何创建线程池?

方式一:JDK5.0开始,提供了代表线程池的接口:ExecutorService。使用ExecutorService的实现类ThreadPoolExecutor自创建一个线程池对象。

        该实现类 ThreadPoolExecutor的构造器一共有七个参数,如下:

        举例:
public class Test9 {public static void main(String[] args) {//目标:创建线程池对象来使用//1、使用线程池(ExecutorService接口)的实现类ThreadPoolExecutor声明七个参数来创建线程池对象ExecutorService pool = new ThreadPoolExecutor(3,5,10, TimeUnit.SECONDS,new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());}
}

方式二:使用Executors(线程池的工具类)调用方法返回不同特点的线程池对象。

下面五会讲。

2、线程池的注意事项

①什么时候开始创建临时线程?

        新任务提交时发现核心线程都在忙,任务队列也满了,并且还可以创建临时线程,此时才会创建临时线程。

②什么时候会拒绝新任务?

        核心线程和临时线程都在忙,任务队列也满了,新的任务过来的时候才会开始拒绝任务。

3、任务拒绝策略

三、处理Runnable任务

1、ExecutorService的常用方法

        举例:

public class Test9 {public static void main(String[] args) {//目标:创建线程池对象来使用//1、使用线程池(ExecutorService接口)的实现类ThreadPoolExecutor声明七个参数来创建线程池对象ExecutorService pool = new ThreadPoolExecutor(3,5,10,TimeUnit.SECONDS,new ArrayBlockingQueue<>(3),Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());//2、使用线程池处理任务!看会不会复用线程?Runnable target = new My_Runnable();//任务对象pool.execute(target);pool.execute(target);pool.execute(target);pool.execute(target);pool.execute(target);pool.execute(target);//3、关闭线程池:一般不关闭线程池//pool.shutdown();//等所有任务执行完毕后,再关闭线程池!//pool.shutdownNow();//立即关闭,不管任务是否执行完毕!}
}//线程任务类(等待被线程对象执行的任务)
class My_Runnable implements Runnable{@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "执行了~~");}
}

        执行结果:

pool-1-thread-2执行了~~
pool-1-thread-3执行了~~
pool-1-thread-2执行了~~
pool-1-thread-3执行了~~
pool-1-thread-2执行了~~
pool-1-thread-1执行了~~

        可见此时6个任务,但是线程池就3个核心线程,因此会产生复用。于是就看到上面确实有很多线程执行了好几个任务,因此线程确实是被复用了。

2、总结

四、处理Callable任务

1、ExecutorService的常用方法

        举例:

        

public class Test10 {public static void main(String[] args) {//目标:创建线程池对象来使用//1、使用线程池(ExecutorService接口)的实现类ThreadPoolExecutor声明七个参数来创建线程池对象ExecutorService pool = new ThreadPoolExecutor(3,5,10,TimeUnit.SECONDS,new ArrayBlockingQueue<>(3),Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());//2、使用线程池处理任务!看会不会复用线程?Future<String> f1 = pool.submit(new My_Callable(100));Future<String> f2 = pool.submit(new My_Callable(200));Future<String> f3 = pool.submit(new My_Callable(300));Future<String> f4 = pool.submit(new My_Callable(400));//输出线程执行完,返回的结果try {System.out.println(f1.get());System.out.println(f2.get());System.out.println(f3.get());System.out.println(f4.get());} catch (InterruptedException e) {throw new RuntimeException(e);} catch (ExecutionException e) {throw new RuntimeException(e);}//3、关闭线程池:一般不关闭线程池//pool.shutdown();//等所有任务执行完毕后,再关闭线程池!//pool.shutdownNow();//立即关闭,不管任务是否执行完毕!}
}//1、定义一个实现Callable接口的实现类
class My_Callable implements Callable<String>{private int n;public My_Callable(int n){this.n = n;}//2、重写call方法,定义线程执行体public String call() throws Exception {int sum = 0;for (int i = 0; i <= n; i++) {sum+=i;}return Thread.currentThread().getName()+"-"+n+"的和是:"+sum;}
}

运行结果:

pool-1-thread-1-100的和是:5050
pool-1-thread-2-200的和是:20100
pool-1-thread-3-300的和是:45150
pool-1-thread-1-400的和是:80200

可见此时线程1被复用。

2、总结

五、通过Executors工具类,创建线程池

1、该工具类中有哪些静态方法?

        举例:

        

public class Test10 {public static void main(String[] args) {//1、通过线程池工具类:Executors,调用其静态方法直接得到线程池ExecutorService pool = Executors.newFixedThreadPool(3);//2、使用线程池处理任务!看会不会复用线程?Future<String> f1 = pool.submit(new My_Callable(100));Future<String> f2 = pool.submit(new My_Callable(200));Future<String> f3 = pool.submit(new My_Callable(300));Future<String> f4 = pool.submit(new My_Callable(400));try {System.out.println(f1.get());System.out.println(f2.get());System.out.println(f3.get());System.out.println(f4.get());} catch (InterruptedException e) {throw new RuntimeException(e);} catch (ExecutionException e) {throw new RuntimeException(e);}//3、关闭线程池:一般不关闭线程池//pool.shutdown();//等所有任务执行完毕后,再关闭线程池!//pool.shutdownNow();//立即关闭,不管任务是否执行完毕!}
}//1、定义一个实现Callable接口的实现类
class My_Callable implements Callable<String>{private int n;public My_Callable(int n){this.n = n;}//2、重写call方法,定义线程执行体public String call() throws Exception {int sum = 0;for (int i = 0; i <= n; i++) {sum+=i;}return Thread.currentThread().getName()+"-"+n+"的和是:"+sum;}
}

运行结果:

pool-1-thread-1-100的和是:5050
pool-1-thread-2-200的和是:20100
pool-1-thread-3-300的和是:45150
pool-1-thread-3-400的和是:80200

2、Executors工具类使用时可能存在的风险

3、总结

六、并发、并行

1、什么是进程?

        正在运行的程序(软件)就是一个进程。

举例

2、什么是线程?

        线程属于进程,一个进程可以同时运行很多个线程。

        进程中的多个线程是并发+并行执行的。 

3、什么是并发?

        并发:进程中的线程是由CPU负责调度执行的,但CPU同时处理线程的数量是有限的(由CPU的核数决定),为了能保证全部线程都能往前执行,因此CPU会轮询为系统的每个线程服务,由于CPU切换的速度很快,给我们的感觉是这些线程在同时执行,这就是并发。

举例

假设我的CPU是单核的(同一时刻只能运行一个线程),但是会让很多线程轮流切换上CPU执行,切换速度极快,仿佛是同时在运行所有进程中的线程,这就叫“并发”。

4、什么是并行?

        并行:在同一个时刻上,同时有多个线程(数量取决于CPU的核数)在被CPU调度执行。

举例

假设我的CPU是4核,那么同一时刻,会有4个线程同时上cpu执行,这就叫“并行”。

                   说白了,并行的线程数,取决于CPU的核数。

 5、总结

举例

                    通过查看某人电脑的任务管理器,得知该电脑的CPU是20核的,也就是说,同一时刻允许20个线程上CPU执行,那么这20个线程就是并行关系;

                   该电脑目前需要处理6800个线程,那么就会20个一组上CPU轮流切换运行,由于切换速度极快,仿佛是同时在运行,这就叫“并发”。

六、综合案例-抢红包游戏

1、介绍

2、编码

public class Test12 {public static void main(String[] args) {/*** 目标:完成多线程的综合小案例* 红包雨游戏:某企业有100名员工,员工的工号依次是1,2,3,4...到100* 现在公司举办了年会活动,活动中有一个红包雨环节,要求共计发出200个红包雨,其中小红包在【1 - 30】 元之间* 总占比80%,大红包在【31 - 100】元, 总占比20%* 分析:100个员工实际上就是100个线程,来竞争200个红包*/List<Integer> redPacket = getRedPacket();//2、定义线程类,创建100个线程,竞争同一个集合for (int i = 1; i <= 100; i++) {new EmployeeGetPacket(redPacket, "员工"+i).start();}}//1、准备这200个随机的红包返回,放到这个List集合中public static List<Integer> getRedPacket(){Random r = new Random();//其中小红包在【1 - 30】 元之间,总占比80%(即160个),大红包在【31 - 100】元,总占比为20%(即40个)ArrayList<Integer> redPacket = new ArrayList<>();for (int i = 1; i <= 160; i++) {redPacket.add(r.nextInt(30) + 1);}for (int i = 1; i <= 40; i++) {redPacket.add(r.nextInt(70) + 31);}return redPacket;}
}//员工抢红包的线程
class EmployeeGetPacket extends Thread{private List<Integer> redPacket;//红包集合//构造器public EmployeeGetPacket(List<Integer> redPacket, String name) {super(name);this.redPacket = redPacket;}public void run() {String name = Thread.currentThread().getName();while(true){//100个人来抢redPackage集合中的钱synchronized (redPacket){if(redPacket.size() == 0){break;}//随机一个索引得到红包int index = (int)(Math.random() * redPacket.size());Integer money = redPacket.remove(index);System.out.println(name + "抢到了" + money + "元");if(redPacket.size() == 0){System.out.println("活动结束!");break;}}try {Thread.sleep(1000);}catch (InterruptedException e){throw new RuntimeException(e);}}}
}

运行结果:

员工1抢到了3元
员工99抢到了20元
员工98抢到了59元
员工100抢到了14元
员工96抢到了2元
员工97抢到了17元
员工95抢到了20元
员工94抢到了12元
员工93抢到了8元
员工92抢到了26元
员工91抢到了7元
...不全部展示了,因为200条抢红包记录,太长了...

以上就是线程池、并发、并行、抢红包游戏案例的全部内容,想了解更多Java知识,请关注本博主~~

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

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

相关文章

【WPF】Prism库学习(一)

Prism介绍 1. Prism框架概述&#xff1a; Prism是一个用于构建松耦合、可维护和可测试的XAML应用程序的框架。它支持WPF、.NET MAUI、Uno Platform和Xamarin Forms等多个平台。对于每个平台&#xff0c;Prism都有单独的发布版本&#xff0c;并且它们在不同的时间线上独立开发。…

通过华为鲲鹏认证发行上市的集成平台产品推荐

华为鲲鹏认证是技术实力与品质的权威象征&#xff0c;代表着产品达到了高标准的要求。从技术层面看&#xff0c;认证确保产品与华为鲲鹏架构深度融合&#xff0c;能充分释放鲲鹏芯片的高性能、低功耗优势&#xff0c;为集成平台的高效运行提供强大动力。在安全方面&#xff0c;…

STM32 ADC --- 任意单通道采样

STM32 ADC — 单通道采样 文章目录 STM32 ADC --- 单通道采样cubeMX配置代码修改&#xff1a;应用 使用cubeMX生成HAL工程 需求&#xff1a;有多个通道需要进行ADC采样&#xff0c;实现每次采样只采样一个通道&#xff0c;且可以随时采样不同通道的功能。 cubeMX配置 这里我们…

web——upload-labs——第十二关——%00截断

查看源码 分析源码我们可以知道&#xff0c;这里是基于白名单过滤&#xff0c;只允许上传jpg,png,gif&#xff0c;但是这里注意第八行&#xff0c;上传路径是可以控制的&#xff0c;所以可以利用%00截断&#xff0c;来达到上传木马的目的。这里要注意一下&#xff0c;%00截断想…

STM32 创建一个工程文件(寄存器、标准库)

首先到官网下载对应型号的固件包&#xff1a; 像我的STM32F103C8T6的就下载这个&#xff1a; 依次打开&#xff1a; .\STM32F10x_StdPeriph_Lib_V3.5.0\STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\arm 可以看到&#xff1a; 这…

Spark:大数据处理的强大引擎

一、Spark 简介 Apache Spark 是一个专为大规模数据处理而设计的快速、通用、可扩展的大数据分析计算引擎。它诞生于 2009 年&#xff0c;由美国加州伯克利大学的 AMP 实验室开发&#xff0c;2013 年被纳入 Apache 开源项目&#xff0c;并迅速成为顶级项目。 Spark 被认为是 …

鸿蒙HarmonyOS 地图定位到当前位置 site查询等操作

应用服务Map使用 地图定位 地点查询及导航 周边查询 点位标记定义等 地图定位 前提地图已经能正常显示&#xff0c;若不能显示请大家参考之前的那篇如何显示地图的博文 地图相关的api 位置效果图&#xff1a; module.json5配置权限 "requestPermissions": [{&…

编程语言02:语法基础

一、注释 (一)单行注释 java&#xff1a;//&#xff0c;快捷键 Ctrl/ package Summarize;public class L01_01 {public static void main(String[] args) {// 单行注释&#xff0c;快捷键Ctrl/} }python:#,快捷键Ctrl/ # python单行注释 (二)多行注释 java /*java多行注释…

ubuntu24.04网卡配置

vim /etc/netplan/01-netcfg.yaml /24表示子网掩码的长度。这种表示法称为CIDR&#xff08;无类别域间路由&#xff09;记法。CIDR记法将IP地址和它们的子网掩码合并为一个单一的值&#xff0c;其中斜杠/后面的数字表示子网掩码中连续的1的位数。 对于/24&#xff1a; 24表示…

基于普中51单片机开发板的电子门铃设计( proteus仿真+程序+设计报告+讲解视频)

基于普中51单片机开发板的电子门铃设计( proteus仿真程序设计报告讲解视频&#xff09; 仿真图proteus8.15(有低版本) 程序编译器&#xff1a;keil 4/keil 5 编程语言&#xff1a;C语言 设计编号&#xff1a;P17 1. 主要功能&#xff1a; 基于51单片机的电子门铃设计 1、…

HTML and CSS Support HTML 和 CSS 支持

GoTo DevExpress Data Grid 数据网格 HTML and CSS Support HTML 和 CSS 支持 HTML和CSS支持允许您创建完全自定义的UI元素&#xff0c;并消除使用基于属性的UI自定义和CustomDraw事件。您可以构建 HTML 格式的 UI&#xff0c;并使用 CSS 样式自定义 UI 元素的外观设置、大小、…

掌握Golang中的数据竞争检测:runtime/race包全面教程

掌握Golang中的数据竞争检测&#xff1a;runtime/race包全面教程 引言数据竞争问题概述数据竞争的定义数据竞争对程序的影响常见数据竞争场景 Golang runtime/race包概述runtime/race包简介启用数据竞争检测使用 go run使用 go build使用 go test 基本用法与示例单元测试中的使…

Ascend C算子性能优化实用技巧05——API使用优化

Ascend C是CANN针对算子开发场景推出的编程语言&#xff0c;原生支持C和C标准规范&#xff0c;兼具开发效率和运行性能。使用Ascend C&#xff0c;开发者可以基于昇腾AI硬件&#xff0c;高效的实现自定义的创新算法。 目前已经有越来越多的开发者使用Ascend C&#xff0c;我们…

【HCIP]——OSPF综合实验

题目 实验需求 根据上图可得&#xff0c;实验需求为&#xff1a; 1.R5作为ISP&#xff1a;其上只能配置IP地址&#xff1b;R4作为企业边界路由器&#xff0c;出口公网地址需要通过PPP协议获取&#xff0c;并进行CHAP认证。&#xff08;PS&#xff1a;因PPP协议尚未学习&#…

深入理解Redis(七)----Redis实现分布式锁

基于Redis的实现方式 1、选用Redis实现分布式锁原因&#xff1a; &#xff08;1&#xff09;Redis有很高的性能&#xff1b; &#xff08;2&#xff09;Redis命令对此支持较好&#xff0c;实现起来比较方便 2、使用命令介绍&#xff1a; &#xff08;1&#xff09;SETNX SETNX …

Python-简单病毒程序合集(一)

前言&#xff1a;简单又有趣的Python恶搞代码&#xff0c;往往能给我们枯燥无味的生活带来一点乐趣&#xff0c;激发我们对编程的最原始的热爱。那么话不多说&#xff0c;我们直接开始今天的编程之路。 编程思路&#xff1a;本次我们将会用到os,paltform,threading,ctypes,sys,…

Web3浪潮下的区块链应用:从理论到实践的全面解析

随着Web3的兴起&#xff0c;区块链技术作为其核心支撑&#xff0c;正迎来前所未有的应用爆发。Web3不仅仅是技术的革新&#xff0c;更代表了一种去中心化、开放、透明的互联网愿景。在这一背景下&#xff0c;区块链技术的应用正从理论走向实践&#xff0c;推动着各行各业的数字…

网络安全:我们的安全防线

在数字化时代&#xff0c;网络安全已成为国家安全、经济发展和社会稳定的重要组成部分。网络安全不仅仅是技术问题&#xff0c;更是一个涉及政治、经济、文化、社会等多个层面的综合性问题。从宏观到微观&#xff0c;网络安全的重要性不言而喻。 宏观层面&#xff1a;国家安全与…

鸿蒙北向开发环境安装指南

境界一&#xff1a;昨夜西风凋碧树。独上高楼&#xff0c;望尽天涯路。----------王静安《人间词话》 单元一&#xff1a;鸿蒙开发工具的安装 学习目标 &#xff08;1&#xff09;完成鸿蒙开发工具Deveco Studio的安装。 任务1.1 下载DevEcoStudio 任务描述 DevEco Studi…

51单片机基础01 单片机最小系统

目录 一、什么是51单片机 二、51单片机的引脚介绍 1、VCC GND 2、XTAL1 2 3、RST 4、EA 5、PSEN 6、ALE 7、RXD、TXD 8、INT0、INT1 9、T0、T1 10、MOSI、MISO、SCK 11、WR、RD 12、通用IO P0 13、通用IO P1 14、通用IO P2 三、51单片机的最小系统 1、供电与…