千万别从系统中创建线程, 看看从线程池中调用的线程的效率(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() 来实现。

如果觉得小编写的还不错的咱可支持 三连 下 (定有回访哦) , 不妥当的咱请评论区 指正

希望我的文章能给各位宝子们带来哪怕一点点的收获就是 小编创作 的最大 动力 💖 💖 💖

在这里插入图片描述



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。