(JAVA)-(多线程)-线程池

news2024/11/26 19:48:12

线程池,顾名思义就是存放线程的池子,当有任务时能够随时取用线程,任务结束后能够放回线程池中。如果把线程比成碗,线程池就像一个碗柜一样。

使用线程池的好处:

1.当有大量线程对象时,减少了线程创建销毁造成的损耗。

2.提高响应速度

3.提高线程的可管理性

线程池的核心逻辑:

1.创建一个池子,池子是空的

2.提交任务的时候池子会创建新的线程对象,任务执行完毕,线程归还给池字,下次再提交任务时,不需要创建新的线程,直接复用已有的线程即可

3.提交任务时,池子中没有空闲的线程,也无法创建新的线程,任务就会排队

代码实现:

1.创建线程池

2.提交任务

3.所有的任务全部执行完毕,关闭线程

一:使用Executors工具类创建线程池对象

Executors是线程池的一个工具类,能调用他的静态方法创建线程池对象

public static ExecutorService newCachedThreadPool();
//创建一个没有上限的线程池
public static ExecutorService newFixedThreadPool(int nThreads);
//创建一个有上限的线程池

1.newCachedThreadPool() 方法:

能创建一个没有上限的线程池,如果现有任务没有线程进行处理,就会创建一个新线程并添加到缓存池中。如果有被使用完但是还没销毁的线程,就复用该线程。如果有线程60s未被使用的话就会从缓存中移出并终止(销毁)。因此,长时间保持空闲的线程池不会使用任何资源。

 ExecutorService pool1 = Executors.newcachedThreadPool();

提交任务:submit方法

可以看到submit方法参数可以传递runnable和Callable的实现类任务

public class test {
    public static void main(String[] args) {
        ExecutorService pool1 = Executors.newCachedThreadPool();
        pool1.submit(new MyRunnable());
        pool1.submit(new MyRunnable());
        pool1.submit(new MyRunnable());
//提交三个任务
        pool1.shutdown();
    }
}

 class MyRunnable implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+"---"+i);
        }
    }
}

我们可以看到线程池创建了三个线程。

2.newFixedThreadPool(int num)方法

这个方法能创建一个固定线程数的线程池,超出线程任务数量的线程会在队列中等待,方法参数为线程池中的线程数

public class test {
    public static void main(String[] args) {
        ExecutorService pool1 = newFixedThreadPool(1);
        pool1.submit(new MyRunnable());
        pool1.submit(new MyRunnable());
        pool1.submit(new MyRunnable());
//提交三个任务
        pool1.shutdown();
    }
}

 class MyRunnable implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+"---"+i);
        }
    }
}

我们可以看到结果中只有线程1在执行任务。

二:自定义线程池

我们首先对Executors工具类进行跟进

我们发现创建这个线程池的方法在底层调用了一个 ThreadPoolExecutor类去创建了对象,并且传递了一些参数进去,ThreadPoolExecutor其实就是线程池的类。

我们先讲解线程池的运行流程

线程池中分为核心线程和临时线程。临时线程倘若经过了一定时间没有处理,就会进行销毁

当任务进行提交时,线程池便会创建线程。

倘若提交的任务数超过了核心线程数,就会在阻塞队列中进行等待,直到核心线程正在进行的任务完成后再执行。倘若提交的任务数超出了阻塞队列的长度,就会进入临时队列中进行执行,若提交的任务在超出了临时队列的范围,就会是使用任务拒绝策略拒绝任务。

通过以上,我们了解了线程池的运行流程。接着我们来看看线程池的参数

跟进发现,线程池这个类最长的构造方法有七个参数,我们逐个讲解

1.corePoolSize:这个参数就是线程池的核心线程数。

2.maximumPoolSize:这个参数是线程池的最大线程数,他肯定是大于核心线程数,从源码中也可以看到,如果这样做在运行时会抛出异常:IllegalArgumentException。

3.keepAliveTime:这个参数是空闲线程的等待时间,当超过这个时间临时线程还没有执行任务,临时线程就会销毁。

4.unit:这个是线程池的空闲时间的单位,需要调用TimeUnit中的枚举常量

  • 它在TimeUnit类中有7种静态属性可取。
    • 天:TimeUnit.DAYS;
    • 小时:TimeUnit.HOURS;
    • 分钟:TimeUnit.MINUTES;
    • 秒:TimeUnit.SECONDS;
    • 毫秒:TimeUnit.MILLISECONDS;
    • 微妙:TimeUnit.MICROSECONDS;
    • 纳秒:TimeUnit.NANOSECONDS;

5.workQueue:这个参数是线程在等待的阻塞队列,需要传递一个阻塞队列进去。

6.theadFactor:这个参数意思是线程工厂,用于创建新的线程。我们可以传递Executros工具类中的deafaultThread方法进行创建线程工厂,他在底层也是创建了一个线程。

7.rejectedExecutionHandler:这个是一个接口,代表任务的拒绝策略,在ThreadPoolExecutor中以内部类的方式内部类方式存在,他们都实现了rejectedExecutionHandler接口。

  • AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。线程池默认的拒绝策略。如何使用new ThreadPoolExecutor.AbortPolicy()
  • DiscardPolicy:也是丢弃任务,但是不抛出异常。
  • DiscardOldestPolicy:丢弃队列最前面的任务,也就是队列头的元素,然后重新尝试执行任务(重复此过程)。如果此时阻塞队列使用PriorityBlockingQueue优先级队列,将会导致优先级最高的任务被抛弃。
  • CallerRunsPolicy:既不抛弃任务也不抛出异常,而是由调用线程的主线程来处理该任务。换言之就是由调用线程池的主线程自己来执行任务(例如:是有main线程启动的线程池,当触发次策略时,多余的任务就会交由main线程来执行),因此在执行任务的这段时间里主线程无法再提交新任务,从而使线程池中工作线程有时间将正在处理的任务处理完成,所以对性能和效率必然是极大的损耗。

那么线程池多大合适呢?

要理解上面的公式,我们得先了解最大并行数是什么

四核八线程:代表着电脑有四个大脑 ,能同时干四件事情,而超线程技术,把一个物理核心模拟成两个逻辑核心,理论上要像八颗物理核心一样在同一时间执行八个线程,所以电脑最大并行数为8.

我们可以用RunTime工具类中的availiableProcessors()静态方法去获取java能够使用的最大线程数。

项目运算比较多,读取本地文件或者数据库比较少,就属于cpu密集型运算,反之则属于IO密集型运算

第一个公式很容易能看懂,那么第二个公式是什么意思呢?

举个例子:从本地文件中读取两个数据,相加。假设java能使用的最大并行数为8,读取数据用了1秒,cpu计算相加用了1秒

从本地文件中读取数据并不是cpu干的事,cpu计算相加用了一秒,因此最合适的线程池大小就是

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

浅谈直流电表在韩国充电桩生产厂家的应用

I.背景&#xff1a; 近几年为应对温室气体的排放导致的全球变暖、气候变化等问题,各大国纷纷对焦推进电动汽车&#xff0c;从而减少传统燃油汽车带来的大量温室气体排放。而推进新能源汽车的各项举措之中&#xff0c;充电桩的基础建设&#xff0c;又是其中的重中之重&#xff…

【MySQL】数据库并发控制:悲观锁与乐观锁的深入解析

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a; 数 据 库 ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 悲观锁&#xff08;Pessimistic Locking&#xff09;: 乐观锁&#xff08;Optimistic Locking&#xff09;: 总结&#x…

2023年,我46岁,进入关机模式,稳了

关键词&#xff1a;持续关机、稳住基本盘、力量训练、新开端。 持续关机 对于性格内向的我&#xff0c;过上安静的生活才是美好岁月的真正开端。我尽量减少不必要的活动&#xff0c;能不出门就不出门。 在10月份&#xff0c;我停止了日更栏目“大志聊赚钱”&#xff0c;该栏目…

紧固件行业的市场规模和增长率是怎样的,主要市场区域有哪些?

分析标准件行业市场容量和增长率 标准件指的是在各种工业设备中广泛使用的连接件&#xff0c;通常由螺栓、螺帽、垫圈等组成。它能够将两个或两个以上的零件牢固地固定在一起&#xff0c;起到传递力量或者关闭效果的作用。标准件是机械制造、汽车、航空、电子、建筑等行业中不…

InterSystems 数据库的存储过程存在哪里

我们都知道 InterSystems 的 Studio 可以创建存储过程。 但这个存储过程我们保存的时候是保存在哪里&#xff1f; 存储逻辑 如果我们在 Studio 创建存储过程的话&#xff0c;存储过程是存储在数据库上面的。 本地文件夹中是没有存储的。 选择系统下面的存储过程&#xff0c…

PostgreSQL10数据库源码安装及plpython2u、uuid-ossp插件安装

PostgreSQL10数据库源码安装及plpython2u、uuid-ossp插件安装 1、环境2、安装包下载3、安装3.1 、解压3.2、配置3.3、编译安装3.4 、启动与关闭 4、安装 uuid-ossp 、plpython2u插件5、参考 1、环境 centos 7 、 postgresql 10.19 2、安装包下载 postgres 源码安装包 3、安…

Flowable-升级为7.0.0.M2-第三节

目录 启动项目添加虚拟机参数启动成功 启动项目 添加虚拟机参数 java.base/java.langALL-UNNAMED --add-opens java.base/java.mathALL-UNNAMED --add-opens java.base/java.util.concurrentALL-UNNAMED --add-opens java.base/java.netALL-UNNAMED --add-opens java.base/ja…

Docker本地部署开源浏览器Firefox并远程访问进行测试

文章目录 1. 部署Firefox2. 本地访问Firefox3. Linux安装Cpolar4. 配置Firefox公网地址5. 远程访问Firefox6. 固定Firefox公网地址7. 固定地址访问Firefox Firefox是一款免费开源的网页浏览器&#xff0c;由Mozilla基金会开发和维护。它是第一个成功挑战微软Internet Explorer浏…

matplotlib范围曲线简例

想在画&#xff08;平均&#xff09;loss 曲线时顺便表示方差&#xff0c;即每一个 epoch 的平均 loss 用 plot 画曲线&#xff0c;而在曲线周围用一个浅色区域表示方差。效果&#xff1a; 参考 [1-3]&#xff0c;用到 matplotlib.pyplot.fill_between 函数。为显示对浅色区及…

C 语言探究(0)

泛型指针 通常情况下&#xff0c;C只允许相同类型的指针之间进⾏转换。例如&#xff1a;⼀个 字符型指针sptr&#xff08;⼀个字符串&#xff09;和⼀个整型指针iptr&#xff0c;我们不允许把sptr 转换为iptr或把iptr转换为sptr。但是&#xff0c;泛型指针能够转换为任何类型的…

ClickHouse基础知识(四):ClickHouse 引擎详解

1. 表引擎的使用 表引擎是 ClickHouse 的一大特色。可以说&#xff0c; 表引擎决定了如何存储表的数据。包括&#xff1a; ➢ 数据的存储方式和位置&#xff0c;写到哪里以及从哪里读取数据。 默认存放在/var/lib/clickhouse/data ➢ 支持哪些查询以及如何支持。 ➢ 并发数…

使用ChatGLM3自定义工具实现大模型查询MySQL数据库

ChatGLM3-6B 采用了全新设计的 Prompt 格式&#xff0c;除正常的多轮对话外。同时原生支持工具调用&#xff08;Function Call&#xff09;、代码执行&#xff08;Code Interpreter&#xff09;和 Agent 任务等复杂场景。 什么是工具调用 大模型虽然强大&#xff0c;但是由于…

yolov8 小目标物体检测、分割加强方法

常见下列三种方法加强小物体检测: Detectron2 (这个与yolov8不大相关,这篇不做多介绍,meta算法) SAHI 算法: Slicing Aided Hyper Inference(切片辅助超推理)通过图像切片的方式来检测小目标。 YOLOv8 变体YOLOv8-P2,旨在提高检测小物体的性能。 1、SAHI 算法 学习参…

WPF Button使用漂亮 控件模板ControlTemplate 按钮使用控制模板实例及源代码 设计一个具有圆角边框、鼠标悬停时颜色变化的按钮模板

续前两篇模板文章 模板介绍1 模板介绍2 WPF中的Button控件默认样式简洁&#xff0c;但可以通过设置模板来实现更丰富的视觉效果和交互体验。按钮模板主要包括背景、边框、内容&#xff08;通常为文本或图像&#xff09;等元素。通过自定义模板&#xff0c;我们可以改…

【XR806开发板试用】XR806串口驱动CM32M对小厨宝的控制实验

一.说明 非常感谢基于安谋科技STAR-MC1的全志XR806 Wi-FiBLE开源鸿蒙开发板试用活动,并获得开发板试用。 XR806是全志科技旗下子公司广州芯之联研发设计的一款支持WiFi和BLE的高集成度无线MCU芯片&#xff0c;支持OpenHarmony minisystem和FreeRTOS&#xff0c;具有集成度高、…

切面编程的理解和使用,Java小白入门(五)

我们进入ruoyi-framework,立刻看到的内容 了解一下aspectj 这个概念 概念 面向切面编程&#xff08;AOP&#xff09; 面向切面编程&#xff08;AOP&#xff09;是一种编程范式&#xff0c;重点聚焦于软件应用程序中的关注点分离。AOP 背后的思想是软件应用程序具有多个切面&a…

【Vue2 + ElementUI】el-table中校验表单

一. 案例 校验金额 阐述&#xff1a;校验输入的金额是否正确。如下所示&#xff0c;点击【编辑图标】会变为input输入框当&#xff0c;输入金额。当输入框失去焦点时&#xff0c;若正确则调用接口更新金额且变为不可输入状态&#xff0c;否则返回不合法金额提示 <templat…

Java小案例-一招弄懂线程池

前言 今天跟大家聊一聊无论是在工作中常用还是在面试中常问的线程池&#xff0c;通过画图的方式来彻底弄懂线程池的工作原理&#xff0c;以及在实际项目中该如何自定义适合业务的线程池。 一、什么是线程池 线程池其实是一种池化的技术的实现&#xff0c;池化技术的核心思想…

渗透测试(Lab4.2)

配置WebDeveloper的时候遇到一个错误 导入失败&#xff0c;因为 E:…ovf 未通过 OVF 规范一致性或虚拟硬件合规性检查。 请单击“重试”放松 OVF 规范与虚拟硬件合规性检查&#xff0c;并重新尝试导入&#xff1b; 或单击“取消”以取消导入。如果重新尝试导入&#xff0c;可能…

请问仿写arkts摇杆功能,为什么我的代码,TouchType.Up 时候摇杆动画不能还原呢?请求大佬指点一下

仿照黑马的arkts 写个摇杆功能&#xff0c;但是为什么我的代码&#xff0c;TouchType.Up 时候摇杆动画不能还原&#xff0c; 请求大佬指点一下 import router from ohos.router import curves from ohos.curvesEntry Component struct ItemPage7 {// 小鱼坐标State fishX: nu…