线程池核心九问

2023-11-03 03:10
文章标签 线程 核心 九问

本文主要是介绍线程池核心九问,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.什么是线程池?

线程池就是提前创建若干个线程,
如果有任务需要处理,线程池里的线程就会处理任务,处理完之后线程并不会被销毁,而是等待下一个任务。减少频繁创建和销毁线程消耗系统资源。

2.为什么要用线程池 ?

频繁创建、销毁 线程,将是对系统资源的极大浪费。
因此,实际开发中我们将使用线程池来管理、复用线程。
使用线程池,可以
1.降低资源消耗: 重复利用线程,减少创建和销毁造成的消耗。
2.提升响应速度: 任务到达,不需要创建,立即执行。
3.提高可管理型: 线程是CPU调度和分派的基本单位,
如果无限制地创建,不仅会消耗系统资源,还会降低系统稳定性。
使用线程池可以统一进行 分配、调优和监控。

3.创建线程池的方式?

Java从1.5 Executors 类提供四种创建线程池方式
1).newSingleThreadExecutor()

  • 单个线程的线程池,即线程池中每次只有一个线程工作,单线程串行执行任务,(队列长度-Integer.MAX_VALUE)

2).newFixedThreadPool(maximumPoolSize)

  • **定最大线程数,线程池 **,核心线程数=最大线程数=设置的线程数,可控制线程最大并发数,(队列长度-Integer.MAX_VALUE);

3).newCachedThreadPool()

  • 可缓存线程池,有任务才新建线程,闲置线程保存60秒 ,(最大线程数长度-Integer.MAX_VALUE)

4).newScheduledThreadPool(corePoolSize)

  • 定核心线程数,线程池,支持定时及周期性任务执行。(最大线程数长度-Integer.MAX_VALUE)
    在这里插入图片描述

在这里插入图片描述

4.为什么不建议使用 Executors静态工厂构建线程池

主要原因:队列堆积,有OOM风险
1.FixedThreadPool 和 SingleThreadPool
允许的请求队列(底层实现是LinkedBlockingQueue)长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM

2.CachedThreadPool 和 ScheduledThreadPool
允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM。

5.线程池参数

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

corePoolSize:核心线程数量,一直存在,除非 allowCoreThreadTimeOut设置为true
maximumPoolSize:线程池允许的最大线程池数量 10
keepAliveTime:线程数量超过corePoolSize,空闲线程的最大超时时间
unit:超时时间的单位
workQueue:工作队列,保存未执行的Runnable 任务 (BlockingQueue 的实现类)
threadFactory:创建线程的工厂类
handler:当线程已满,工作队列也满了的时候,会被调用。被用来实现各种拒绝策略。

工作队列介绍
在这里插入图片描述

6.线程池的执行顺序

在这里插入图片描述

当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运
行的线程数大于 corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它
最终会收缩到 corePoolSize 的大小。

7.四种策略**

  • ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常
  • ThreadPoolExecutor.DiscardPolicy:丢弃任务,但是不抛出异常。
  • ThreadPoolExecutor.DiscardOldestPolicy:**丢弃队列最老的任务,然后重新提交被拒绝的任务 **
  • ThreadPoolExecutor.CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务

8.实现原理

线程池由两个核心数据结构组成:
1)线程集合(workers):存放执行任务的线程,是一个HashSet;
2)任务等待队列(workQueue):存放等待线程池调度执行的任务,是一个阻塞式队列BlockingQueue;

8.如何合理设置线程池大小

任务一般可分为:CPU密集型、IO密集型、混合型,对于不同类型的任务需要分配不同大小的线程池。

  • CPU密集型任务: 尽量使用较小的线程池,一般为CPU核心数+1 ; (+1是利用等待空闲)
    • 因为CPU密集型任务使得CPU使用率很高,若开过多的线程数,只能增加上下文切换的次数,因此会带来额外的开销。
  • IO密集型任务: 一般为2*CPU核心数。
    • IO密集型任务CPU使用率并不高,因此可以让CPU在等待IO的时候去处理别的任务,充分利用CPU时间。
  • 混合型任务
    • 可以将任务分成IO密集型和CPU密集型任务,然后分别用不同的线程池去处理。

线程等待时间所占比例越高,需要越多线程。线程CPU时间所占比例越高,需要越少线程。
最佳线程数目 = (线程等待时间与线程CPU时间之比 + 1)* CPU数目

//java 中获取核心数 int availableProcessors = Runtime.getRuntime().availableProcessors();

9.线程池的动态规划参数动态化

JDK原生线程池ThreadPoolExecutor提供了如下几个public的setter方法,如下图所示:
在这里插入图片描述

JDK允许线程池使用方通过ThreadPoolExecutor的实例来动态设置线程池的核心策略,
以setCorePoolSize为方法例,
在运行期线程池使用方调用此方法设置corePoolSize之后,
线程池会直接覆盖原来的corePoolSize值,并且基于当前值和原始值的比较结果采取不同的处理策略。
对于当前值小于当前工作线程数的情况,说明有多余的worker线程,
此时会向当前空闲的worker线程发起中断请求以实现回收,
多余的worker在下次空闲的时候也会被回收;
对于当前值大于原始值且当前队列中有待执行任务,
则线程池会创建新的worker线程来执行队列任务,setCorePoolSize具体流程如下:
在这里插入图片描述

这篇关于线程池核心九问的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/335174

相关文章

C语言线程池的常见实现方式详解

《C语言线程池的常见实现方式详解》本文介绍了如何使用C语言实现一个基本的线程池,线程池的实现包括工作线程、任务队列、任务调度、线程池的初始化、任务添加、销毁等步骤,感兴趣的朋友跟随小编一起看看吧... 目录1. 线程池的基本结构2. 线程池的实现步骤3. 线程池的核心数据结构4. 线程池的详细实现4.1 初

Java子线程无法获取Attributes的解决方法(最新推荐)

《Java子线程无法获取Attributes的解决方法(最新推荐)》在Java多线程编程中,子线程无法直接获取主线程设置的Attributes是一个常见问题,本文探讨了这一问题的原因,并提供了两种解决... 目录一、问题原因二、解决方案1. 直接传递数据2. 使用ThreadLocal(适用于线程独立数据)

Andrej Karpathy最新采访:认知核心模型10亿参数就够了,AI会打破教育不公的僵局

夕小瑶科技说 原创  作者 | 海野 AI圈子的红人,AI大神Andrej Karpathy,曾是OpenAI联合创始人之一,特斯拉AI总监。上一次的动态是官宣创办一家名为 Eureka Labs 的人工智能+教育公司 ,宣布将长期致力于AI原生教育。 近日,Andrej Karpathy接受了No Priors(投资博客)的采访,与硅谷知名投资人 Sara Guo 和 Elad G

PostgreSQL核心功能特性与使用领域及场景分析

PostgreSQL有什么优点? 开源和免费 PostgreSQL是一个开源的数据库管理系统,可以免费使用和修改。这降低了企业的成本,并为开发者提供了一个活跃的社区和丰富的资源。 高度兼容 PostgreSQL支持多种操作系统(如Linux、Windows、macOS等)和编程语言(如C、C++、Java、Python、Ruby等),并提供了多种接口(如JDBC、ODBC、ADO.NET等

线程的四种操作

所属专栏:Java学习        1. 线程的开启 start和run的区别: run:描述了线程要执行的任务,也可以称为线程的入口 start:调用系统函数,真正的在系统内核中创建线程(创建PCB,加入到链表中),此处的start会根据不同的系统,分别调用不同的api,创建好之后的线程,再单独去执行run(所以说,start的本质是调用系统api,系统的api

java线程深度解析(六)——线程池技术

http://blog.csdn.net/Daybreak1209/article/details/51382604 一种最为简单的线程创建和回收的方法: [html]  view plain copy new Thread(new Runnable(){                @Override               public voi

java线程深度解析(五)——并发模型(生产者-消费者)

http://blog.csdn.net/Daybreak1209/article/details/51378055 三、生产者-消费者模式     在经典的多线程模式中,生产者-消费者为多线程间协作提供了良好的解决方案。基本原理是两类线程,即若干个生产者和若干个消费者,生产者负责提交用户请求任务(到内存缓冲区),消费者线程负责处理任务(从内存缓冲区中取任务进行处理),两类线程之

java线程深度解析(四)——并发模型(Master-Worker)

http://blog.csdn.net/daybreak1209/article/details/51372929 二、Master-worker ——分而治之      Master-worker常用的并行模式之一,核心思想是由两个进程协作工作,master负责接收和分配任务,worker负责处理任务,并把处理结果返回给Master进程,由Master进行汇总,返回给客

java线程深度解析(二)——线程互斥技术与线程间通信

http://blog.csdn.net/daybreak1209/article/details/51307679      在java多线程——线程同步问题中,对于多线程下程序启动时出现的线程安全问题的背景和初步解决方案已经有了详细的介绍。本文将再度深入解析对线程代码块和方法的同步控制和多线程间通信的实例。 一、再现多线程下安全问题 先看开启两条线程,分别按序打印字符串的

java线程深度解析(一)——java new 接口?匿名内部类给你答案

http://blog.csdn.net/daybreak1209/article/details/51305477 一、内部类 1、内部类初识 一般,一个类里主要包含类的方法和属性,但在Java中还提出在类中继续定义类(内部类)的概念。 内部类的定义:类的内部定义类 先来看一个实例 [html]  view plain copy pu