Java并发编程(6)-线程池总结

Java实现并发编程中的线程池管理! 🏆本文收录于「编程与技术实战」专栏,此专栏涵盖了C/C++编程、人工智能、数据结构、机器学习等技术领域的内容,助你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!! 阅读详情

一.为什么要使用线程池

1. 降低资源消耗
2. 减少反复创建线程带来的开销
3. 提高获取线程的响应速度

二.Executor框架

1.什么时Executor框架

Excutor框架与JDK 1.5被引入,用于代替线程的手动start启动,并且为我们提供了线程池的支持等等。
Executor 框架不仅包括了线程池的管理,还提供了线程工厂、队列以及拒绝策略等,Executor 框架让并发编程变得更加简单。

2.Executor框架的组成有哪些

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-43XQIAKi-1574217742215)(http://note.youdao.com/yws/res/3285/BD9F714067A945A8B320D48DEA5F0CF4)]
主要可以分为三个部分:

  1. 任务(Runnable和Callable):任务是Executor提交执行的最小单位,只要实现了Runnable接口或Callable接口并重写相关方法即可被作为任务执行。
  2. 任务执行器(Executor):任务执行器的任务是提交任务(提交Callable任务还可获取到执行结果)。任务执行器需要实现ExecutorService接口,该接口继承自Executor抽象类。常见的任务执行器有ThreadPollExecutor和ScheduledThreadPollExecutor。
    在这里插入图片描述
  3. 异步计算结果(Future)
    Future 接口以及 Future 接口的实现类 FutureTask 类都可以代表异步计算的结果。
    当我们把 Runnable接口 或 Callable 接口 的实现类提交给 ThreadPoolExecutor 或 ScheduledThreadPoolExecutor 执行。(调用 submit() 方法时会返回一个 FutureTask 对象)

三、ThreadPoolExecutor相关

ThreadPoolExecutor位于java.util.concurrent并发包下,为一些Executor提供了基本的实现,在JDK1.5中由Executors中的工厂中的newCachedThreadPool、newFixedThreadPool和newScheduledThreadExecutor方法所返回。但在JDK1.7之后,不能通过Executors去获得ThreadPoolExecutor了,而是需要自己手动去定制。ThreadPoolExecutor是一个灵活的、健壮的池实现,允许用户进行各种各样的定制。

1.ThreadPoolExecutor的构造方法参数
  * 用给定的初始参数创建一个新的ThreadPoolExecutor。
     */
    public ThreadPoolExecutor(int corePoolSize,//线程池的核心线程数量
                              int maximumPoolSize,//线程池的最大线程数
                              long keepAliveTime,//当线程数大于核心线程数时,多余的空闲线程存活的最长时间
                              TimeUnit unit,//时间单位
                              BlockingQueue<Runnable> workQueue,//任务队列,用来储存等待执行任务的队列
                              ThreadFactory threadFactory,//线程工厂,用来创建线程,一般默认即可
                              RejectedExecutionHandler handler//拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
                               )
  1. corePoolSize :
    核心线程池大小,当线程池中的线程数目小于corePoolSize时,新提交任务将创建一个新线程执行任务,即使此时线程池中存在空闲线程。
  2. maximumPoolSize:
    最大线程池大小,表示当前池中可以活跃的最大线程数目。
  3. keepAliveTime :
    线程池中超过corePoolSize数目的空闲线程最大存活时间。
  4. TimeUnit:
    keepAliveTime时间单位。可以设置为TimeUnit.MICROSECONDS、TimeUnit.SECONDS等单位,分别表示毫秒和秒。
  5. workQueue :
    阻塞任务队列,用以存储超出了corePoolSize的线程。
  6. threadFactory:
    新建线程工厂。如果没有的话则使用系统默认的。
  7. RejectedExecutionHandler:
    当提交任务数超过maxmumPoolSize与workQueue之和时,任务会交给RejectedExecutionHandler来处理。如果没有的话则使用系统默认的。
2.不断地往线程池中添加任务

在这里插入图片描述

在这里插入图片描述

  1. 当任务的数量增加时,会增加core线程来处理,但此时线程数量不会超过corePoolSize;
  2. 当core线程全部被占用着且已经达到了corePoolSize,此时不会立即创建新的线程,而是将任务扔到任务队列里面,并且用core线程去执行;
  3. 任务队列满了(意味着插入任务失败),则开始创建MAX线程去处理它们;若线程数达到MAX后,队列还一直是满的(无法处理),则抛出RejectedExecutionException。
3.ThreadPoolExecutor的饱和策略有哪些

首先明确一点,饱和策略会在ThreadPoolExecutor无法处理新增的任务时起作用,即线程数量已经达到了max,且当前的工作队列是满的,无法处理新的任务是:

1.AbortPolicy

抛出RejectedExecutionException异常,即无法处理异常。

2.CallerRunsPolicy

既不抛弃任务也不抛出异常,而是将某些任务回退到调用者,让调用者去执行它。

3.DiscardPolicy

将不能够处理的任务抛弃,不执行它。

4.DiscardOldestPolicy

将任务队列中最老的任务丢弃,而将新的任务放入任务队列中。

4.有哪些线程池
1.newFixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(
                                    nThreads,// corePoolSize
                                    nThreads, // maxmiPoolSize
                                  0L, TimeUnit.MILLISECONDS,
                                  //使用一个基于FIFO排序的阻塞队列,在所有corePoolSize线程都忙时新任务将在队列中等待
                                  new LinkedBlockingQueue<Runnable>());
}

创建可重用且固定线程数的线程池,如果线程池中的所有线程都处于活动状态,此时再提交任务就在队列中等待,直到有可用线程;如果线程池中的某个线程由于异常而结束时,线程池就会再补充一条新线程。原理是有界的阻塞队列。
在这里插入图片描述

2.newCachedThreadPool
public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, // corePoolSize = 0
                                  Integer.MAX_VALUE, // maximPoolSize=2^31 - 1
                                  60L, TimeUnit.SECONDS, // 空闲时间60s
                                 //使用同步队列,将任务直接提交给线程
                                  new SynchronousQueue<Runnable>());
}

创建可缓存的线程池,如果线程池中的线程在60秒未被使用就将被移除,在执行新的任务时,当线程池中有之前创建的可用线程就重用可用线程,否则就新建一条线程。

在这里插入图片描述

3.newSingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {
   return new FinalizableDelegatedExecutorService
                     //corePoolSize和maximumPoolSize都等于,表示固定线程池大小为1
                        (new ThreadPoolExecutor(1, // corePoolSize=1 
                                                1,// maximPoolSize=1
                                                0L, TimeUnit.MILLISECONDS,
                                                new LinkedBlockingQueue<Runnable>()));
}

创建一个单线程的Executor,如果该线程因为异常而结束就新建一条线程来继续执行后续的任务。

在这里插入图片描述

4.newScheduledThreadPool

创建一个可延迟执行或定期执行的线程池。

5.如何确定线程池中需要多少个线程

一般来说,线程池中的线程数量不可盲目地确定和选择,因为如果线程池中线程数量太大,那么CPU会对许多线程进行上下文切换,从而导致效率的低下;如果线程数量太少,又会导致CPU核心数无法被充分地利用。

根据任务的不同,可将任务分为CPU密集型任务与IO密集型任务,它们的区别是CPU密集型任务需要充分地使用CPU操作,几乎不需要CPU等待;而IO密集型任务需要等待IO阻塞,所以CPU会有相对多的空闲时间。以下的N表示N核CPU:

1. CPU密集型任务:N + 1
2. IO密集型任务:2 * N

四、相关问题

1.Runnable与Callable

1. Runnable:无返回值的任务。且任务方法为run()

public interface Runnable {
   /**
    * 被线程执行,没有返回值也无法抛出异常
    */
    public abstract void run();
}

2. Callable:有返回值的任务。且任务方法为V call()

public interface Callable<V> {
    /**
     * 计算结果,或在无法这样做时抛出异常。
     * @return 计算得出的结果
     * @throws 如果无法计算结果,则抛出异常
     */
    V call() throws Exception;
}
2.execute()和submit()
  1. execute():提交的是Runnable,且不能接受返回值。
  2. submit():提交的是Callable,且能接受返回值FutureTask。
    public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<Void> ftask = newTaskFor(task, null);
        execute(ftask);
        return ftask;
    }
    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
        return new FutureTask<T>(runnable, value);
    }
3.shutdown()和shutdownNow()

shutdown()和shutdownNow()内部实现是依次调用线程的interrupt方法去终止线程执行,但不同之处在于shutdown()是终止已经执行完成任务的线程而不会去终止正在执行任务的进程,但shutdownNow()会终止所有状态的线程,无论其是不是正在执行任务。

4.isTerminated()和isShutdown()
  1. isTerminated():当线程池中全部线程都已经关闭时,返回 true。
  2. isShutdown():当线程池调用shutdown()或shutdownNow()方法时,返回true。
pgpool-II安装部署 文章介绍了pgpool-II的核心功能、架构组成以及实际部署的关键配置步骤 阅读详情

相关推荐

Matlab处理气象数据(六)数据的面积加权

由于地理投影导致导致每个像元实际地面面积不同,越靠近北极实际面积越小,越靠近赤道实际面积越大,如果不进行面积加权就简单平均,会导致温度较实际温度偏低。 用以下公式计算地理投影每个像元的面积: double pi = 3.1415926; double R = 6371007.181; //units - m double area = (pi/180.0)*R*R*fabs(sin(dLat1/180.0*pi) - sin(dLat2/180.0*pi)) * fabs(dLon1 - dLo

设计の诗 1万+

JUC之ThreadPoolExecutor(1)总体介绍

ThreadPoolExecutor线程池

爪哇岛咖啡种植农场 418

h5支付不能打开支付宝 ios_iOS支付宝H5支付无法返回APP解决方案

本文前大段在讲楼主是如何解决这个问题的,以及中间遇到的麻烦。赶时间的同学可以直接看最后的 最终解决方案。在讨论之前,我们先看看官方文档上的一句话:注意:在iOS系统中,唤起支付宝App支付完成后,不会自动回到浏览器或商户APP。用户可手工切回到浏览器或商户APP;支付宝H5收银台会自动跳转回商户return_url指定的页面。what? 官方直接跟我们说GG了?楼主不甘心,还是想尝试一下。借鉴之前...

weixin_39864101的博客 856

ThreadPoolExecutor详解

一、ThreadPoolExecutor类讲解 1、线程池状态: 五种状态: 线程池的状态 说明 RUNNING 允许提交并处理任务 SHUTDOWN 不允许提交新的任务,但是会处理完已提交的任务 STOP 不允许提交新的任务,也不会处理阻塞队列中未执行的任务, 并设置正在执行的线程的中断标志位 TIDYING .

赶路人儿 11万+

MaxEnt软件的下载与安装

1、下载网站:http://lucky-boy.ys168.com/ (这是之前在网上搜到的,里面有许多软件安装包,感谢网页主的资源共享,违权必删)

weixin_42191203的博客 2万+

中心对数比变换(Centered Log Ratio Transformation,CLR)的原理及scikit-bio介绍

中心对数比变换(Centered Log Ratio Transformation,CLR)是一种数据预处理方法,常用于成分数据分析领域。在成分数据中,各成分之间通常存在一定的约束关系,比如它们的和为固定值等,中心对数比变换可以有效地处理这种具有特殊约束的数据。官方文档scikit-bio是一个在Python3中处理生物数据的库成分统计 (skbio.stats.composition )模块中的,此函数将组合从Aitchison几何体转换到真实空间。这个clr。

RECORD LEARN PROGRESS 1万+

Java并发——ThreadPoolExecutor详解(一)

ThreadPoolExecutor 类ThreadPoolExecutor可以非常方便地创建线程池对象,而不需要程序员设计大量的new实例化Thread相关的代码。 构造: ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) corePoolSize:池中所保存的线程数,包括空闲线程,也就

吴声子夜歌的博客 1916

MD01和MD01N比较

摘要:MD01(传统MRP)与MD01N(MRP Live)是SAP系统不同版本的物料需求计划事务码。核心差异包括:MD01N取消MRP列表、简化计划规则、合并MPS/MRP操作、采用BAdI技术等,体现S/4HANA平台简化、标准化和智能化的演进方向。MD01N通过优化参数配置、增强筛选功能、利用HANA实时计算能力,实现了更高效的物料计划流程,代表了新一代计划引擎的技术革新。

SAP_LES_COM的博客 893

线程池之ThreadPoolExecutor概述

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_33695450的博客 262

【反蒸馏实战 00】AI抢不走的工作:一份针对30个“高危”职位的“反取代”实战手册(反蒸馏计划启动)

AI时代职场生存指南:30个技术岗位的“反蒸馏”实战策略 随着AI技术快速发展,职场正面临前所未有的结构性重构。本系列专栏聚焦30个技术岗位,深入分析AI对各职位的影响路径,并提供系统性的"反蒸馏"策略。通过5层分析框架(AI冲击现状、核心价值解构、AI天花板、能力升级路径、人机协作模式),帮助从业者识别可替代任务与核心价值,建立不可替代的专业优势。内容涵盖IT开发、数据分析、产品管理等技术领域,为职场人提供从“被AI替代”到“与AI协同”的转型路线图,守护职业价值。

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 1654

2023.03.27更新大麦网PC端抢购软件和使用教程

近期发现大麦网页端抢购页面悄然发生变化,之前可以在页面选择票价、档次,并且点击按钮进行购票,现在不行了,新的页面如下图所示。已经安全没有了点击按钮,因此,但是并不代表不能像以前之前那样。

猫敷雪 1万+

ThreadPoolExecutor 参数详解

1、 ThreadPoolExecutor 数据成员 private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); ctl 主要用于存储线程池的工作状态以及池中正在运行的线程数。显然要在一个整型变量存储两个数据,只能将其一分为二。其中高3bit用于存储线程池的状态,低位的29bit用于存储正在运行的线程数。 线程...

猎人在吃肉 2万+

从零开始用 C# 打造工业级上位机系统:完整项目实战

本文介绍了一个基于C#开发的工业级上位机系统项目。该系统采用分层架构设计,包含通信、数据采集、UI展示、告警日志等模块,支持Modbus协议和串口通信。文章详细阐述了系统架构设计、关键模块实现(如Modbus通信封装、实时数据采集、告警系统等)以及性能优化策略。该项目已在实际工控场景中稳定运行超过1年,具备良好的可扩展性和稳定性,适合有一定C#基础的开发者参考学习工业软件开发实践。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 1370

6、Java并发编程:线程池的使用

在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题:   如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。   那么有没有一种办法使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任务?   在Java中可以通过线程池来达到这样的...

dxx707099957的博客 164

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

java线程池使用实例6_Java并发编程:线程池的使用

Java并发编程:线程池的使用在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题:如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。那么有没有一种办法使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任务?在Java中可以通过线程池来达到...

weixin_39869693的博客 240

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

Java并发编程第6讲——线程池(万字详解)

Java中的线程池是运用场景最多的并发框架,几乎所有需要异步或并发执行任务的程序都可以使用线程池,本篇文章就详细介绍一下。首先有关线程的使用会出现两个问题: 线程是宝贵的内存资源、单个线程约占1MB空间,过多分配易造成内存溢出。频繁的创建及销毁线程会增加虚拟机回收频率、资源开销,造成性能下降。基于如上问题,出现了线程池:线程容器,可设定线程分配的数量。将预先创建的线程对象存入池中,并重用线程池中的线程对象。避免频繁的创建和销毁。

让~学习~成为一种习惯(橡 皮 人の技术博客) 1558

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

Java并发编程-6.线程池

Java并发编程-线程池

silly8543 193

Java并发编程笔记6:线程池的使用

ThreadPoolExecutor 在 Executoors 中的 newChachedThreadPool, newFixedThreadPool, newScheduledThreadExecutor 的工厂方法返回的都是 ThreadPoolExecutor 对象。如果默认的执行策略不能满足需求,可以通过 ThreadPoolExecutor 的构造函数进行实例化,根据自己的需求定制。 )...

weixin_33860553的博客 201

java并发编程(6)--线程池

1.创建固定大小的线程池 2.创建缓存线程池 3.创建单一线程池

sh542610的专栏 471

java线程池介绍(java并发编程实战第6章)

为什么需要使用线程池? one-thread-per-request可能带来的问题: 1. 线程的创建和销毁会占用一定的资源. 如果请求频繁而对请求的处理是轻量级的(大多的web请求符合该情形), 创建一个线程处理请求后将其销毁的方式是不划算的. 2. 过多的线程导致线程切换频繁, 用于处理请求的CPU时间反而会减少. 如果当前的线程数已经让CPU处于忙碌状态, 那么增加更多的线程不会

u012572955的专栏 376

Java并发编程的艺术6之Java中的13个原子操作类、并发工具类、线程池、Executor框架

Java从JDK1.5开始提供了java.util.concurrent.atomic包,这个包中的原子操作类提供了一种用法简单、性能高效、线程安全地更新变量地方式。 6.Java中的13个原子操作类 6.1.原子更新基本类型 使用原子方式更新基本类型,Atomic包提供了三个类:AtomicBoolean、AtomicInteger、AtomicLong。 几种常用方法: int add...

worldeert的博客 232

Java并发编程基础

进程是操作系统进行资源分配和调度的基本单位,是程序的一次执行实例。这里主要理解为对内存进行分配的基本单位,主要为内存,其余少量网络IO等。

HelloMyAndYourWorld的博客 767

《Java 并发编程》线程池

《Java 并发编程》线程池🚀1. 自定义线程池🚀2. ThreadPoolExecutor🚁2.1 线程池状态🚁2.2 构造方法🚁2.3 newFiexedThreadPool🚁2.4 newCachedThreadPool🚁2.5 newSingleThreadExecutor🚀3. 提交任务🚀4. 关闭线程池🚀5. 任务调度线程池 🚀1. 自定义线程池 阻塞队列中维护了由主线程(或者其他线程)所产生的的任务 主线程类似于生产者,产生任务并放入阻塞队列中 线程池类似于消费者,得到阻塞队列中已有的任务

华仔仔的博客 2596

Java并发编程面试题: 线程池

收集大量Java经典面试题目,内容涵盖了包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 等知识点。适合准备Java面试的读者参考和复习。

m0_46013789的博客 1602

线程池:Java并发编程的加速器

线程池通过复用线程,显著减少了线程创建和销毁的开销,提高了资源利用率和任务的响应速度。它允许预先创建一组线程,并在需要时从池中取出线程来执行任务,任务完成后线程返回池中等待下一个任务。

✨ 欢迎来到【Seal ^_^ 的优快云博客】!✨ 5114

Java 并发编程下篇 -(线程池)

七、线程池

雾里 4084
上一篇: Java并发编程(5)-Executor线程调度框架的使用
下一篇: Java并发编程(7)-ThreadPoolExecutor的饱和策略
BoringRong
BoringRong 领域专家: 后端开发技术领域 领域专家: 后端开发技术领域
博客等级 码龄9年 2万+粉丝 386原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BoringRong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值