JAVA——线程池

news/2024/3/28 22:26:59/文章来源:https://blog.csdn.net/zzbzxzzdf/article/details/130247263

目录

一、线程池的概念

二、Java标准库中的线程池

三、ThreadPoolExecutor 类的参数

四、线程池的拒绝策略

五、模拟实现线程池

一、线程池的概念

线程池顾名思义就是集中存储线程的地方——联想一下水池。

线程池是一种多线程处理形式,处理过程中将任务添加到阻塞队列BlockingQueue)中存储,然后在需要创建启动线程的时候从阻塞队列中 put 出任务并执行。

使用线程池可以有效避免线程过多会带来调度开销,进而影响缓存局部性和整体性能

可用线程数量应该取决于可用的并发处理器,线程数过多会导致额外的线程切换开销

创建线程池的目的就是为了提高线程在创建或销毁时对系统资源的消耗,如果我们从系统中创建线程那么操作系统就要花时间花精力来进行相关操作,其实系统是属于大忙人,操作系统最核心的功能是 硬件管理,驱动管理,进程管理,内存管理、文件管理……此时频繁的创建或者销毁线程对系统的消耗是相对较大的。

线程池就是提前把线程创建好,此时使用线程就可以直接从线程池里拿(这里面涉及到任务的创建,就是规划好每个线程要做什么),线程生命周期结束后再还给线程池。

依据上图描述:线程池最大的好处就是减少每次启动、销毁线程给系统资源带来的损耗,因为系统同时要给这么多的程序提供服务,有的时候服务不一定那么及时。


二、Java标准库中的线程池

Java标准库中给用户提供了现成的线程池

  • 使用 Executors . newFixedThreadPool(10) 能创建出固定包含 10 个线程的线程池。
  • 返回值类型为:ExecutorService
  • 使用 ExecutorService . submit() 方法可以创建一个任务到线程池中——(还未启动 new 状态)

我们创建的线程是需要调用 start() 方法启动),不然线程是不会启动的。

ExecutorService pool = Executors.newFixedThreadPool(10);

pool.submit(new Runnable() {

     @Override

     public void run() { //任务

         System.out.println("创建一个 new 状态的线程");

     }

});     

首先了解一下Executors 创建线程池的几种方式:

  1. newFixedThreadPool: 创建固定的线程数的线程池
  2. newCachedThreadPool: 创建线程数目动态增长的线程池
  3. newSingleThreadExecutor: 创建只包含单个线程的线程池
  4. newScheduledThreadPool: 设定延迟时间后执行命令,或者定期执行任务

解释为什么创建线程池对象需要调用方法来创建:

构造方法的主要作用是给对象赋值;给初始化创建对象的成员变量传输数据。

Executors 类只有一个,如果想创建出不同性质的线程池,就得利用不同的构造方法来传参,这就涉及到构造方法的重载,方法的重载的关键要素就是在于方法名相同,形参列表要不同(形参类型,形参个数),所以有些时候场景下构造方法无法构成重载,就无法区分具体想创建出何种性质的线程池,所以大佬设计出——工厂模式,也是我们最常用的实例化对象模式了,是用工厂方法代替new 操作的一种模式,虽然这样做,可能多做一些工作,但会给类带来更大的可扩展性和尽量少的代码修改量。

这些静态方法的内部还是会使用  new 关键字创建对象 。

上面这些 “工厂方法”  都是基于 ThreadPoolExecutor 类的封装 

Executors 类 本质上也是基于 ThreadPoolExecutor 类的封装

ThreadPoolExecutor 类提供了更多的可选参数,可以进一步细化创建不同性质的线程池。


三、ThreadPoolExecutor 类的参数

ThreadPoolExecutor 使用可用的几个池线程之一执行每个提交的任务,通常使用 Executors 工厂方法配置。面试常问的知识点!!!

形参列表:以下文献出自 JDK 官方文档

TimeUnit是java.util.concurrent包下面的一个类,表示给定单元粒度的时间段。

unit 参数

TimeUnit.DAYS          //天
TimeUnit.HOURS         //小时
TimeUnit.MINUTES       //分钟
TimeUnit.SECONDS       //秒
TimeUnit.MILLISECONDS  //毫秒


四、线程池的拒绝策略

线程池的拒绝策略就是如果线程池中的任务已满,继续往线程池中添加任务,如何进行拒绝。

线程池的执行流程有 3 个重要的判断点:

判断当前工作的线程数是否小于核心线程数

判断当前任务队列是否已满.

判断当前线程数是否已达最大线程数.

如果在经过上述三个过程后, 得到的结果都是 true , 那么就会执行线程池的拒绝策略.

以下文献出自 JDK 官方文档:Java标准库提供了四种拒绝策略


代码演示利用 ThreadPoolExecutor 类创建线程池:

public class Demo1 {public static void main(String[] args) throws InterruptedException {int corePoolSize = 10;// 最大核心线程数int maximumPoolSize = 15; // 核心线程 + 临时线程long keepAliveTime = 5; // 描述临时线程的生命周期// unit TimeUnit.SECONDS 单位秒BlockingQueue workQueue = new LinkedBlockingQueue(10); //自定义阻塞队列// 当线程池满时继续添加任务抛出异常RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();ThreadPoolExecutor pool = new ThreadPoolExecutor( // 创建线程池corePoolSize,maximumPoolSize,keepAliveTime,TimeUnit.SECONDS,workQueue,handler);for (int i = 0; i < 10; i++) { //创建 10 个任务pool.submit(new Runnable() {@Overridepublic void run() { //任务// Thread.currentThread() 返回当前线程的引用// getName() 显示线程名System.out.println(Thread.currentThread().getName() + " 线程执行");}},i); //线程名}}}

 由于多线程是并发执行,线程之间的调度是无序的,所以打印执行的线程也是无序的。

当我们设计创建100 个任务往线程池里放。

由图可见其实也就只创建了 14个线程就抛出了异常(每个人电脑的性能不一样,结果也不一样)。

RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();

这个线程池的拒绝策略可以根据上图四种策略自行设置(在实际开发中根据需求)。

上述代码就是给大家演示如何创建线程池和设置线程池的拒绝策略。


五、模拟实现线程池

public class MyThreadPool {

    //阻塞队列用来存放任务

    private BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(10);

    public void submit(Runnable runnable) throws InterruptedException {

        queue.put(runnable); // 任务进入”线程池“

    }

    // 此处实现一个固定的线程数的线程池

    public MyThreadPool(int n) {

        for (int i = 0; i < n; i++) {

            Thread t = new Thread(() -> {

                // 循环取任务

                while (true) {

                    try {

                        //弹出一个任务执行

                        Runnable runnable = queue.take();

                        runnable.run();// 调用run() 方法执行

                    } catch (InterruptedException e) {

                        e.printStackTrace();

                    }

                }

            });

            t.start();

        }

    }

}

class  TheadDemo {

    public static void main(String[] args) throws InterruptedException {

        MyThreadPool pool = new MyThreadPool(10);

        for (int i = 0; i < 10; i++) {

            int number = i; //变量捕获,事实final

            // 10个线程并发无序调度

            pool.submit(new Runnable() {

                @Override

                public void run() {

                    System.out.println("hello" + number);

                }

            });

        }

    }

}


只要用心

每个人都是优秀的

努力付出

平凡的你

也可以创造奇迹

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_102555.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ext4日志优化-iJournaling

背景 这几年随着SSD等高性能介质的普及&#xff0c;及其在大规模分布式存储系统上的应用。基于Append only的日志写入技术也应用得越来越多&#xff0c;这几天刚好有空&#xff0c;重读了Ext4文件系统的日志部分的内容&#xff0c;也正好看到一篇对Ext4日志技术进行优化的论文…

《编码——隐藏在计算机软硬件背后的语言》精炼——第11章(门)

“The only source of knowledge is experience.” - Albert Einstein 引言 编码是一种处理并表达信息的方式&#xff0c;它包括摩斯电码、盲文、二进制语言等等&#xff0c;当然作为计算机类的经典书籍&#xff0c;这本书简述了计算机中以二进制数为基础的编码方式&#xff0…

nginx简单介绍

文章目录 1. 下载并解压2. 80端口被占用&#xff0c;更改nginx默认的监听端口3. 访问nginx4. 在linux上安装nginx5. nginx常用命令6. nginx.conf 1. 下载并解压 官网下载 2. 80端口被占用&#xff0c;更改nginx默认的监听端口 更改conf/nginx.conf文件 3. 访问nginx ht…

【Linux】popen pclose接口介绍

本篇文章简单讲述了c语言接口popen/pclose的用法 1.函数作用 函数定义如下 #include <stdio.h>FILE *popen(const char *command, const char *type); int pclose(FILE *stream);1.1 popen popen函数会创建一个管道&#xff0c;fork后调用shell来打开进程。由于管道的…

射频封装技术:层压基板和无源器件集成

射频和无线产品领域可以使用非常广泛的封装载体技术&#xff0c;它们包括引线框架、层压基板、低温共烧陶瓷&#xff08;LTCC&#xff09;和硅底板载体&#xff08;Si Backplane&#xff09;。由于不断增加的功能对集成度有了更高要求&#xff0c;市场对系统级封装方法&#xf…

Qt 项目Mingw编译器转换为VS编译器时的错误及解决办法

错误 在mingw生成的项目&#xff0c;转换为VS编译器时通常会报些以下错误&#xff08;C4819警告&#xff0c;C2001错误&#xff0c;C2143错误&#xff09; 原因及解决方式 这一般是由于字符编码引起的&#xff0c;在源代码文件中包含了中文字符导致的。Qt Creator 生成的代码文…

iptables防火墙和Firewalld

引言 在 Internet 中&#xff0c;企业通过各种应用系统来为用户提供各种服务&#xff0c;如 Web 网站、电子邮件系统、FTP 服务器、数据库系统等&#xff0c;那么&#xff0c;如何来保护这些服务器&#xff0c;过滤企业不需要的访问甚至是恶意的入侵呢&#xff0c;接下来&#…

【Linux】生产者消费者模型——环形队列RingQueue(信号量)

文章目录 铺垫信号量信号量概念信号量PV操作信号量基本接口 环形队列的生产消费模型引入环形队列访问环形队列代码实现代码改造多生产者多消费者代码 总结 铺垫 之前写的代码是存在不足的地方的&#xff1a; 我们使用线程操作临界资源的时候要先去判断临界资源是否满足条件&am…

最新动态 | 大势智慧参加广东省应急测绘保障与安全生产演练

4月20日&#xff0c;2023年度广东省应急测绘保障与安全生产演练在台山市赤溪镇鱼塘湾举行。本次演练由广东自然资源厅主办&#xff0c;广东省国土资源测绘院、江门市自然资源局和台山市人民政府承办。在省市各指导单位与参演单位的多方协同与指挥下&#xff0c;应急测绘保障与安…

【三十天精通Vue 3】第十四天 Vue 3 的单元测试详解

✅创作者&#xff1a;陈书予 &#x1f389;个人主页&#xff1a;陈书予的个人主页 &#x1f341;陈书予的个人社区&#xff0c;欢迎你的加入: 陈书予的社区 &#x1f31f;专栏地址: 三十天精通 Vue 3 文章目录 引言一、为什么要进行单元测试1.1 单元测试的概念1.2 单元测试的优…

ctfshow_WEB_web2 wp

前言 写这个是因为。。。我想摆烂&#xff0c;就去从最简单的题开始做了&#xff0c;想着交一道题是一道嘛&#xff0c;总之觉得这样做很适合欺骗安慰自己&#xff08;逃 然后我发现我错了&#xff0c;我第二道题就做了好久还没做出来&#xff0c;甚至最后去点开了hint…… ps…

Java网络编程系列之NIO

Java网络编程系列之NIO 1.Java NIO概述1.1 阻塞IO1.2 非阻塞IO1.3 NIO概述1.3.1 Channels1.3.2 Buffer1.3.3 Selector 2.Java NIO(Channel)2.1Channel概述2.2 Channel实现2.3 FileChannel 介绍与示例2.4 FileChannel 操作详解2.4.1 打开FileChannel2.4.2 从FileChannel读取数据…

自定义测试平台搭建

体验地址&#xff1a;TestManagePlatform 首次加载会比较慢... 功能点 1.数据工具生成&#xff0c;增删改查 2.测试用例以及测试套件生成&#xff0c;测试执行测试基础用例增删改查。 3.Jacoco 代码增量扫描 4.文章管理 欢迎私聊&#xff0c;支撑自定义开发。

Java基础(十)字符串相关类

1 字符串相关类之不可变字符序列&#xff1a;String 1.1 String的特性 java.lang.String 类代表字符串。Java程序中所有的字符串文字&#xff08;例如"hello" &#xff09;都可以看作是实现此类的实例。 字符串是常量&#xff0c;用双引号引起来表示。它们的值在创…

对数据结构的初步认识

前言: 牛牛开始更新数据结构的知识了.本专栏后续会分享用c语言实现顺序表,链表,二叉树,栈和队列,排序算法等相关知识,欢迎友友们互相学习,可以私信互相讨论哦! &#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;推荐专栏: &#x1f354;&#x1f35f;&a…

Allegro PCB后处理

Allegro PCB后处理&#xff0c;主要是完成线路设计以后&#xff0c;输出生产文件之前的处理。这是看教程做的记录&#xff0c;方便以后自己参考。 教程&#xff1a; [小哥Cadence Allegro 132讲字幕版PCB视频教程]_哔哩哔哩_bilibili 感觉关键是多看右边Options菜单&#xff0…

Simulation Extractable Versions of Groth’s zk-SNARK Revisited学习笔记

1. 引言 等人2020年论文《Simulation Extractable Versions of Groth’s zk-SNARK Revisited》&#xff0c;开源代码实现见&#xff1a; https://github.com/Baghery/ABPR22&#xff08;Rust&#xff0c;基于arkworks开发。使用了Multi-Scalar Multiplication (MSM)技术来优化…

linux下使用ftp下载服务器数据

首先确认服务器地址 比如我要从uniprot获取数据&#xff0c;需要先ping服务器地址&#xff1a; 可见&#xff0c;ftp地址不需要前面的https 匿名登录 匿名&#xff1a;anonymous 密码&#xff1a;任意邮箱&#xff0c;如123163.com 这里的传输模式我使用的是二进制&#xff…

Revit进入Unity教程

一、背景 小伙伴们是否有Revit进入Unity交互的需求呢&#xff1f; 二、实现功能 1.Revit进入Unity,包含模型属性&#xff0c;材质&#xff0c;轻量化等 2.实现BIM构件点选&#xff0c;高亮&#xff0c;属性展示 3.实现BIM模型分层显示&#xff0c;爆炸等效果 学习教程&…

xilinx zynq+vitis实现命令行编译输出xsa以及bin文件

执行菜单命令【开始】—【所有程序】—【Xilinx Design Tools】—【Vivado2020.1】—【Vivado2020.1Tcl Shell】,弹出命令界面 或者cmd命令下输入call D:\soft_install\vivado2020.1\Vivado\2020.1\bin\vivado.bat -mode tcl 2.输入打开工程指令&#xff1a; open_project …