线程池 (通俗易懂)

2023-11-01

一、线程池是什么

之前我们已经认识过"池":String,字符串常量池;MySQL JDBC,数据库连接池(DataSource)…

线程诞生的原因是进程太重量了,导致创建进程/销毁进程比较低效 (内存资源的申请和释放)!而线程就是共享了内存资源,新的线程复用之前的资源,不必重新申请了 (快了)~~
但是如果线程创建的频率高了,此时线程创建销毁的开销仍然不能忽略!
此时就可以使用线程池来进一步优化这里的速度了!!!

在这里插入图片描述
在这里插入图片描述

用户态:每个进程都是自己执行自己的逻辑;
内核态:一个系统里只有这一份内核在执行逻辑,这个内核要给所有的进程都提供一些服务!
在这里插入图片描述
最终的结论:使用线程池是纯用户态操作,要比创建线程 (经历内核态的操作)要快~~
线程池最大的好处就是减少每次启动、销毁线程的损耗!

总结三点:

  • 降低资源消耗:减少线程的创建和销毁带来的性能开销。
  • 提高响应速度:当任务来时可以直接使用,不用等待线程创建。
  • 可管理性:进行统一的分配、监控,避免大量的线程间因互相抢占系统资源导致的阻塞现象。

二、标准库中的线程池

  • 使用 Executors.newFixedThreadPool(10) 能创建出固定包含 10 个线程的线程池
  • 返回值类型为 ExecutorService
  • 通过 ExecutorService.submit 可以注册一个任务到线程池中
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Demo {
    public static void main(String[] args) {
        ExecutorService pool = Executors.newCachedThreadPool();
        pool.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("这是任务");
            }
        });
    }
}

Executors 创建线程池的几种方式

  • newFixedThreadPool:创建固定线程数的线程池
  • newCachedThreadPool:创建线程数目动态增长的线程池
  • newSingleThreadExecutor:创建只包含单个线程的线程池
  • newScheduledThreadPool:设定延迟时间后执行命令,或者定期执行命令,是进阶版的Timer

Executors 本质上是 ThreadPoolExecutor 类的封装。
ThreadPoolExecutor 提供了更多的可选参数,可以进一步细化线程池行为的设定。

三、线程池的执行流程

1)当新加入一个任务时,先判断当前线程数是否大于核心线程数,如果结果为 false,则新建线程并执行任务;
2)如果结果为 true,则判断任务队列是否已满,如果结果为 false,则把任务添加到任务队列中等待线程执行;
3)如果结果为 true,则判断当前线程数量是否超过最大线程数?如果结果为 false,则新建线程执行此任务;
4)如果结果为 true,执行拒绝策略。
在这里插入图片描述

四、实现线程池

3.1 思路与细节

一个线程池可以同时提交N个任务,对应的线程池中有M个线程来负责完成这N个任务,如何把N个任务分配给M个线程呢?

生产者消费者模型正好可以解决这个问题!
先搞一个阻塞队列,每个被提交的任务都被放到阻塞队列中。搞M个线程来取队列元素。如果队列空了,M个线程自然阻塞等待;如果队列不为空,每个线程都取任务、执行任务,完了再来取下一个…直到队列为空,线程继续阻塞~~

在这里插入图片描述
注意:
1)阻塞队列能够保证线程安全~
2)Thread的线程跑起来之后,在执行过程中,是不会被提前销毁的!run() 执行完了才会被销毁~
3)线程什么时候结束呢?不用结束!因为无法判定啥时候会有新的线程过来!
一般还是在服务器开发中会更常用到线程池,这时线程池肯定是要持续工作的了~
如果非要结束,单独写一个shutdown方法,强制interrupt所有的工作线程 (如果你要写shutdown,后面是需要操作这些线程实例的,所以需要用数组保存起来)

3.2 完整代码

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

class MyThreadPool {
    private BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();

    public void submit(Runnable runnable) throws InterruptedException {
        queue.put(runnable);
    }

    public MyThreadPool(int m) {
        // 在构造方法中, 创建出 M 个线程. 负责完成工作.
        for (int i = 0; i < m; i++) {
            Thread t = new Thread(() -> {
                while (true) {
                    try {
                        Runnable runnable = queue.take();
                        runnable.run();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            t.start();
        }
    }
}

public class Demo {
    public static void main(String[] args) throws InterruptedException {
        MyThreadPool pool = new MyThreadPool(10);
        for (int i = 0; i < 1000; i++) {
            int taskId = i;  // i是一直在变化的,所以我们创建一个新的变量在Runnable进行捕获!
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println("执行当前任务: " + taskId + " 当前线程: " + Thread.currentThread().getName());
                }
            });
        }
    }
}

五、标准库里的构造方法

标准库里提供的 ThreadPoolExecutor 其实要更复杂一些,尤其是构造方法,可以支持很多参数,可以支持很多选项,让我们来创建出不同风格的线程池~~

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
标准库里带的拒绝策略:重点
(领导:鹏哥;员工:汤老湿)
在这里插入图片描述
1)AbortPolicy:中止策略,线程池会抛出异常并中止执行此任务;
2)CallerRunsPolicy:把任务交给添加此任务的线程来执行;
3)DiscardPolicy:忽略此任务(最新加入的任务);
4)DiscardOldestPolicy:忽略最先加入队列的任务(最老的任务)。


例题: 使用ThreadPoolExecutor创建一个忽略最新任务的线程池,创建规则:
1.核心线程数为5
2.最大线程数为10
3.任务队列为100
4.拒绝策略为忽略最新任务

代码实现:

public class Thread_Demo {
    public static void main(String[] args) throws InterruptedException {
        // 依题意创建线程池
        ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(5, // 核心线程数
                10, // 最大线程数
                3, // 线程空闲时长
                TimeUnit.SECONDS, // 线程空闲时长的时间单位
                new LinkedBlockingQueue<>(100), // 任务队列
                new ThreadPoolExecutor.DiscardPolicy()); // 拒绝策略为忽略最新任务
 
        // 测试执行
        for (int i = 0; i < 2000; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "已执行.");
            },"thread-" + (i + 1)).start();
        }
    }
}

六、延伸问题

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

线程池 (通俗易懂) 的相关文章

  • 如何使用 Apache POI API 将图像添加到 pptx 中添加的图像占位符?

    我已经预定义了带有文本和图像占位符的 pptx 模板 我如何从模板访问和修改这些占位符 我可以使用 POI pptx API 直接将图像和文本添加到幻灯片中 但如何将其添加到模板的占位符中 请参阅链接以了解如何添加占位符来创建固定模板 ht
  • Hibernate注解放置问题

    我有一个我认为很简单的问题 我见过两种方式的例子 问题是 为什么我不能将注释放在字段上 让我举一个例子 Entity Table name widget public class Widget private Integer id Id G
  • 如何在android上的python kivy中关闭应用程序后使服务继续工作

    我希望我的服务在关闭应用程序后继续工作 但我做不到 我听说我应该使用startForeground 但如何在Python中做到这一点呢 应用程序代码 from kivy app import App from kivy uix floatl
  • JavaFX 中具有自定义内容的 ListView

    How i can make custom ListView with JavaFx for my app I need HBox with image and 2 Labels for each line listView 您可以通过查看
  • 使用 AES SecretKey 的 Java KeyStore setEntry()

    我目前正在 Java 中开发一个密钥处理类 特别是使用 KeyStore 我正在尝试使用 AES 实例生成 SecretKey 然后使用 setEntry 方法将其放入 KeyStore 中 我已经包含了代码的相关部分 The KS Obj
  • 画透明圆,外面填充

    我有一个地图视图 我想在其上画一个圆圈以聚焦于给定区域 但我希望圆圈倒转 也就是说 圆的内部不是被填充 而是透明的 其他所有部分都被填充 请参阅这张图片了解我的意思 http i imgur com zxIMZ png 上半部分显示了我可以
  • 在 Netbeans 8 上配置 JBoss EAP 的问题

    我已经下载了 JBoss EAP 7 并正在 Netbeans 8 上配置它 我已经到达向导 实例属性 其中要求从选择框中选择 域 当我打开选择框时 它是空的 没有什么可以选择的 因此 完成 按钮也处于非活动状态 这使得无法完成配置 我通过
  • Calendar.getInstance(TimeZone.getTimeZone("UTC")) 不返回 UTC 时间

    我对得到的结果真的很困惑Calendar getInstance TimeZone getTimeZone UTC 方法调用 它返回 IST 时间 这是我使用的代码 Calendar cal Two Calendar getInstance
  • 具有 java XSLT 扩展的数组

    我正在尝试使用 java 在 XSLT 扩展中使用数组 我收到以下错误 Caused by java lang ClassCastException org apache xpath objects XObject cannot be ca
  • 在游戏视图下添加 admob

    我一直试图将 admob 放在我的游戏视图下 这是我的代码 public class HoodStarGame extends AndroidApplication Override public void onCreate Bundle
  • react-native run-android 失败并出现错误:任务 ':app:dexDebug' 执行失败

    我使用的是 Windows 8 1 和react native cli 1 0 0 and react native 0 31 0 添加后react native maps对于该项目 我运行了命令react native upgrade并给
  • 编辑文件名在 JComboBox 中的显示方式,同时保持对文件的访问

    我对 Java 很陌生 对堆栈溢出也很陌生 我正在尝试利用 JMF API 创建一个用 Java 编码的简单媒体播放器 到目前为止 我已经能够设置一个简单的队列 播放列表来使用JComboBox called playListHolder
  • IntelliJ - 调试模式 - 在程序内存中搜索文本

    我正在与无证的第三方库合作 我知道有一定的String存储在库深处的某个字段中的某处 我可以预测的动态值 但我想从库的 API 中获取它 有没有一种方法可以通过以下方式进行搜索 类似于全文搜索 full程序内存处于调试模式并在某个断点处停止
  • 如何知道抛出了哪个异常

    我正在对我们的代码库进行审查 有很多这样的陈述 try doSomething catch Exception e 但我想要一种方法来知道 doSomething 抛出了哪个异常 在 doSomething 的实现中没有 throw 语句
  • 在 Spring 中重构这个的最佳方法?

    private final ExecutorService executorParsers Executors newFixedThreadPool 10 public void parse List
  • 我可以创建自定义 java.* 包吗?

    我可以创建一个与预定义包同名的自己的包吗在Java中 比如java lang 如果是这样 结果会怎样 这难道不能让我访问该包的受保护的成员 如果不是 是什么阻止我这样做 No java lang被禁止 安全管理器不允许 自定义 类java
  • 游戏内的java.awt.Robot?

    我正在尝试使用下面的代码来模拟击键 当我打开记事本时 它工作正常 但当我打开我想使用它的游戏时 它没有执行任何操作 所以按键似乎不起作用 我尝试模拟鼠标移动和点击 这些动作确实有效 有谁知道如何解决这个问题 我发现这个问题 如何在游戏中使用
  • FileOutputStream.close() 中的设备 ioctl 不合适

    我有一些代码可以使用以下命令将一些首选项保存到文件中FileOutputStream 这是我已经写了一千遍的标准代码 FileOutputStream out new FileOutputStream file try BufferedOu
  • ServletContainer 类未找到异常

    我无法再编译我的球衣项目 并且出现以下异常 GRAVE Servlet Project API threw load exception java lang ClassNotFoundException com sun jersey spi
  • 如何从 Maven 存储库引用本机 DLL?

    如果 JAR 附带 Maven 存储库中的本机 DLL 我需要在 pom xml 中放入什么才能将该 DLL 放入打包中 更具体地举个例子Jacob http search maven org artifactdetails 7Cnet s

随机推荐

  • Java后端特殊格式字符处理

    在接收前端传过来的数据时 发现了带格式的特殊字符 例如 这样的加粗黑体带格式的字符 这样的字符导致了后端接口出现了问题 于是决定对改字段进行格式化处理 使用Normalizer这个类进行格式化 Normalizer isNormalized
  • android studio 代理设置及注意事项

    现有环境 windows 10 64位 android studio arctic fox 2020 3 1 Patch 3 遇到的问题 无论如何修改androidstudio代理不起作用 最后发现是gradle properties文件没
  • KVM/QEMU简介

    KVM QEMU简介 KVM虚拟机是基于linux内核虚拟化 自linux2 6 20之后就集成在linux的各个主要发行版本中 它使用linux自身的调度器进行管理 所以相对于xen 其核心源码很少 KVM的虚拟化需要硬件的支持 如int
  • Delphi Edit右键系统菜单加自定义菜单项

    闲言少叙 详见代码 unit Unit1 interface uses Windows Messages SysUtils Variants Classes Graphics Controls Forms Dialogs StdCtrls
  • 基础算法题——牛牛和牛可乐的赌约2(题意混淆)

    牛牛和牛可乐的赌约2 题目链接 牛牛感觉在上一次赌约中 情况对于自己非常不利 所以决定再赌一场 这时候 牛蜓队长出现了 第一 绝对不意气用事 第二 绝对不漏判任何一件坏事 第三 绝对裁判的公正漂亮 牛蜓队长带他们来到了一个棋盘游戏 棋盘左上
  • React虚拟DOM浅析

    在Web开发中 需要将数据的变化实时反映到UI上 这时就需要对DOM进行操作 但是复杂或频繁的DOM操作通常是性能瓶颈产生的原因 为此 React引入了虚拟DOM Virtual DOM 的机制 一 什么是虚拟DOM 在React中 ren
  • 电脑反应速度慢怎么办_笔记本电脑运行慢

    笔记本电脑运行慢怎么办呢 在使用一段时间之后 电脑产品就会出现运行卡顿反应慢等现象 我们可以通过一些方法恢复电脑的运行效率 延长电脑的使用寿命 下面就为大家介绍几个方法 希望一下的介绍能够帮助到您 笔记本电脑运行慢 1 添加一个SSD 相比
  • Java开发工具 IntelliJ IDEA(idea使用教程,手把手教学)内容很全,一篇管够!!!

    IDEA使用教程 下载安装 IntelliJ IDEA 介绍 IDEA 全称 IntelliJ IDEA 是 Java 语言的集成开发环境 IDEA 在业界被公认为是最好的 java 开发工具之一 尤其在智能代码助手 代码自动提示 重构 J
  • WSL2(win10子系统)Linux图形化GUI教程win-kex

    WSL2 win10子系统 Linux图形化GUI教程win kex 备注 一 开始前的准备 1 更新Windows版本 2 开启Windows功能 二 Linux子系统的安装 1 下载WSL 2 WSL版本转换 3 配置软件源 三 配置优
  • Bugku:社工-进阶收集

    Bugku过年上了几道新的社工题 有空了来试着写看看 先打开附件可以发现存在一张空间截图 盲猜应该是西安的 烂怂 大雁塔吧 从评论中主角和朋友的对话 我们大概可以获得以下信息 主角家距离大雁塔一共有七站地铁 其中要进行中转 同时作者是从始发
  • 在C#中使用OpenCV(使用OpenCVSharp)

    1 什么是OpenCVSharp 为了解决在Csharp下编写OpenCV程序的问题 我做过比较深入的研究 并且实现了高效可用的方法 GOCW 这几天在搜集资料的时候 偶尔看见了OpenCVSharp 从时间上来看 它已经经过了更久的发展
  • Unity中几种简单的相机跟随

    unity中相机追随 固定相机跟随 这种相机有一个参考对象 它会保持与该参考对象固定的位置 跟随改参考对象发生移动 using UnityEngine using System Collections public class Camera
  • Memcached 清除缓存命令

    首先打开cmd窗口 输入一下命令清除memcached缓存 1 连接 telnet 127 0 0 1 11211 2 查看状态 stats 3 清除缓存 flush all 显示ok以后 缓存就清理成功啦
  • 罗技驱动检测不到设备?解决方法

    罗技旗下的鼠标是很多用户都在使用的设备 需要用户安装驱动程序才能够运行 而近期有些小伙伴遇到了罗技驱动检测不到设备的情况 这该如何处理 纯净之家 win7纯净版系统 win7 ghost 纯净版 方法一 1 检测不到设备也有可能不是驱动的问
  • Linux的正则表达式

    目录 正则简介 正则三剑客一 grep 正则三剑客二 sed 正则三剑客三 awk 1 正则简介 什么是正则表达式 简单的说 正则表达式就是为处理大量的字符串而定义的一套规则和方法 通过定义的这些特殊符号的辅助 系统管理员就可以快速过滤 替
  • Linux命令 chmod -R 755

    linux 命令chmod 755的意思 chmod是Linux下设置文件权限的命令 后面的数字表示不同用户或用户组的权限 一般是三个数字 第一个数字表示文件所有者的权限 第二个数字表示与文件所有者同属一个用户组的其他用户的权限 第三个数字
  • 【django】Forbidden (CSRF cookie not set.)

    CSRF 表示django全局发送post请求均需要字符串验证 功能 防止跨站请求伪造的功能 工作原理 客户端访问服务器端 在服务器端正常返回给客户端数据的时候 而外返回给客户端一段字符串 等到客户端下次访问服务器端时 服务器端会到客户端查
  • 面试——Unity Animation和Animator的区别

    两者都是控制动画播放的 Animation控制一个动画播放的各类方法和数据 当然你可以通过修改目标动画进行动画切换 Animator则可以实现控制多个动画的播放 切换 叠加等一级对骨骼动画控制等更复杂的效果 是一个动画状态机 除却必要的动画
  • nmon命令

    启动nmon监控命令 日志保存到 log 路径下 nmon16g x86 sles12 s0 5 c14400 f m log 对nmon文件赋权 chmod 777 file name s 采集时间 c 采集次数 f 文件类型 不填写为标
  • 线程池 (通俗易懂)

    线程池 一 线程池是什么 二 标准库中的线程池 三 线程池的执行流程 四 实现线程池 3 1 思路与细节 3 2 完整代码 五 标准库里的构造方法 六 延伸问题 一 线程池是什么 之前我们已经认识过 池 String 字符串常量池 MySQ