首页 > Python资料 博客日记

千万别从系统中创建线程, 看看从线程池中调用的线程的效率(实践篇)

2024-08-14 21:00:04Python资料围观58

文章千万别从系统中创建线程, 看看从线程池中调用的线程的效率(实践篇)分享给大家,欢迎收藏Python资料网,专注分享技术知识

本篇会加入个人的所谓鱼式疯言

❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言

而是理解过并总结出来通俗易懂的大白话,

小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的.

🤭🤭🤭可能说的不是那么严谨.但小编初心是能让更多人能接受我们这个概念 !!!

在当今这个多核处理器成为标配的时代,如何高效地利用计算资源已成为软件开发中不可忽视的关键因素。随着应用程序变得越来越复杂,对并发处理的需求也日益增长。试想一下,在一个繁忙的服务器上,如果每一个新任务都创建一个新的线程来处理,那么系统将不堪重负——频繁的线程创建和销毁不仅消耗大量的时间和内存,还可能导致系统性能急剧下降。

前言

为了解决这一问题,并实现 更高效的资源管理线程池 的概念应运而生。线程池是一种用于 管理和复用一组预先创建好的线程 的方法

它通过 预先创建一定数量的工作线程 并将其 置于池中等待分配任务 ,从而 避免了频繁创建和销毁线程 带来的开销。

而在本篇文章中,小编将延续上篇我们对 线程池的初识, 以及 线程池的参数理解

在篇文章中来 实际运用并实现我们线程池 的学习。

  1. 线程池的使用

  2. 线程池的实现

一. 线程池的使用

在我们 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> . 实际运用分析

在上面的代码中

  1. 首先我们 创建线程池, 并指定核心线程的个数
  1. 在for 循环中调用 submit 来重写 run方法 充分利用创建的这几个线程来完成我们需要的工作
  1. 最终 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>. 运用分析

在上面的代码中

  1. 首先我们创建了 线程池, 这里 不需要 传递参数,线程池会根据需求动态的创建一定数量的线程 来进行工作。
  1. 循环使用线程池来,在 submit() 中重写 run 方法执行任务
  1. 最终在调用 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. 实现原理

在上述的代码中

  1. 首先,定义一个 阻塞队列管理我们不同的任务 , 因为这里虽然是创建不同的线程,但是这里还是以任务为 基本单位 去执行的。
  1. 其次进行 构造方法传参过程 ,也是 创建线程的过程 来,并把 每个任务出队列进行运行, 然后 线程抢占执行
  1. 当用户调用 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() 来实现。

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

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


版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!

标签:

相关文章

本站推荐