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

多线程案例(4)-线程池

文章目录

  • 多线程案例四
  • 四、线程池

大家好,我是晓星航。今天为大家带来的是 多线程案例-线程池 相关的讲解!😀

多线程案例四

四、线程池

线程池是什么

虽然创建线程 / 销毁线程 的开销

想象这么一个场景:

在学校附近新开了一家快递店,老板很精明,想到一个与众不同的办法来经营。店里没有雇人, 而是每次有业务来了,就现场找一名同学过来把快递送了,然后解雇同学。这个类比我们平时来一个任务,起一个线程进行处理的模式。

很快老板发现问题来了,每次招聘 + 解雇同学的成本还是非常高的。老板还是很善于变通的,知道了为什么大家都要雇人了,所以指定了一个指标,公司业务人员会扩张到 3 个人,但还是随着 业务逐步雇人。于是再有业务来了,老板就看,如果现在公司还没 3 个人,就雇一个人去送快 递,否则只是把业务放到一个本本上,等着 3 个快递人员空闲的时候去处理。这个就是我们要带出的线程池的模式。

🧨线程池最大的好处就是减少每次启动、销毁线程的损耗。🧨

标准库中的线程池

  • 使用 Executors.newFixedThreadPool(10) 能创建出固定包含 10 个线程的线程池.
  • 返回值类型为 ExecutorService
  • 通过 ExecutorService.submit 可以注册一个任务到线程池中.
ExecutorService pool = Executors.newFixedThreadPool(10);
pool.submit(new Runnable() {@Overridepublic void run() {System.out.println("hello");}
});

上述代码第一行代码就是创建了一个线程池,池子里线程数目固定是10个。

这个操作,使用某个类的某个静态方法,直接构造出了一个对象来(相当于是把 new 操作,给隐藏到这样的方法后面了)

像这样的方法,就称为"工厂方法"

提供工厂方法的类,也就成为"工厂类"

此处这个代码就使用了"工厂模式"这种 设计模式

那么什么是工厂模式呢?

答:工厂模式,一句话表示,使用普通的方法来代替构造方法,创建对象。为啥要代替呢,因为构造方法有坑,他只能构造一种对象,如果要构造多种不同情况的对象,就难搞了。

例如我们需要使用笛卡尔坐标系来构造坐标,空间直角坐标系和极坐标系,那么此时我们的代码就会是:

class Point {//构造空间直角坐标系public Point(double x, double y) {}//构造极坐标系public Point(double r, double a) {}
}

显然此时我们虽然可以用代码写出并构造出这两个坐标系,但是他们是❌错误的,因为我们的构造方法只能构造一个对象。而普通方法是可以构造多个对象的

那么就会有人问了我们不是可以通过重载的方法来进行多个构造方法吗,此时我们来看一下重载的要求,重载要求的是:方法名相同,参数的个数或者类型不相同。

因此我们这里根本不可能进行重载调用。

普通方法构建笛卡尔坐标系代码:

class PointFactory {public static Point makePointByXY(double x,double y) {}public static Point makePointByRA(double r,double a) {}
}
public class ThreadDemo26 {public static void main(String[] args) {Point P = PointFactory.makePointByXY(10,20);}
}

普通方法,方法名字没有限制。因此有多种方式构造,就可以直接使用不同的方法名即可。此时,方法的参数是否要区分,已经不重要了

这里我们区分一下重载和重写的区别:

重载(overload):指一个类中可以有多个方法具有相同的名字,但这些方法的参数不同(参数的类型和个数不同)。分别在父类子类里也是可能构成重载的。

重写(override):在不同类中(指父类和子类)中,两个具有相同方法名和相同参数的方法,称作重写。 (如果是其他语言,重写方法不一定通过父类子类)

重写本质上就是用一个新的方法,代替旧的… 就得要求新的方法和旧的方法,名字/参数都得一摸一样

下面我们为大家带来几个线程池的使用举例:

运行程序之后发现,main线程结束了,但是整个进程没有结束。线程池中的线程都是 前台线程。此时会阻止进程结束。(前面定时器 Timer 也是同理)

下属代码为什么不能直接写 System.*out*.println("hello" + n); 呢?

答:因为变量捕获,这里的 i 是主线程里的局部变量(在主线程的栈上),随着主线程这里的代码块执行结束就销毁了。很可能主线程这里的 for 执行完了,当前 run 的任务在线程池里还没排到呢,此时 i 就销毁了

变量捕获(必须是不可修改的变量才能捕获 有final修饰的变量也可捕获):在定义 run 的时候,偷偷把 i 当前的值记住。后续执行run的时候,就创建一个也叫做 i 的局部变量,并且把这个值赋值过去

final:

final修饰类,表示该类是无法被任何其他类继承的,意味着此类在一个继承树中是一个叶子类,并且此类的设计已被认为很完美而不需要进行修改或扩展。

final修饰类中的方法,表示该类是无法被任何其他类继承的,不可以被重写;也就是把该方法锁定了,以防止继承类对其进行更改。

final修饰类中的变量,表示该变量一旦被初始化便不可改变。

此处要注意,当前是往线程池里放了1000个任务,1000个任务就是让这 10 个线程来平均分配一下,差不多一个线程执行100个任务,但是注意这里并非是严格的平均,可能有的多一个有的少一个,都很正常。(每个线程都执行完一个任务之后,再立即取下一个任务,由于每个任务执行时间都差不多,因此每个线程做的任务数量就差不多)

进一步的可以认为,这1000个任务,就在一个队列里排队,这10个线程,就依次来取队列中的任务,取一个就执行一个,执行完了之后再执行下一个。

因为线程调度是随机分配的,因此会出现顺序不一样的情况。

Executors 创建线程池的几种方式

  • newFixedThreadPool: 创建固定线程数(可能是多个)的线程池
  • newCachedThreadPool: 创建线程数目动态增长的线程池.
  • newSingleThreadExecutor: 创建只包含单个线程的线程池.
  • newScheduledThreadPool: 设定 延迟时间后执行命令,或者定期执行命令. 是进阶版的 Timer. 执行的时候不是由扫描线程自己执行,而是由单独的线程池来执行。

总结:实践中确定的线程数量,也很简单,通过测试/实验的方式

Executors 本质上是 ThreadPoolExecutor 类的封装.

ThreadPoolExecutor 提供了更多的可选参数, 可以进一步细化线程池行为的设定. (后面再介绍)

实现线程池

  • 核心操作为 submit, 将任务加入线程池中 使用 Worker 类描述一个工作线程.
  • 使用 Runnable 描述一个任务.
  • 使用一个 BlockingQueue 组织所有的任务
  • 每个 worker 线程要做的事情: 不停的从 BlockingQueue 中取任务并执行.
  • 指定一下线程池中的最大线程数 maxWorkerCount; 当当前线程数超过这个最大值时, 就不再新增 线程了.
class Worker extends Thread {private LinkedBlockingQueue<Runnable> queue = null;public Worker(LinkedBlockingQueue<Runnable> queue) {super("worker");this.queue = queue;}@Overridepublic void run() {// try 必须放在 while 外头, 或者 while 里头应该影响不大try {while (!Thread.interrupted()) {Runnable runnable = queue.take();runnable.run();}} catch (InterruptedException e) {}}
}
public class MyThreadPool {private int maxWorkerCount = 10;private LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue();public void submit(Runnable command) {if (workerList.size() < maxWorkerCount) {// 当前 worker 数不足, 就继续创建 workerWorker worker = new Worker(queue);worker.start();}// 将任务添加到任务队列中queue.put(command);}public static void main(String[] args) throws InterruptedException {MyThreadPool myThreadPool = new MyThreadPool();myThreadPool.execute(new Runnable() {@Overridepublic void run() {System.out.println("吃饭");}});Thread.sleep(1000);}
}

自己实现线程池版本二:

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;/*** Created with IntelliJ IDEA.* Description:* User: 晓星航* Date: 2023-08-01* Time: 15:16*/
class MyThreadPoll {//此处不涉及 "时间",此处只有任务,就直接使用 Runnable 即可~~private BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();//n 表示线程的数量public MyThreadPoll(int n) {//在这里创建线程for (int i = 0; i < n; i++) {Thread t = new Thread(()->{while (true) {try {Runnable runnable = queue.take();runnable.run();} catch (InterruptedException e) {e.printStackTrace();}}});t.start();}}//注册任务给线程池public void submit(Runnable runnable) {try {queue.put(runnable);} catch (InterruptedException e) {e.printStackTrace();}}
}public class ThreadDemo27 {public static void main(String[] args) {MyThreadPoll pool = new MyThreadPoll(10);for (int i = 0; i < 1000; i++) {int n = i;pool.submit(new Runnable() {@Overridepublic void run() {System.out.println("hello" + n);}});}}
}

四个拒绝策略:

例如我们此时在学习,而有好朋友叫我们去打游戏

那么对应上面情况:

  1. 要学习的东西太多,我直接开摆,啥也不干了…
  2. 学习任务太多了,让朋友们自己去玩。(此时朋友们自己去打游戏了)
  3. 直接不学了,开玩!
  4. 拒绝去玩,继续学习。(至于朋友们有没有玩我们不必管)

感谢各位读者的阅读,本文章有任何错误都可以在评论区发表你们的意见,我会对文章进行改正的。如果本文章对你有帮助请动一动你们敏捷的小手点一点赞,你的每一次鼓励都是作者创作的动力哦!😘

相关文章:

多线程案例(4)-线程池

文章目录 多线程案例四四、线程池 大家好&#xff0c;我是晓星航。今天为大家带来的是 多线程案例-线程池 相关的讲解&#xff01;&#x1f600; 多线程案例四 四、线程池 线程池是什么 虽然创建线程 / 销毁线程 的开销 想象这么一个场景&#xff1a; 在学校附近新开了一家…...

【数据结构OJ题】轮转数组

原题链接&#xff1a;https://leetcode.cn/problems/rotate-array/ 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 1. 方法一&#xff1a;暴力求解&#xff0c;将数组的第一个元素用临时变量tmp存起来&#xff0c;再将数组其他元素往右挪动一步&…...

现代C++中的从头开始深度学习:【4/8】梯度下降

一、说明 在本系列中&#xff0c;我们将学习如何仅使用普通和现代C编写必须知道的深度学习算法&#xff0c;例如卷积、反向传播、激活函数、优化器、深度神经网络等。 在这个故事中&#xff0c;我们将通过引入梯度下降算法来介绍数据中 2D 卷积核的拟合。我们将使用卷积和上一个…...

Yolov5缺陷检测/目标检测 Jetson nx部署Triton server

使用AI目标检测进行缺陷检测时&#xff0c;部署到Jetson上即小巧算力还高&#xff0c;将训练好的模型转为tensorRT再部署到Jetson 上供http或GRPC调用。1 Jetson nx 刷机 找个ubuntu 系统NVIDIA官网下载安装Jetson 的sdkmanager一步步刷机即可。 本文刷的是JetPack 5.1, 其中包…...

MobaXterm 中文乱码, 及pojie

中文解决方法&#xff1a; 把“连字”去掉&#xff01; MobaXterm网页&#xff0c;可以生成一个授权文件Custom.mxtpro。放在安装目录就可以了 MobaXterm Keygen (husbin.top)http://b70.husbin.top:5000/...

java: 程序包sun.misc不存在

启动失败&#xff0c;rebuild时也报错&#xff1a;java: 程序包sun.misc不存在 问题出在JDK版本上&#xff0c;这个包在JDK9的时候已经被弃用了&#xff0c;这里改回JDK8即可 步骤如下&#xff1a;...

WSL2Linux 子系统(五)

WLS2Linux 子系统编译 Android 上一篇文章中讲解 《WLS2Linux 子系统迁移/恢复》&#xff0c;从C盘迁移到D盘。既可以防止C盘爆红&#xff0c;又可以释放磁盘空间。有更大存储空间意味大有可为&#xff0c;比如说编译Android系统。本文则以开源 firefly Android10代码为例简单…...

java 企业工程管理系统软件源码 自主研发 工程行业适用 em

​ 工程项目管理软件&#xff08;工程项目管理系统&#xff09;对建设工程项目管理组织建设、项目策划决策、规划设计、施工建设到竣工交付、总结评估、运维运营&#xff0c;全过程、全方位的对项目进行综合管理 工程项目各模块及其功能点清单 一、系统管理 1、数据字典&#…...

IPO观察丨困于门店扩张的KK集团,还能讲好增长故事吗?

KK集团发起了其IPO之路上的第三次冲击。 近日&#xff0c;KK集团更新了招股书&#xff0c;继续推进港交所上市进程&#xff0c;此前两次上市搁置后终于有了新动向。从更新内容来看&#xff0c;KK集团招股书披露了公司截至2023年一季度的最新业绩&#xff0c;交出一份不错的“成…...

【iOS】RunLoop

前言-什么是RunLoop&#xff1f; 什么是RunLoop? 跑圈&#xff1f;字面上理解确实是这样的。 Apple官方文档这样解释RunLoop RunLoop是与线程息息相关的基本结构的一部分。RunLoop是一个调度任务和处理任务的事件循环。RunLoop的目的是为了在有工作的时候让线程忙起来&#…...

数据包传输方式:单播、多播、广播、组播、泛播

数据包传输方式 单播、多播、广播、组播、泛播 网络中假设X代表所有的机器&#xff0c;Y代表X中的一部分机器&#xff0c;Z代表一组机器&#xff0c;1代表一台机器&#xff0c;那么 1&#xff1a;1 那就是单播&#xff1b;1&#xff1a;Y 那就是多播&#xff1b;1&#xff1…...

WebRTC基础知识

文章目录 基础概念NAT (Network Address Translation) 打洞STUN&#xff08;Session Traversal Utilities for NAT&#xff09;基于STUN协议的DDoS反射攻击 # TODO TURN&#xff08;Traversal Using Relays around NAT&#xff09;ICE&#xff08;Interactive Connectivity Est…...

积累常见的有针对性的python面试题---python面试题001

1.考点列表的.remove方法的参数是传入的对应的元素的值,而不是下标 然后再看remove这里,注意这个是,删除写的那个值,比如这里写3,就是删除3, 而不是下标. remove不是下标删除,而是内容删除. 2.元组操作,元组不支持修改,某个下标的内容 可以问他如何修改元组的某个元素 3.…...

在springboot使用websocket时mapper无法注入

直接上代码 package cn.ujoined.combined.utils;import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Componen…...

前端加密与解密的几种方式

1.base64加密方式 1. base64是什么&#xff1f; Base64&#xff0c;顾名思义&#xff0c;就是包括小写字母a-z、大写字母A-Z、数字0-9、符号""、"/"一共64个字符的字符集&#xff0c;&#xff08;另加一个“”&#xff0c;实际是65个字符&#xff0c;至于…...

详解Spring Bean的生命周期

详解Spring Bean的生命周期 Spring Bean的生命周期包括以下阶段&#xff1a; 1. 实例化Bean 对于BeanFactory容器&#xff0c;当客户向容器请求一个尚未初始化的bean时&#xff0c;或初始化bean的时候需要注入另一个尚未初始化的依赖时&#xff0c;容器就会调用createBean进…...

详解Shell 脚本中 “$” 符号的多种用法

通常情况下&#xff0c;在工作中用的最多的有如下几项&#xff1a; $0&#xff1a;Shell 的命令本身 1到9&#xff1a;表示 Shell 的第几个参数 $? &#xff1a;显示最后命令的执行情况 $#&#xff1a;传递到脚本的参数个数 $$&#xff1a;脚本运行的当前进程 ID 号 $*&#…...

Redis如何实现Session存储

在Redis中实现Session存储,主要有两种方式:使用Spring Session和手动存储。 使用Spring Session:Spring Session是Spring框架提供的一个模块,用于简化Session管理,并将Session数据存储到外部数据存储中,如Redis。使用Spring Session,你只需要在Spring Boot项目中添加相应…...

安防视频监控汇聚EasyCVR平台接入Ehome告警,公网快照不显示的原因排查

智能视频监控汇聚平台TSINGSEE青犀视频EasyCVR可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等&#xff0c;视频监控管理平台…...

【Springboot】@ComponentScan 详解

文章目录 ComponentScanComponentScan ANNOTATION 和 REGEXComponentScan CUSTOMComponentScan ASSIGNABLE_TYPE ComponentScan ComponentScan 是 Spring 框架中的一个注解&#xff0c;用于自动扫描和注册容器中的组件。 使用 ComponentScan 注解可以告诉 Spring 在指定的包或…...

flask-----信号

安装&#xff1a; flask中的信号使用的是一个第三方插件&#xff0c;叫做blinker。通过pip list看一下&#xff0c;如果没有安装&#xff0c;通过以下命令即可安装blinker&#xff1a; pip install blinker flask其中有内置的信号 template_rendered _signals.signal(temp…...

10_Vue3 其它的组合式API(Composition API)

Vue3 中的其它组合式API 1.shallowReactive 与 shallowRef 2. readonly 与 shallowReadonly 3.toRaw 与 markRaw 4.customRef 5.provide 与 inject 6.响应式数据的判断...

COCOS项目运行的时候图片模糊的原因

1、首先。用X坐标来分析&#xff0c;如果size*Anchor Position有小数&#xff0c;如上图57*0.5667695.5。这样就会导致x模糊。如果y同样计算结果包含小数&#xff0c;那么y也会模糊。xy同时模糊的情况是最模糊的。 2、如果当前node没有问题&#xff0c;那么就要检查上级node是…...

Python中搭建IP代理池的妙招

在Python的爬虫世界里&#xff0c;你是否也想搭建一个功能强大的IP代理池&#xff0c;让你的爬虫无忧无虑地畅游各大网站&#xff1f;今天&#xff0c;我就来教你使用Scrapy框架搭建IP代理池&#xff0c;让你的爬虫更加智能、高效&#xff01;跟着我一步一步来&#xff0c;轻松…...

学习pytorch 2

学习pytorch 2 2. dataset实战代码数据集 2. dataset实战 B站小土堆视频 代码 from torch.utils.data import Dataset from PIL import Image #import cv2 import osclass MyData(Dataset):def __init__(self, root_dir, label_dir):self.root_dir root_dirself.label_dir …...

elementui动态表单实现计算属性携带参数,并将计算出的值四舍五入保留两位小数

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言方法1方法2结论 前言 写项目的时候&#xff0c;遇到需要在动态表单中&#xff0c;将同一级输入框输入的内容计算出来&#xff0c;并动态显示&#xff0c;发现c…...

嵌入式面试5 -makefile shell

2、 如果有一个简单的helloworld项目目录如下&#xff1a; tree helloworld helloworld |– file2.h |– file1.cpp |– file2.cpp 请编写一个Makefile文件。 答&#xff1a; TARGET helloworld CXX g COMPILE : $(COMPILE) file1.cpp COMPILE : $(COMPILE) file2.cpp OBJE…...

获40余家主机厂青睐,这家OTA「吸金王」完成超亿元B2轮融资!

继今年4月获得上汽集团旗下尚颀资本及其合作方山高投控的投资后&#xff0c;近日上海艾拉比智能科技有限公司&#xff08;以下简称“艾拉比”&#xff09;正式完成总额过亿元的B2轮融资&#xff0c;新的投资方为聚卓资本、老股东国科新能继续增持&#xff0c;势能资本持续担任独…...

CGI, FastCGI, WSGI, uWSGI, uwsgi分别是什么?

CGI 1、通用网关接口&#xff08;Common Gateway Interface/CGI&#xff09;,CGI描述了服务器&#xff08;nginx,apache&#xff09;和请求处理程序&#xff08;django,flask,springboot web框架&#xff09;之间传输数据的一种标准. 2.所有bs架构软件都是遵循CGI协议的 3.一…...

Android T 窗口层级相关的类(更新中)

窗口在App端是以PhoneWindow的形式存在&#xff0c;承载了一个Activity的View层级结构。这里我们探讨一下WMS端窗口的形式。 可以通过adb shell dumpsys activity containers 来看窗口显示的层级 窗口容器类 —— WindowContainer类 /*** Defines common functionality for c…...

合肥微网站建设/seo搜索引擎优化培训班

支持安卓9哦 无root党不进来看看吗更新安卓9后&#xff0c;相信大家的平行空间都会闪退吧 是不是很烦恼呢 我分享的这个平行空间精简版是最新版的&#xff0c;支持安卓9 不会闪退&#xff0c;本人米8 安卓9完美运行&#xff0c;新人发帖不关照一下吗[应用名称]: 平行空间精简版…...

java有没有做项目的网站/营销推广有哪些公司

Commons-SCXML 是一个状态机框架&#xff0c; 首先介绍状态机相关的术语。 1、状态机相关术语 1、1状态机 是一种行为&#xff0c;他说明对象在它的生命周期中响应事件所经历的状态序列以及对那些事件的响应。 1、2状态 是指对象的生命周期中的条件或者状况。在此期间对象将…...

个人业务网站建设/windows系统优化软件

欢迎使用Xcode Xcode是Apple的集成开发环境(IDE)。您使用Xcode为Apple产品(包括iPad,iPhone,Apple Watch,Apple TV和Mac)构建应用程序。 Xcode提供了用于管理整个开发工作流程的工具-从创建您的应用程序到测试,优化并将其提交到App Store。 项目将组织开发应用程序所…...

潍坊网站的公司电话/seo查询seo

一&#xff0c;利用网站浏览器F12键&#xff0c;利用谷歌浏览器插件找到视频的.m3u8文件&#xff0c;并打开。 二&#xff0c;打开m3u8文件后&#xff0c;里面有很多.ts的链接&#xff0c;和key的链接。 三&#xff0c;保存为html文件&#xff0c;下载ts文件&#xff0c;代码如…...

做雨棚的网站/中国职业培训在线

IEEE的会议论文模板是双栏&#xff08;两列&#xff09;&#xff0c;插入较宽的图时&#xff0c;不好受 https://github.com/DeathKing/LaTeX-Template-Cn/tree/master/Paper/CHN-PaperTemplate...

图片下载 wordpress/百度seo最成功的优化

假设有一个很长的花坛&#xff0c;一部分地块种植了花&#xff0c;另一部分却没有。可是&#xff0c;花不能种植在相邻的地块上&#xff0c;它们会争夺水源&#xff0c;两者都会死去。 给你一个整数数组 flowerbed 表示花坛&#xff0c;由若干 0 和 1 组成&#xff0c;其中 0 …...