首页 > Python资料 博客日记
千万别从系统中创建线程, 看看从线程池中调用的线程的效率(实践篇)
2024-08-14 21:00:04Python资料围观58次
本篇会加入个人的所谓鱼式疯言
❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言
而是理解过并总结出来通俗易懂的大白话,
小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的.
🤭🤭🤭可能说的不是那么严谨.但小编初心是能让更多人能接受我们这个概念 !!!
在当今这个多核处理器成为标配的时代,如何高效地利用计算资源已成为软件开发中不可忽视的关键因素。随着应用程序变得越来越复杂,对并发处理的需求也日益增长。试想一下,在一个繁忙的服务器上,如果每一个新任务都创建一个新的线程来处理,那么系统将不堪重负——频繁的线程创建和销毁不仅消耗大量的时间和内存,还可能导致系统性能急剧下降。
前言
为了解决这一问题,并实现 更高效的资源管理 ,线程池
的概念应运而生。线程池是一种用于 管理和复用一组预先创建好的线程 的方法
它通过 预先创建一定数量的工作线程 并将其 置于池中等待分配任务 ,从而 避免了频繁创建和销毁线程
带来的开销。
而在本篇文章中,小编将延续上篇我们对 线程池的初识
, 以及 线程池的参数理解
在篇文章中来 实际运用并实现我们线程池 的学习。
-
线程池的使用
-
线程池的实现
一. 线程池的使用
在我们 Java的标准库 中就封装了很多不同参数列表的线程池,所代表的功能和原理大体上是相似的, 但 实际的使用细节和适用场景还是不同 的。
而小编这次主要带着小伙伴们了解两种我们实际开发中比较常见的 两种线程池创建的方法
他们都属于 Executors
这个类下的 静态方法
第一种:
newFixedThreadPool()
方法下的可 自定义核心线程 个数的一类方法
第二种:
newCachedThreadPool()
方法下根据需求自动创建 一定数量的非核心方法
的一类方法
1. newFixedThreadPool()
<1>. 代码展示
package ThreadDemo.ThreadPoolDemo;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ForkJoinPool;
public class ExecutorTest {
public static void main(String[] args) throws InterruptedException {
// 利用这个方法造一个线程池
ExecutorService executorService = Executors.newFixedThreadPool(4);
// 循环遍历来打印每一个线程
for (int i = 0; i < 10; i++) {
// 线程开始执行
int id = i;
executorService.submit(()->{
Thread t = Thread.currentThread();
System.out.println("submit: "+ t.getName() + " 正在运行"+ id);
});
}
// 等待
Thread.sleep(1000);
// 结束创建的所有线程
executorService.shutdown();
System.out.println("程序结束!");
}
}
<2> . 实际运用分析
在上面的代码中
- 首先我们 创建线程池, 并指定核心线程的个数
- 在for 循环中调用
submit
来重写 run方法 充分利用创建的这几个线程来完成我们需要的工作
- 最终
shutdown()
来 终止所有线程的结束 。
鱼式疯言
上面我们通过
newFixedThreadPool()
创建指定 数目的线程池
这样的场景特别适用于我们知道这个场景是
最大限度
,并能够 充分利用我们的线程池中的线程资源 。
2. newCachedThreadPool()
<1>. 代码演示
package TestDemo6;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
public class Test1 {
public static void main(String[] args) {
// 创建线程池
ExecutorService executorService1 = Executors.newCachedThreadPool();
// 通过循环的方式进行线程的使用
for (int i = 0; i < 10; i++) {
int id = i;
executorService1.submit(()-> {
Thread t= Thread.currentThread();
System.out.println(" 当前线程名为: " + t.getName() + "id为 "+ id);
});
}
// 结束所有线程
executorService1.shutdown();
}
}
<2>. 运用分析
在上面的代码中
- 首先我们创建了 线程池, 这里 不需要 传递参数,线程池会根据需求动态的创建一定数量的线程 来进行工作。
- 循环使用线程池来,在
submit()
中重写run 方法
来 执行任务 。
- 最终在调用
shutdown
来 终止线程 。
鱼式疯言
这个线程池中最大的线程个数为
Integer
的 最大取值 , 也就是21亿
。
这么大的线程池是非常适合我们
Java程序员对于服务器的开发
会用到这个 线程池 。
二. 线程池的实现
我们知道了如何使用,那么我们就要往 更深的层次去理解 ,如何通过这些线程池的功能,实现一份我们自己的简单线程池呢 ? ? ? 🤔🤔🤔
答案是 可以的 。
这里小编只演示线程池有参数的 newFixedThreadPool()
的 方法实现 哦
小伙伴只需要掌握到这种程度就足够了哦 💖 💖 💖 💖
1. 线程池实现展示
class MyPoolThread {
// 用一个阻塞队列来存储工作任务
BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(1000);
public MyPoolThread(int nThreads) {
for (int i = 0; i < nThreads; i++) {
// 实例化线程
Thread thread = new Thread(()->{
// 使用while 的方式让 n 个线程都存在
// 并且进行抢占执行
while(true) {
try {
Runnable t = queue.take();
t.run();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
// 创建线程
thread.start();
}
}
public void mySubmit(Runnable runnable) {
// 添加任务
try {
queue.put(runnable);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
MyPoolThread t = new MyPoolThread(5);
// 重写任务
t.mySubmit(()->{
for (int i = 0; i < 10; i++) {
int id = i;
t.mySubmit(()-> {
Thread t1 = Thread.currentThread();
System.out.println(" 当前线程名为: " + t1.getName() + " id为 "+ id);
});
}
});
}
}
2. 实现原理
在上述的代码中
- 首先,定义一个
阻塞队列
来 管理我们不同的任务 , 因为这里虽然是创建不同的线程,但是这里还是以任务为 基本单位 去执行的。
- 其次进行 构造方法传参过程 ,也是 创建线程的过程 来,并把 每个任务出队列进行运行, 然后
线程抢占执行
。
- 当用户调用 submit() 方法时,我们就可以把每个任务都加入到对应的阻塞队列中按照 先进先出 的特点依次执行。
鱼式疯言
** 细节分析**:
上述 while
的目的是保证刚创建的线程不会结束, 依然可以抢占执行。
如果不使用 while
就会出现以下情况
class MyPoolThread {
// 用一个阻塞队列来存储工作任务
BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(1000);
public MyPoolThread(int nThreads) {
for (int i = 0; i < nThreads; i++) {
// 实例化线程
Thread thread = new Thread(()->{
// 使用while 的方式让 n 个线程都存在
// 并且进行抢占执行
// while(true) {
try {
Runnable t = queue.take();
t.run();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// }
});
// 创建线程
thread.start();
}
}
public void mySubmit(Runnable runnable) {
// 添加任务
try {
queue.put(runnable);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
MyPoolThread t = new MyPoolThread(5);
// 重写任务
t.mySubmit(()->{
for (int i = 0; i < 10; i++) {
int id = i;
t.mySubmit(()-> {
Thread t1 = Thread.currentThread();
System.out.println(" 当前线程名为: " + t1.getName() + " id为 "+ id);
});
}
});
}
}
总结
在本篇文章中,我们一共实践了两个知识点
-
线程池的使用: 我们学习到了两种线程池的使用案例: newFixedThreadPool(线程个数) , 以及
newCachedThreadPool(无参数) 的两种方法的使用,小伙伴一定要多加练习来掌握哦 ❣️ ❣️ ❣️ ❣️ -
2. 线程池的实现: 我们的核心通过阻塞队列的方式循环创建线程并运行runnable 方法来实现我们 newFixedThreadPool() 来实现。
如果觉得小编写的还不错的咱可支持 三连 下 (定有回访哦) , 不妥当的咱请评论区 指正
希望我的文章能给各位宝子们带来哪怕一点点的收获就是 小编创作 的最大 动力 💖 💖 💖
标签:
相关文章
最新发布
- 【Python】selenium安装+Microsoft Edge驱动器下载配置流程
- Python 中自动打开网页并点击[自动化脚本],Selenium
- Anaconda基础使用
- 【Python】成功解决 TypeError: ‘<‘ not supported between instances of ‘str’ and ‘int’
- manim边学边做--三维的点和线
- CPython是最常用的Python解释器之一,也是Python官方实现。它是用C语言编写的,旨在提供一个高效且易于使用的Python解释器。
- Anaconda安装配置Jupyter(2024最新版)
- Python中读取Excel最快的几种方法!
- Python某城市美食商家爬虫数据可视化分析和推荐查询系统毕业设计论文开题报告
- 如何使用 Python 批量检测和转换 JSONL 文件编码为 UTF-8
点击排行
- 版本匹配指南:Numpy版本和Python版本的对应关系
- 版本匹配指南:PyTorch版本、torchvision 版本和Python版本的对应关系
- Python 可视化 web 神器:streamlit、Gradio、dash、nicegui;低代码 Python Web 框架:PyWebIO
- 相关性分析——Pearson相关系数+热力图(附data和Python完整代码)
- Python与PyTorch的版本对应
- Anaconda版本和Python版本对应关系(持续更新...)
- Python pyinstaller打包exe最完整教程
- Could not build wheels for llama-cpp-python, which is required to install pyproject.toml-based proj