线程池原理

线程和线程池七大参数、线程池分类、运行原理详解,线程池的使用场景 文章目录1. 线程2. 线程池 1. 线程 1.1线程         线程是调度CPU资源的最小单位,线程模型分为KLT模型与ULT模型,JVM使用的KLT模型,一个java线程对应一个OS线程,线程有多个生命状态 ①:NEW :新建 ②:RUNNABLE :运行 ③:BLOCKED :阻塞 ④:WAITING :等待 ⑤:TIMED_WAITING :超时等待 ⑥:TERMINATED :终结 其中运行又分为 就绪、运行中 阅读详情

目录

属性

核心属性

阻塞队列

饱和策略 

状态属性

状态分类

状态转换

新增任务

处理流程

对于核心线程

进阶 

合理配置线程池 

任务的性质

任务的优先级

任务的执行时间

任务的依赖性 

建议使用有界队列 

线程池分类 

FixThreadPool 

SingleThreadExecutor 

CachedThreadPool

ScheduledThreadPool 

WorkStealingPool 


属性

核心属性

  1. int corePoolSize:核心线程数量
  2. int maximumPoolSzie:最大线程数量
  3. long keepAliveTime:非核心线程的最大空闲等待时间
  4. boolean allowCoreThreadTimeOut:核心线程也使用最大空闲等待时间;默认 false
  5. BlockingQueue<Runnable> workQueue:任务队列
  6. ThreadFactory threadFactory:线程工厂;所有线程都使用此工厂创建
  7. RejectedExecutionHandler handler:拒绝策略;线程数达到上限,任务队列已满,对新提交的任务采取的策略

阻塞队列

有界:

  • ArrayBlockingQueue:由数组组成的有界阻塞队列;按插入顺序排序;默认不公平访问。
  • LinkedBlockingQueue:由链表组成的有界阻塞队列;按插入顺序排序。
  • SynchronousQueue:不存储元素的阻塞队列;每个插入操作,必须等到另一个线程调用移除操作,否则一直阻塞。

无界:

  • PriorityQueue:支持优先级排序的无界阻塞队列;不保证同优先级元素排序,可自行重写比较器。
  • DelayQueue:使用优先级队列实现的无界阻塞队列,可实现任务定时执行;缓存系统设计(保存缓存有效期)
  • LinkedTransferQueue:由链表组成的无界阻塞队列。
  • LinkedBlockingDeque:由链表组成的无界双向阻塞队列。

饱和策略 

  • AbortPolicy:直接抛出异常。
  • CallerRunsPolicy:直接用调用者线程执行任务。
  • DiscardOldestPolicy:丢弃队列中最早元素,并尝试插入,失败则不断重试。
  • DiscardPolicy:不处理,直接丢弃。

状态属性

状态分类

  • RUNNING:能接受新的任务,并且能处理阻塞队列中的任务。
  • SHUTDOWN:不再接受新的任务,但是能处理阻塞队列中的任务。
  • STOP:不再接受新的任务,也不再处理阻塞队列中的任务。
  • TIDYING:所有任务都已终止。
  • TERMINATED:默认是什么都不做,只是一个标识。

状态转换

新增任务

处理流程

对于核心线程

  • 并没有真正意义上的核心线程,只是一个数量的概念。
  • 对外而言存在核心线程,底层其实没有实现,所有线程都是同等的。
  • 当前线程获取任务时,工作线程数量 <= 核心线程数量,则它就是核心线程;否则它不是核心线程。
// 线程获取任务
private Runnable getTask() {
    // 当前线程上次获取任务是否超时
    boolean timedOut = false; 

    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);

        // 线程池已不再接受新任务,并且不再处理队列中任务或者队列为空
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            // 当前线程可以销毁
            decrementWorkerCount();
            return null;
        }

        // 获取当前工作线程数量
        int wc = workerCountOf(c);

        // 核心线程允许超时销毁 || 当前线程数 > 核心线程数
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
        
        // 当前线程是否满足销毁条件:1.工作线程数量 2.核心线程是否可销毁
        // ⭐⭐⭐没有对线程进行特殊判断(是否为核心线程)
        // ⭐⭐⭐对外而言存在核心线程,底层其实所有线程都同等。
        if ((wc > maximumPoolSize || (timed && timedOut))
            && (wc > 1 || workQueue.isEmpty())) {
            if (compareAndDecrementWorkerCount(c))
                return null;
            continue;
        }

        // 从阻塞队列获取新任务
        try {
            // 是否需要超时获取
            Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                workQueue.take();
            if (r != null)
                return r;
            timedOut = true;
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}

进阶 

合理配置线程池 

任务的性质

  1. CPU 密集型任务:需要消耗大量 CPU 资源的任务,解压、解密、计算;大部分线程都需要使用 CPU 资源,线程设置过多,会频繁出现上下文切换,影响性能;CPU + 1。
  2. IO 密集型任务: MySQL、文件读写、网络传输;线程等待 IO 时,不需要 CPU 计算,可以让出 CPU,假如线程设置过少,CPU 资源不能得到充分利用;CPU * 2。
  3. 混合型任务:假如两任务执行时间相差不大,将任务拆分成 CPU 密集型、IO 密集型,吞吐量高于直接串行;假如执行时间相差太大,则直接串行。

线程数 = CPU 核心数 * (1 + IO 耗时 / CPU 耗时)

任务的优先级

使用优先级队列处理。 

任务的执行时间

  1. 可使用优先队列。 
  2. 平均工作时间(使用 CPU)占比越高,线程数则越少。
  3. 平均等待时间(IO 等)占比越高,线程数则越多,充分利用 CPU 资源。

任务的依赖性 

是否依赖其他系统资源,如数据库连接;提交 SQL 后需要等待,此时不需要 CPU 计算,应该设置大线程数,充分利用 CPU 资源。 

建议使用有界队列 

有界队列能增加系统的稳定性和预警能力,可以根据需求设大一些,但是不建议使用无界。 

无界队列,可能导致内存被撑满,使得整个系统不可用。

线程池分类 

FixThreadPool 

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}
// 无界
public LinkedBlockingQueue() {
    this(Integer.MAX_VALUE);
}

队列无界:核心线程饱和后,任务添加至队列等待。

  • “最大线程数”与“非核心线程最大空闲时间” 无效。
  • 任务永远不会被拒绝。
  • 多个任务并行执行。

应用场景:只有核心线程,并且都不会销毁,将一直占用资源;适合数量固定且耗时较长的任务,让线程保持忙碌状态。

SingleThreadExecutor 

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}
// 无界
public LinkedBlockingQueue() {
    this(Integer.MAX_VALUE);
}

队列无界:唯一核心线程创建后,任务添加至队列等待。

  • “最大线程数”与“非核心线程最大空闲时间” 无效。
  • 任务永远不会被拒绝。
  • 单个线程,所有任务串行执行。

应用场景:多任务顺序执行。

CachedThreadPool

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}
// 空队列
public SynchronousQueue() {
    this(false);
}

空队列:添加新任务,需要其他空闲线程取走,否则创建非核心线程,60s 最大空闲时间。

  • 任务提交速度 > 线程处理任务速度,会不断创建新线程;可能耗尽内存和 CPU 资源。

应用场景:全是非核心线程,60s 自动销毁,不会占用系统资源;适合任务量大但耗时短的任务。

ScheduledThreadPool 

public static ExecutorService newWorkStealingPool(int parallelism) {
    return new ForkJoinPool
        (parallelism,
         ForkJoinPool.defaultForkJoinWorkerThreadFactory,
         null, true);
}

public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
          new DelayedWorkQueue());
}

// 实现任务周期性执行
scheduleAtFixedRate
scheduleWithFixedDelay

队列无界:核心线程饱和后,任务添加至队列等待。

  • 任务执行完,修改下次执行时间,重新放入队尾。

应用场景:定时任务,具体固定周期的重复任务。

WorkStealingPool 

// 1.8 加入,为 Fork/Join 的扩展
// parallelism 表示并行度
public static ExecutorService newWorkStealingPool(int parallelism) {
    return new ForkJoinPool
        (parallelism,
         ForkJoinPool.defaultForkJoinWorkerThreadFactory,
         null, true);
}

Fork/Join:将“大任务“拆分成多个“小任务”,并分发到多个线程;所有任务执行完,再进行合并。

  • 工作窃取算法:每个线程都对应一个任务队列,互不干扰;线程获取自己队列中任务为 FIFO;任务都完成后,会去其他线程任务队列中获取任务,为了减少冲突,从队尾取 LIFO。
  • 将任务拆分,并行执行,提高效率;但是会消耗更多的系统资源。
  • 不指定 parallelism 则默认为 CPU 核数。

应用场景:适合很耗时的任务。

Labview项目01:标准可配置序列测试框架 摘要:本文介绍了一个基于LabVIEW2020开发的通用测试框架系统。该系统采用模块化设计,包含主界面、调试界面、设置界面和登录界面。主功能包括:1)可配置测试序列,支持延时、预定值输出、随机值输出等操作;2)单步测试功能自主添加;3)界面支持测试序列编辑和权限管理。系统采用队列机制处理事件和测试流程,通过CSV文件存储测试序列,支持参数化配置。用户可自定义测试VI(A_.vi和N_.vi格式),并通过调试界面验证测试序列。最终测试结果在主界面显示,提供整体判断功能。该系统既可作为学习参考,也可用于实际测试 阅读详情

相关推荐

vietjetair 航空的webpack多参数生成学习

工作内不是特别多,居安思危,有一个抓机票信息的公司面试前竟然需要做面试题,这就是一个题。看了下,有点麻烦,webpack 最初不得要领,看了下资料,找了个框架,练了两个简单的,搞这个吧。入库需要自己找,有几个参数不是明文的,算法不是很复杂,位置不太好找。整体难度一般。

liu_yueyang的博客 1510

【JUC】线程池原理

线程池:一个容纳多个线程的容器,容器中的线程可以重复使用,省去了频繁创建和销毁线程对象的操作降低资源消耗,减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务提高响应速度,当任务到达时,如果有线程可以直接用,不会出现系统僵死提高线程的可管理性,如果无限制的创建线程,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控线程复用,同一个线程可以被重复使用,来处理多个任务池化技术。

Yinin.的博客 1179

ubuntu20.04下内核源码下载分析

ubuntu 20.04下内核源代码下载,配置编译环境写在前面一、安装VMware Workstation和Ubuntu20.04二、修改apt源合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入 写在前面 我最近的科研工作需要使用到对ubun

冰冻三尺非一日之寒 1万+

Tomcat线程池监控及线程池原理分析

当有新任务时,Tomcat的线程池核心线程如果已经创建完了,Tomcat会尽最大努力开启新的非核心线程去执行新任务,而JUC的ThreadPoolExecutor则是入队,等待队列满了再创建新的非核心线程去执行任务。

wenyixicodedog的博客 1万+

避坑!瑞萨RZ/N2L用J-Link下载调试的那些‘坑’(从驱动版本到硬件架构选择)

本文详细解析了瑞萨RZ/N2L开发中使用J-Link调试时常见的兼容性问题与解决方案,包括驱动版本选择、SWD连接优化及e2 studio调试技巧。特别针对硬件架构与驱动版本的匹配问题提供了实用对照表,帮助开发者高效避开调试陷阱,提升开发效率。

weixin_30576827的博客 441

PyTorch实战:5步搞定QAT量化感知训练(附避坑指南)

本文详细介绍了在PyTorch中实施量化感知训练(QAT)的五步实战流程。通过环境准备、模型融合、伪量化节点与STE原理剖析、校准微调训练、模型转换与导出等步骤,帮助开发者有效压缩模型以适配移动端与边缘设备部署,并提供了关键的超参数设置与常见问题避坑指南。

weixin_29083373的博客 417

Tomcat线程池原理(上篇:初始化原理)

在Java Web的开发过程中,Tomcat常用的web容器。SpringBoot之前,我们用的是单独的 Tomcat,SpringBoot时代,嵌入了Tomcat。在Jdk中,JUC内有线程框架,以及可以自定义参数配置的 TreadPoolExecutor。Tomcat内也实现了自己的线程池。所谓线程池,是被用来处理传入的 HTTP 请求的。当客户端发送请求时,Tomcat 会从线程池中获取一个可用的线程来处理该请求。处理完请求后,线程将返回线程池,并在下一个请求到来时再次被重用。

FBB360JAVA的博客 2953

TC3XX - MCAL知识点(十一):WDG EB-tresos配置说明与代码浅析

在AUTOSAR中,看门狗栈实现了三种监控机制:实时监控:用于周期软件的定时监控期限监督:针对非周期软件逻辑监督:用于监督执行顺序的正确性看门狗(WDG)驱动实现AUTOSAR(4.2.2)中规定的看门狗SWS,提供初始化、改变操作模式和设置触发条件(超时)等服务,供看门狗硬件(WDT)用户使用。WDG驱动的用户包括:模式管理模块(用于初始化),WdgM通过Wdglf设置触发条件和驱动运行模式设置。WdgM实施上述监督机制。AUTOSAR扩展触发概念,以支持窗口看门狗模式。

梦想技术家 3599

Java线程池实现原理详解

原理概述 其实java线程池的实现原理很简单,说白了就是一个线程集合workerSet和一个阻塞队列workQueue。当用户向线程池提交一个任务(也就是线程)时,线程池会先将任务放入workQueue中。workerSet中的线程会不断的从workQueue中获取线程然后执行。当workQueue中没有任务的时候,worker就会阻塞,直到队列中有任务了就取出来继续执行。 线程池的几...

u013332124的专栏 6万+

RK3399外设驱动之MIPI

RK3399外设驱动之MIPI 文章目录RK3399外设驱动之MIPIMIPI命令解析入口代码mipi显示配置实例rk3399mipi驱动rk mipi驱动注册过程rk32_mipi_dsi.c解析 内核版本 Linux4.4 平台 rk3399 作者 nineyole MIPI命令解析入口代码 MIPI的入口代码如下:kernel\drivers\video\rockchip\screen\lcd_mipi.c static int __init rk_mipi_screen_in

学无止境 2227

STM32实战开发(66):STM32图像处理开发教程

随着物联网、人工智能和嵌入式技术的不断发展,图像处理技术在嵌入式系统中的应用越来越广泛。图像处理不仅在视觉识别、安防监控、智能家居等领域中发挥着重要作用,也在工业自动化、医疗成像、无人驾驶等高科技领域中占据重要地位。而STM32凭借其强大的硬件性能和丰富的外设支持,成为了许多图像处理应用的理想平台。

2201_76125393的博客 1444

Java 线程池的工作原理

Java 线程池主要是用于管理线程组及其运行状态,以便 Java 虚拟机更好地利用 CPU 资源。 Java 线程池的工作原理为:JVM 先根据用户的参数创建一定数量的可运行的线程任务,并将其放入队列当中,在线程创建好后启动这些任务,如果正在运行的线程数量超过了线程池的最大线程数量(线程池的数量是用户自己设置的),那么超出的数量的线程排队等待,在有任务执行完毕后,线程池调度器会发现有可用的线程,进而再次从队列中取出任务并执行。线程池的主要作用就是线程复用,线程资源管理,控制操作系统的最大并发数,以保证系统的

古城的博客 7537

在Simulink中搭建一个基于IoT设备间通信协议栈的仿真模型

物联网(IoT)设备间的通信协议栈仿真对于理解不同层级的协议如何协同工作,以及优化网络性能至关重要。通过Simulink结合MATLAB的强大功能,我们可以模拟和分析从物理层到应用层的完整通信过程。下面详细介绍如何使用Simulink进行IoT设备间通信协议栈的仿真。

amy_mhd的博客 156

线程池的原理及C++线程池的封装实现

线程池原理介绍 线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。 线程池的组成部分: 线程池管理器(ThreadPoolManager):用于创建并管理线程池 工作线程(WorkThread): 线程池中线程 任务接口(Task):每个任务必须实现的接口...

amoscykl的博客 4633

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

java线程池原理

java线程池原理

大猩猩的博客 1099

Devexpress16.2.6破解工具

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

Java线程池原理详解

在Java中可以通过来达到这样的效果。今天我们就来详细讲解一下Java的线程池,首先我们从最核心的ThreadPoolExecutor类中的方法讲起,然后再讲述它的实现原理,接着给出了它的使用示例,最后讨论了一下如何合理配置线程池的大小。以下是本文的目录大纲:一.Java中的ThreadPoolExecutor类二.深入剖析线程池实现原理三.使用示例四.如何合理配置线程池的大小若有不正之处请多多谅解,并欢迎批评指正。

qq_39308587的博客 1049

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

线程池原理及面经

可以实现。

wy990880的博客 948

java线程池的执行原理

Java线程池通过提供了强大而灵活的并发任务管理机制。理解其执行原理有助于我们在实际开发中根据具体需求合理配置和使用线程池,从而编写高效、健壮的并发应用。线程池的合理使用可以显著提高系统的性能和资源利用率,同时简化并发编程的复杂性。

Flying_Fish_roe的博客 1388

线程池原理及改造

首先我们先了解一下线程池里面几个参数:第一个是核心线程数,第二个是线程池最大线程数。(线程池里面的线程分为核心线程和非核心线程,既然核心线程有3个,那么说明还可以创建最多2个非核心线程)第三个是最大空闲时间,第四个是时间单位为秒,第五个是阻塞队列(这个很重要),第六个是线程工厂,默认的,最后一个是拒绝策略。

m0_63624484的博客 1190

线程池 核心原理

线程池

一个想交朋友的陌生人 1558

Java 线程池核心原理

线程池是一种管理和复用线程的机制,它可以在需要执行任务时分配线程,执行完任务后将线程放回线程池中,以便重复利用。线程池可以有效地控制并发线程的数量,提高系统的性能和资源利用率。

qq_45607784的博客 1411

线程池的设计原理是什么?

导读 线程池相关的知识点是面试中非常高频的问题,掌握线程及线程池相关的知识点也是程序员向高段位进阶的必由之路。由于线程池涉及线程、并发、编程语言内存模型等多方面的知识,历来也不是一块特别好掌握的内容。因此,小码哥决定好好梳理下这方面的知识,希望能够对你有所帮助。在本文中,作者将以JAVA语言中的线程池设计为基础,从原理分析及代码实践两个方面来进行梳理。 线程的概念 在了解线程池的相关的知识之前,我...

无敌码农 1176

线程池原理_搞懂线程池原理 这篇足够了

线程池原理线程池做的工作主要是控制运行的线程的数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量超出数量的线程排队等候,等其它线程执行完毕,再从队列中取出任务来执行。他的主要特点为:线程复用;控制最大并发数;管理线程。1. 线程复用每一个 Thread 的类都有一个 start 方法。 当调用 start 启动线程时 Java 虚拟机会调用该类的 run方法。...

weixin_28945799的博客 105

Python 线程池原理及实现

概述 传统多线程方案会使用“即时创建, 即时销毁”的策略。尽管与创建进程相比,创建线程的时间已经大大的缩短,但是如果提交给线程的任务是执行时间较短,而且执行次数极其频繁,那么服务器将处于不停的创建线程,销毁线程的状态。 一个线程的运行时间可以分为3部分:线程的启动时间、线程体的运行时间和线程的销毁时间。在多线程处理的情景中,如果线程不能被重用,就意味着每次创建都需要经过启动、销毁和运行3个...

码农富哥 2万+

线程池 原理

线程池原理

红血哥 1141
上一篇: MySQL基础篇(三)锁
下一篇: 操作系统(一)硬件结构
皮皮杨233
博客等级 码龄7年 42粉丝 75原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值