千万别从系统中创建线程, 看看从线程池中调用的线程的效率(Java实践篇)
邂逅岁月 2024-09-07 11:35:02 阅读 53
本篇会加入个人的所谓鱼式疯言
❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言
而是理解过并总结出来通俗易懂的大白话,
小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的.
🤭🤭🤭可能说的不是那么严谨.但小编初心是能让更多人能接受我们这个概念 !!!
在当今这个多核处理器成为标配的时代,如何高效地利用计算资源已成为软件开发中不可忽视的关键因素。随着应用程序变得越来越复杂,对并发处理的需求也日益增长。试想一下,在一个繁忙的服务器上,如果每一个新任务都创建一个新的线程来处理,那么系统将不堪重负——频繁的线程创建和销毁不仅消耗大量的时间和内存,还可能导致系统性能急剧下降。
前言
为了解决这一问题,并实现 更高效的资源管理 ,<code>线程池 的概念应运而生。线程池是一种用于 管理和复用一组预先创建好的线程 的方法
它通过 预先创建一定数量的工作线程 并将其 置于池中等待分配任务 ,从而 避免了频繁创建和销毁线程
带来的开销。
而在本篇文章中,小编将延续上篇我们对 线程池的初识
, 以及 线程池的参数理解
在篇文章中来 实际运用并实现我们线程池 的学习。
线程池的使用
线程池的实现
一. 线程池的使用
在我们 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 循环中调用 <code>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>. 运用分析
在上面的代码中
首先我们创建了 线程池, 这里 不需要 传递参数,线程池会根据需求动态的创建一定数量的线程 来进行工作。
循环使用线程池来,在 <code>submit() 中重写
run 方法
来 执行任务 。
最终在调用
shutdown
来 终止线程 。
鱼式疯言
这个线程池中最大的线程个数为
<code>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. 实现原理
在上述的代码中
首先,定义一个 <code>阻塞队列 来 管理我们不同的任务 , 因为这里虽然是创建不同的线程,但是这里还是以任务为 基本单位 去执行的。
其次进行 构造方法传参过程 ,也是 创建线程的过程 来,并把 每个任务出队列进行运行, 然后
线程抢占执行
。
当用户调用 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() 来实现。
如果觉得小编写的还不错的咱可支持 三连 下 (定有回访哦) , 不妥当的咱请评论区 指正
希望我的文章能给各位宝子们带来哪怕一点点的收获就是 小编创作 的最大 动力 💖 💖 💖
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。