JAVA多线程进阶篇 11、JUC线程池之ThreadPoolExecutor

JUC详解(各种乱七八糟的锁) JUC 进程和线程: 进程:一个进程可以包含多个线程,至少是一个线程,java默认2个线程——main、GC(垃圾回收) 线程:开了一个软件,写字的时候也会有自动保存的线程在进行,Thread、Runnable、Callable java开启不了线程,java操作的是底层的C++,java无法操作,用的是虚拟机 并发与并行: 并发:多线程操作同一个资源(假设cpu只有一核的时候,模拟多线程,快速交替处理线程) 并行:CPU多核情况下才有,多个线程同时执行 并发编程的本质:充分利用电脑的CPU 线程有几种 阅读详情

1. 为什么要使用线程池?

如果放任线程无限制地创建,会耗尽CPU资源,并且降低系统的响应速度。
为了更好的对线程进行管理,实现线程的统一分配,调优和监控,降低资源消耗。
JUC设计了线程池。线程池从机制上分为两种.,一是ThreadPoolExecutor,另一类是ForkJoinPool。

  • ThreadPoolExecutor
    使用多个线程和阻塞队列实现对线程和任务进行管理的工具。
  • ForkJoinPool
    将一个大任务拆分为很多小任务来异步执行的管理的工具。

1.1 Executor 和 ExecutorService

ThreadPoolExecutor 和 ForkJoinPool 都实现了Executor 和 ExecutorService接口。
Executor 和 ExecutorService接口规定了对线程池使用的提交任务和关闭任务的方法。

1.2 线程池提交任务

  • execute()方法是Executor接口规定的。只能接受Runnable类型的任务。
    void execute(Runnable command);
  • submit()方法是ExecutorService接口规定的。有返回值,且可以通过Future.get()抛出Exception
    <T> Future<T> submit(Callable<T> task);
    <T> Future<T> submit(Runnable task, T result);
    Future<?> submit(Runnable task);

1.3 线程池关闭

  • shutdown()方法,shutdown只是将线程池的状态设置为SHUTWDOWN状态,正在执行的任务会继续执行下去,没有被执行的则中断。

  • shutdownNow(),而shutdownNow则是将线程池的状态设置为STOP,正在执行的任务则被停止,没被执行任务的则返回。

    shutdownNow会停止正在运行的线程。

2. ThreadPoolExecutor

2.1 构造方法与参数

  • int corePoolSize:核心线程数,常驻在线程池内。
  • int maximumPoolSize:最大线程数。
  • long keepAliveTime:当线程池里线程数量大于corePoolSize时,会将超时空闲的线程进行关闭,keepAliveTime代表时间计量。
  • TimeUnit unit:当线程池里线程数量大于corePoolSize时,会将超时空闲的线程进行关闭,unit代表时间单位。
  • BlockingQueue workQueue:存储线程任务的队列。
  • ThreadFactory threadFactory:创建线程的方法,可以自定义。
  • RejectedExecutionHandlerhandler:当线程数大于maximumPoolSize,且workQueue放不下时,拒绝任务的策略,可以自定义。
    • RejectedExecutionHandlerhandler

构造方法:

   public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              RejectedExecutionHandler handler) 

2.2 ThreadPoolExecutor原理

  • 线程池首先当前运行的线程数量是否少于corePoolSize。如果是,则创建一个新的工作线程来执行任务。如果都在执行任务,否则进入下一步。
  • 判断BlockingQueue是否已经满了,倘若还没有满,则将线程放入BlockingQueue。否则进入下一步
  • 如果创建一个新的工作线程将使当前运行的线程数量超过maximumPoolSize,则交给RejectedExecutionHandler来处理任务。

2.3 自定义ThreadPoolExecutor

尽管Executors实现了多个静态方法来创建各种线程池,在正式工作中,我们应当实现自定义的ThreadPoolExecutor 。根据实际场景需求,指定活动线程的数量,限制线程池的大小、创建我们自己的 RejectedExecutionHandler 实现来处理不能适应工作队列的工作。

以下程序创建的线程池,初始大小为2,最大为5,不设置超时,任务队列大小为3,在创建线程时,为线程自定义命名,当超出了线程池处理容量时,将拒绝任务,并将消息写入队列。

public class ThreadFactoryTest {

    static AtomicLong cnt = new AtomicLong();

    public static void main(String[] args) {

        RejectedExecutionHandler handler = new RejectedExecutionHandler() {
            @Override
            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                System.out.println("我拒绝了任务,并将任务移到MQ中等待以后执行");
            }
        };

        ThreadFactory factory = new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                return new Thread(r,"线程"+cnt.incrementAndGet());
            }
        };

        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 5, 0, TimeUnit.SECONDS, new ArrayBlockingQueue<>(3), factory, handler);
        for(int i=0;i<1000;i++) {
            threadPoolExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+" ,提交任务");
                }
            });
        }
        threadPoolExecutor.shutdown();
    }
}

3. Executors提供ThreadPoolExecutor构造方法

Executors是一个JUC工具类,实现了多个静态方法来创建各种线程池,下面来了解一下。

在高并发环境中并不建议直接使用Executors的方法,建议实现自定义的ThreadPoolExecutor。

3.1 SingleThreadExecutor

线程池中只有一个线程,因此可以保证所提交任务的顺序执行。

  • 核心线程数 1
  • 最大线程数 1
  • 超时时间为0,即不存在超时移除的情况
  • 使用无界的阻塞队列。可存放的任务数为Integer.MAX_VALUE。
    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

3.2 CachedThreadPool

线程池线程不设上限,使用SynchronousQueue作为阻塞队列,当任务来后立即调度线程执行,如果不够,就创建新线程执行。适用于任务压力不平稳的场景。

  • 核心线程数 0
  • 最大线程数 Integer.MAX_VALUE
  • 超时时间为1分钟,1分钟没有任务的线程会被销毁
  • 使用SynchronousQueue作为阻塞队列。可以参考后面介绍JUC集合的博客文章
    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

3.3 FixedThreadPool

指定线程池的线程数量,不会主动销毁线程,也不会增加线程数。适用于任务压力较平稳的场景。
线程池的数量一般根据CPU核数、以及CPU的利用率综合考虑,实际工作中通过压测确定。

  • 核心线程数 nThreads
  • 最大线程数 nThreads
  • 超时时间为0,即不存在超时移除的情况
  • 使用无界的阻塞队列。可存放的任务数为Integer.MAX_VALUE。
    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

3.4 ScheduledThreadPool

任务提供延迟或周期执行。核心线程数由程序指定,线程数不限,使用DelayedWorkQueue来存储任务。

  • 核心线程数 corePoolSize
  • 最大线程数 Integer.MAX_VALUE
  • 超时时间为0,即不存在超时移除的情况
  • 使用DelayedWorkQueue,为存储周期或延迟任务专门定义的一个延迟队列。
    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ThreadPoolExecutor(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
    new DelayedWorkQueue());
    }

总结

为了更好的对线程进行管理,实现线程的统一分配,调优和监控,降低资源消耗,JUC设计了线程池。

Executors实现了多个静态方法来创建各种线程池,在正式工作中,我们应当实现自定义的ThreadPoolExecutor 。

多线程系列在github上有一个开源项目,主要是本系列博客的实验代码。

https://github.com/forestnlp/concurrentlab

如果您对软件开发、机器学习、深度学习有兴趣请关注本博客,将持续推出Java、软件架构、深度学习相关专栏。

您的支持是对我最大的鼓励。

四万字爆肝总结java多线程所有知识点(史上最全总结) 这是笔者历时三周左右总结的所有java多线程中的知识点,只要是多线程的问题这里都可以看到,笔者使用通俗易懂的语言介绍了各个场景,以及他们实现的原理,希望对路过的你有所帮助。 阅读详情

相关推荐

【Java面试题汇总】多线程、JUC、锁篇(2026版)

线程和进程的区别、CAS的ABA问题、AQS、哪些地方使用了CAS、怎么保证线程安全、线程同步方式、synchronized的用法及原理、Lock、volatile、线程的六个状态、ThreadLocal、线程通信方式、创建方式、两种创建线程池的方法、线程池设置合适的线程数、线程安全的集合?ConcurrentHashMap、JUC

种一棵树最好的时间是十年前,其次是现在 1万+

Java线程池ThreadPoolExecutor详细介绍与使用

Java线程池ThreadPoolExecutor详细介绍与使用

qq_27480007的博客 1万+

【Java多线程】JUC之线程池(一)与线程池的初识

线程池概念 有时候,系统需要处理非常多的执行时间很短的请求,如果每一个请求都开启一个新线程的话,系统就要不断的进行线程的创建和销毁,有时花在创建和销毁线程上的时间会比线程真正执行的时间还长。而且当线程数量太多时,系统不一定能受得了。 概念:线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。我们将任务添加到任务队列中,线程池得知有任务到来后,会唤醒线程,如若所有线程都在执行任

墩墩分墩 1227

springboot项目中使用线程池来实现上万条数据的excel文件上传保存到数据库

请根据你项目中的实际需求和结构调整这些。

qq_51891433的博客 865

从零搭建高通8255车载开发环境:QNX SDP、SDK配置与镜像编译全流程

本文详细介绍了如何从零搭建高通SA8255P车载开发环境,涵盖QNX SDP部署、SDK工具链配置到多系统镜像编译的全流程。特别针对SAIL安全岛镜像构建、QNX系统优化及Android系统资源分配等关键技术点提供实战指导,帮助开发团队高效完成车载系统开发与调试。

weixin_33582311的博客 364

星座SAR动目标检测(GMTI)

参考代码 星座SAR动目标检测 www.youwenfan.com/contentcsg/52399.html。

feifeigo123的博客 549

使用线程池 插入万条数据做压力测试

往数据库插入一万条数据多线程

qq_53170175的博客 482

PSO算法介绍

结合网上的文章对PSO进行一些介绍,并附上自己复现的算法。

Witty_Hou的博客 1万+

Java多线程做压力测试

写一个多线程做压力测试的例子: public interface RequestHandler<T> { public void handle(T result); } package com.arch; import java.util.ArrayList; import java.util.List; import java.util.concurrent.*; public class ConcurrentTestUtil { /**

不见其长,日有所长 1714

手把手完整实现STM32+LORA组网网关+机智云平台+手机APP应用———第一节- 一主多从的LORA本地组网通信-实现从机采集温湿度与主机显示数据

本教程为《手把手实现STM32+LORA组网网关+机智云平台+手机APP应用》第一节。实现一个主机,两个从机的LORA组网通信。两个从机采集温湿度数据并通过LORA传输数据到主机,然后主机接收到两个从机数据后进行数据显示,本节通过PC串口助手显示两个从机的数据。 下一节将其主机接收的数据通过WIFI网关(ESP8266)传到机智云平台与手机APP。 本文讲解一主多从的LORA本地组网通信,串口助手进行数据展示。使用硬件主要包括:STM32F103C8T6最小系统板(3个)、正点原子LORA模块ATK-L

嵌入式阿齐Archie 1万+

学Simulink——基于AI融合与智能调度的场实例:联邦学习支持的多卫星协同通信建模

本文介绍了一种基于联邦学习的多卫星协同通信Simulink建模方法。系统采用"星-星协同+星-地协调"架构,每颗卫星本地训练LSTM链路预测模型,地面中心通过FedAvg算法聚合模型参数。建模过程包括卫星通信模型构建、联邦学习机制设计、协同决策系统开发等步骤,支持隐私保护、高效协同和智能决策。仿真结果表明,该方法在预测准确率(89%)、吞吐量(56.7Mbps)等方面优于独立训练模式,接近集中式训练性能。该方案为大规模卫星星座的智能协同提供了仿真验证平台,未来可拓展去中心化联邦学习、异构

xiaoheshang_123的博客 209

java 多线程压测_java多线程模拟loadrunner进行压测

package syttest;/*** @author yuzhuliu:* @version 创建时间:2017年9月26日 下午11:58:21* 类说明*/public class ThreadTest {public static int threadCount=1;//启动线程数量public static int threadExcuteCount=10;//每个线程执行任务次数,没...

weixin_34771903的博客 356

【面试系列】软件架构师 高频面试题及详细解答

本文介绍了软件架构师岗位的初级、中级和高级面试题及详细解答,涵盖了系统设计、面向对象设计、分布式系统、云计算技术、性能优化等关键领域。通过这些问题和解答,候选人可以深入理解软件架构师的核心职责和技能要求。此外,文章总结了在面试中需要掌握的常考知识点,包括架构模式、分布式系统管理、安全性、数据管理和DevOps实践。通过掌握这些知识点,软件架构师能够有效设计和指导复杂系统的结构,确保系统的可扩展性、性能和维护性。

在路上的专栏 850

【JUC】ThreadPoolExecutor 合理的配置线程池的大小

ThreadPoolExecutor 合理的配置线程池的大小,了解一下。

tanpenggood 1598

计算机组成原理(第三版)唐朔飞-第十章控制单元的设计-课后习题

计算机组成原理(第三版)唐朔飞-第十章控制单元的设计-课后习题

weixin_45735391的博客 3万+

【二.图像处理核心技术】【5.形态学操作:腐蚀/膨胀/开闭运算】

想象一下,你拍了一张布满雪花点的老照片,或者扫描了字迹断裂的文档,这时候形态学操作就是你的像素整形师!它们能让模糊的边界变清晰,把断裂的笔画连起来,甚至从X光片里揪出癌细胞。今天我们要聊的,是计算机视觉界的"广场舞双雄"——腐蚀和膨胀。这俩操作就像给像素点们请了个健身教练,要么集体减肥(腐蚀),要么组团增肌(膨胀)。下次当你用美颜相机时,不妨会心一笑——这看似魔法的背后,正是形态学在默默耕耘。腐蚀的规则很简单:如果一个像素点周围的邻居不全白,它就"狗带"(变黑)。:先用砂纸打磨(腐蚀),再喷漆填补(膨胀)

商务合作|问题讨论|交流学习 请联系作者微信,加微信请务必注明来意,博客主页有联系方式 426

Java多线程基础-11:工厂模式及代码案例之线程池

Java中代码案例之线程池,详解 ExecutorService 接口,ThreadPoolExecutor类,代码实现线程池;详解工厂模式

wyd_333的博客 2305

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Java多线程系列--“JUC线程池”01之 线程池架构

概要 前面分别介绍了"Java多线程基础"、"JUC原子类"和"JUC锁"。本章介绍JUC的最后一部分的内容——线程池。内容包括:线程池架构图线程池示例 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3509903.html 线程池架构图 线程池的架构图如下: ScheduledThreadPoolExecutor继承Thread...

LMAKE_nbsp的博客 194

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

Java多线程系列--“JUC线程池”03之 线程池原理——线程池源码分析

概要 在前面一章"Java多线程系列--“JUC线程池”02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明。内容包括:线程池示例参考代码(基于JDK1.7.0_40)线程池源码分析 (一) 创建“线程池” (二) 添加任务到“线程池” (三) 关闭“线程池” 转载请注明出处:http://www.cnblogs.com/skywa...

LMAKE_nbsp的博客 3023

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

【尚硅谷/周阳】JUC学习笔记

JUC学习笔记【尚硅谷/周阳】 本文章基于B站视频教程【juc 与 jvm 并发编程 Java 必学_阳哥- 尚硅谷】进行整理记录,仅用于个人学习,交流使用。 0.课前引入 1.进程/线程是什么? 进程: 进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。 线程: 通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义。线程可以利用进程所拥有的资源,在引入线程的操作系

耿鬼不会笑的博客 3776

JUC之线程池

JUC之线程池1 前言1.1 Callable接口1.2 注意2.ThreadPoolExecutor2.1 为什么用线程池2.2 线程池的好处2.3 架构说明2.4 线程池的创建2.4.1 Executors.newFixedThreadPool(int count)2.4.2 Executors.newSingleThreadExecutor()2.4.3 Executors.newCacheThreadPool()2.4.4 Executors.newScheduledThreadPool(int

weixin_44533129的博客 424

【第九章】JUC之ThreadPoolExecutor线程池详解

一、线程池简介   线程池主要是为了控制运行的线程数量,处理过程中将任务放到队列中,然后在线程创建后启动这些任务,如果线程数超过了最大数量,超出数量的线程排队等候,等其它线程执行完毕,再从队列中取出任务来执行。 线程池主要特点是:线程复用、控制崔大并发数、管理线程。 二、如何使用线程池?   Java中的线程池是通过Executor框架实现的,该框架中用到了Executor、Executors、E...

林大侠 399

JUC第二十讲:深入理解 Java 中的线程池

先看几道多线程相关的问题 1、三个线程 a、b、c并发运行,b,c线程需要a的数据怎么实现? 难点: 1、是让 ThreadB 和 ThreadC 等待 ThreadA 先执行完 2、 ThreadA 执行完之后给ThreadB和ThreadC发送消息 思路:我们必须让ThreadB和ThreadC去等待ThreadA完成任务后发出的消息 并使用Semaphore类来控制线程的等待acquire........................

Jet_qi的博客 742

大厂高频面试题复习JAVA学习笔记-JUC多线程及高并发(下)

0 JUC基础概念wait/sleep的区别并发与并行的区别线程的六个状态JUC结构 ​编辑1 请谈谈你对volatile的理解JMM(java内存模型)可见性不保证原子性有序性​编辑指令重排双端检查机制DLC2 CAS你知道吗?3 原子类AtomicInteger的ABA问题谈谈?原子更新引用知道吗?原子引用4 我们知道ArrayList是线程不安全,请编码写一个不安全的案例并给出解决方案。list​编辑setmap参数传递​编辑5 公平锁/非公平锁/可重入锁/递归锁/自旋锁谈谈你的理解?

qq_51586702的博客 1488

Java - 基础 & JUC 多线程

基础多线程 1、程序 · 进程 · 线程 程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念 进程是程序的一次执行过程,是一个动态的概念;进程是系统资源分配的单位 线程是CPU调度和执行的单位,是一个独立的执行路径;一个进程可以包含多个线程,且一个进程中至少应有一个线程,不然没有存在的意义 在程序运行时,即使没有自己创建线程,后台也会有线程在跑,如main主线程、gc垃圾回收线程等 主线程main()是系统的入口,用于执行程序 在一个进程中,如果开辟了多个线程,线程的运

qq_43613793的博客 349

JUC 多线程并发编程

进程(Process):计算机中正在运行的程序的实例,是操作系统分配资源的基本单位。每个进程拥有自己的内存空间、文件描述符、数据栈等。 线程(Thread):进程中的一个执行单元。一个进程中至少有一个线程,通常称为主线程。线程是 **CPU 调度和执行的最小单位。** 线程共享进程的资源,一个进程中的多个线程可以并发执行,线程之间的通信比进程之间的通信更高效。 ### 2. 并发与并行 并发(Concurrency):系统能够在同一**时间段**内处理多个任务,但这些任务可

小程xy的博客 1937
上一篇: JAVA多线程进阶篇 10、JUC之Callable Future FutureTask
下一篇: JAVA多线程进阶篇 12、JUC线程池之ForkJoinPool
悟空学编程
博客等级 码龄12年 32粉丝 123原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

打赏作者

悟空学编程

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

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

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

打赏作者

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

抵扣说明:

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

余额充值