线程池介绍

目录

  • 线程池
    • 作用和目的
    • Executor框架
    • 线程池的创建
      • 1. 手动创建
      • 2. 使用Executors工厂类方法创建
    • 任务提交
    • 线程池执行流程
    • 线程池的关闭
    • ScheduledThreadPoolExecutor介绍

线程池

介绍了为什么要使用线程和线程池:JAVA中线程池的定义及使用
Java线程池ExecutorService
有介绍Future接口、ScheduledExecutorService接口:秒懂 Java ExecutorService

作用和目的

为什么要使用线程池技术?

  1. 降低系统资源消耗, 通过重用已存在的线程, 降低线程创建和销毁造成的消耗;
  2. 提高系统响应速度, 当有任务到达时, 无需等待新线程的创建便能立即执行;
    方便线程并发数的管控, 线程若是无限制的创建, 不仅会额外消耗大量系统资
    源, 更是占用过多资源而阻塞系统或oom等状况, 从而降低系统的稳定性。 线程池
  3. 能有效管控线程, 统一分配、 调优, 提供资源使用率;
  4. 更强大的功能, 线程池提供了定时、 定期以及可控线程数等功能的线程池, 使用
    方便简单

Executor框架

框架简介,接口和类间继承关系图

线程池的创建

1. 手动创建

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

ThreadPoolExecutors()参数含义:

  1. corePoolSize:核心线程数,一旦创建将不会再释放。如果创建的线程数还没有达到指定的核心线程数量,将会继续创建新的核心线程,直到达到最大核心线程数后,核心线程数将不在增加;如果没有空闲的核心线程,同时又未达到最大线程数,则将继续创建非核心线程;如果核心线程数等于最大线程数,则当核心线程都处于激活状态时,任务将被挂起,等待空闲线程来执行。默认情况下, 核心线程一直存活在线程池中, 即便他们在线程池中处于闲置状态。 除非我们将ThreadPoolExecutor的allowCoreThreadTimeOut属性设为true的时候, 这时候处于闲置的核心线程在等待新任务到来时会有超时策略, 这个超时时间由keepAliveTime来指定。 一旦超过所设置的超时时间, 闲置的核心线程就会被终止。

  2. maximumPoolSize:最大线程数,允许创建的最大线程数量。如果最大线程数等于核心线程数,则无法创建非核心线程;如果非核心线程处于空闲时,超过设置的空闲时间,则将被回收,释放占用的资源。
    keepAliveTime: 也就是当线程空闲时,所允许保存的最大时间,超过这个时间,线程将被释放销毁,但只针对于非核心线程。
    TimeUnit:时间单位,用于指定keepAliveTime的时间单位。

  3. workQueue:等待队列,用于存储等待处理的任务。线程池提供了多种类型的等待队列,例如ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue等。
    通过线程池中的execute方法提交的Runable对象都会存储在该队列中。

  • ArrayBlockingQueue 基于数组实现的有界的阻塞队列,该队列按照FIFO( 先进先出) 原则对队列中的元素进行排序。
  • LinkedBlockingQueue 基于链表实现的有界的阻塞队列,该队列按照FIFO( 先进先出) 原则对队列中的元素进行排序。
  • SynchronousQueue 内部没有任何容量的阻塞队列。 在它内部没有任何的缓存空间。 对于SynchronousQueue中的数据元素只有当我们试着取走的时候才可能存在。
  • PriorityBlockingQueue 具有优先级的无限阻塞队列。
  1. threadFactory: 线程工厂, 为线程池提供新线程的创建。 ThreadFactory是一个接口, 里面只有一个newThread方法。 默认为DefaultThreadFactory类。

  2. handler:拒绝策略,用于处理无法处理的任务。线程池提供了多种类型的拒绝策略,例如AbortPolicy、CallerRunsPolicy、DiscardOldestPolicy、DiscardPolicy等。是RejectedExecutionHandler对象, 而RejectedExecutionHandler是一个接口, 里面只有一个rejectedExecution方法,当任务队列已满并且线程池中的活动线程已经达到所限定的最大值或者是无法成功执行任务, 这时候ThreadPoolExecutor会调用RejectedExecutionHandler中的rejectedExecution方法。在ThreadPoolExecutor中有四个内部类实现了rejectedExecutionHandler接口。 在线程池中它默认是AbortPolicy, 在无法处理新任务时抛出RejectedExecutionException异常。

  • CallerRunsPolicy 直接用调用者所在线程来运行任务。
  • AbortPolicy 直接抛出RejectedExecutionException异常。
  • DiscardPolicy 丢弃掉该任务,不进行处理。
  • DiscardOldestPolicy 丢弃队列里最近的一个任务,并执行当前任务。
    我们也可以通过实现RejectedExecutionHandler接口来自定义我们自己的handler。如记录日志或持久化不能处理的任务。

2. 使用Executors工厂类方法创建

Executors只是一个工厂类,它所有的方法返回的都是ThreadPoolExecutor、ScheduledThreadPoolExecutor这两个类的实例

  1. Executors.newCachedThreadPool():
public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。线程的空闲等待时间是60s,超过此时间将会被回收。
对于newCachedThreadPool他的任务队列采用的是SynchronousQueue, 上面说到在SynchronousQueue内部没有任何容量的阻塞队列。 SynchronousQueue内部相当于一个空集合, 我们无法将一个任务插入到SynchronousQueue中。 所以说在线程池中如果现有线程无法接收任务,将会创建新的线程来执行任务。

  1. Executors.newFixedThreadPool:
public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

  1. Executors.newScheduledThreadPool:
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }

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

创建一个定长线程池,支持定时及周期性任务执行。它的核心线程数是固定的, 对于非核心线程几乎可以说是没有限制的, 并且当非核心线程处于限制状态的时候就会立即被回收。

  1. Executors.newSingleThreadExecutor:
public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

任务提交

  1. execute(Runnable)方法:没有办法获知task的执行结果。

  2. submit(Runnable)方法:submit(Runnable)和execute(Runnable)区别是前者可以返回一个Future对象,通过返回的Future对象,我们可以检查提交的任务是否执行完毕。当执行完毕时,通过返回的future.get()方法可以获得一个null,没执行完毕时会阻塞get()方法。

  3. submit(Callable)方法:submit(Callable)和submit(Runnable)类似,也会返回一个Future对象,但是除此之外,submit(Callable)接收的是一个Callable的实现,Callable接口中的call()方法有一个返回值,可以返回任务的执行结果。

  4. T result = invokeAny(Collection<? extents Callable>)方法:

public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
        throws InterruptedException, ExecutionException {
        try {
            return doInvokeAny(tasks, false, 0);
        } catch (TimeoutException cannotHappen) {
            assert false;
            return null;
        }
    }

invokeAny(…)方法接收的是一个Callable的集合,执行这个方法不会返回Future,但是会返回所有Callable任务中其中一个任务的执行结果。这个方法也无法保证返回的是哪个任务的执行结果,反正是其中的某一个。

  1. List<Future> = invokeAll(Collection<? extents Callable>)方法:
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
        throws InterruptedException {
    }

invokeAll(…)与 invokeAny(…)类似也是接收一个Callable集合,但是前者执行之后会返回一个Future的List,其中对应着每个Callable任务执行后的Future对象。

线程池执行流程

  1. 如果在线程池中的线程数量没有达到核心的线程数量, 这时候就回启动一个核心线程来执行任务。
  2. 如果线程池中的线程数量已经超过核心线程数, 这时候任务就会被插入到任务队列中排队等待执行。
  3. 由于任务队列已满, 无法将任务插入到任务队列中。 这个时候如果线程池中的线程数量没有达到线程池所设定的最大值, 那么这时候就会立即启动一个非核心线程来执行任务。
  4. 如果线程池中的数量达到了所规定的最大值, 那么就会拒绝执行此任务, 这时候就会调用RejectedExecutionHandler中的rejectedExecution方法来通知调用者。
    注意:当核心线程任务满时,新来的任务先采用任务队列缓存,当任务队列满时才会新建非核心线程。

线程池的关闭

为什么需要关闭线程池?
如果的应用程序是通过main()方法启动的,在这个main()退出之后,如果应用程序中的ExecutorService没有关闭,这个应用将一直运行。之所以会出现这种情况,是因为ExecutorService中运行的线程会阻止JVM关闭。

  1. public void shutdown()方法
    在调用shutdown()方法之后,将线程池状态设置成SHUTDOWN状态,然后中断所有没有正在执行任务的线程。
    在调用shutdown()方法之后,ExecutorService不会立即关闭,但是它不再接收新的任务,直到当前所有线程执行完成才会关闭,所有在shutdown()执行之前提交的任务都会被执行。

  2. public List shutdownNow()方法
    将线程池的状态设置成STOP状态,然后中断所有任务(包括正在执行的)的线程,并返回等待执行任务的列表。
    这个动作将跳过所有正在执行的任务和被提交还没有执行的任务。但是它并不对正在执行的任务做任何保证,有可能它们都会停止,也有可能执行完成。
    shutdownNow() 方法会尝试立即销毁 ExecutorService 实例,所以并不能保证所有正在运行的线程将同时停止。
    该方法会返回等待处理的任务列表,由开发人员自行决定如何处理这些任务。

因为提供了两个方法,因此关闭 ExecutorService 实例的最佳实战 ( 也是 Oracle 所推荐的 )就是同时使用这两种方法并结合 awaitTermination() 方法。
使用这种方式,ExecutorService 首先停止执行新任务,等待指定的时间段完成所有任务。如果该时间到期,则立即停止执行。

executorService.shutdown();
try {
    if (!executorService.awaitTermination(800, TimeUnit.MILLISECONDS)) {
        executorService.shutdownNow();
    } 
} catch (InterruptedException e) {
    executorService.shutdownNow();
}

ScheduledThreadPoolExecutor介绍

用于执行定时性、或者周期性的任务

  1. 定时执行Runnable接口
public ScheduledFuture<?> schedule(Runnable command,
                                       long delay,
                                       TimeUnit unit){}

在固定延迟后安排单个任务的执行,返回的Future对象可以用作判断任务是否执行完成。

  1. 定时执行Callable接口
public <V> ScheduledFuture<V> schedule(Callable<V> callable,
                                           long delay,
                                           TimeUnit unit) {}

在固定延迟后安排单个任务的执行,返回的Future对象可以用作判断任务是否执行完成和获取任务执行的结果。

  1. 执行周期性任务接口
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                                  long initialDelay, // 任务将在初始延迟之后第一次执行
                                                  long period, // 线程池将在第一次执行任务后每隔此时间执行一次相同的任务
                                                  TimeUnit unit) {}

public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                                     long initialDelay, // 任务将在初始延迟之后第一次执行
                                                     long delay, // 保证任务迭代之间必须具有固定长度的延迟
                                                     TimeUnit unit) {}

scheduleWithFixedDelay()与scheduleAtFixedRate()方法很类似, 但是不同的是scheduleWithFixedDelay()方法的周期时间间隔是以上一个任务执行结束到下一个
任务开始执行的间隔, 而scheduleAtFixedRate()方法的周期时间间隔是以上一个任务开始执行到下一个任务开始执行的间隔, 也就是这一些任务系列的触发时间都是
可预知的。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

k8s概述及核心组件

一、k8s概述 1.1 引言 docker compose 单机编排工具 有企业在用 docker swarm 能够在多台主机中构建一个docker集群 基本淘汰集群化管理处理工具 容器 微服务封装 dockerfile 编写成镜像 然后进行发布 dockerfile 可以写成shell脚本&#xff08;函数做调…

【Linux网络编程】HTTPS协议

【Linux网络编程】HTTPS协议 目录 【Linux网络编程】HTTPS协议HTTPS介绍加密常见的加密方式HTTPS的工作过程探究&#xff08;重点&#xff09;常见问题完整流程总结 作者&#xff1a;爱写代码的刚子 时间&#xff1a;2024.5.9 前言&#xff1a;本篇博客将会介绍HTTPS协议 HTTPS…

【记录】常见的前端设计系统(Design System)

解释一下设计系统的定义&#xff0c;以及在国内&#xff0c;都有那些优秀的设计系统可以学习&#xff0c;希望可以帮到大家。 什么是设计系统&#xff08;Design System)&#xff1f; 设计系统&#xff08;Design System&#xff09;是一套综合性的指导原则、组件和规则&…

VBA技术资料MF152:列出工作表中所有单元格的注释

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…

Linux进程——Linux环境变量

前言&#xff1a;在结束完上一篇的命令行参数时&#xff0c;我们简单的了解了一下Linux中的环境变量PATH&#xff0c;而环境变量不只有PATH&#xff0c;关于更多环境变量的知识我们将在本篇展开&#xff01; 本篇主要内容&#xff1a; 常见的环境变量 获取环境变量的三种方式 本…

GORM数据库连接池对接Prometheus

一、背景与介绍 Golang的database/sql包定了关于操作数据库的相关接口&#xff0c;但是没有去做对应数据库的实现。这些实现是预留给开发者或者对应厂商进行实现的。 其中让我比较关注的是Golang的sql包有没有实现连接池pool的机制呢? 毕竟Golang是静态语言&#xff0c;类似J…

pwn(一)前置技能

以下是pwn中的题目&#xff08;漏洞&#xff09;类型&#xff1a; 关于pwn的学习&#xff1a; 一.什么是pwn&#xff1f;&#xff08;二进制的漏洞&#xff09; "Pwn"是一个俚语&#xff0c;起源于电子游戏社区&#xff0c;经常在英语中用作网络或电子游戏文化中的…

AI中转站计费平台系统源码一站式解决方案安装说明

AI中转站计费平台系统源码一站式解决方案安装说明 功能 | Features AI 联网功能 AI online searching service 多账户均衡负载 Multi-account load balancing HTTP2 Stream 实时响应功能 HTTP2 Stream real-time response function 节流和鉴权体系 Throttling and authenticati…

GitHub中Asterank源码python修改成C++(本人python不太会)

GitHub - typpo/asterank: asteroid database, interactive visualizations, and discovery tools 主要目的是在进行多元线性回归的时候将枚举型转换为数值型 python: # # The constants used in calculations for the values of asteroids. ## General constants GENERAL_I…

基于Detectron2的计算机视觉实践

书籍&#xff1a;Hands-On Computer Vision with Detectron2: Develop object detection and segmentation models with a code and visualization approach 作者&#xff1a;Van Vung Pham&#xff0c;Tommy Dang 出版&#xff1a;Packt Publishing 书籍下载-《基于Detectr…

.OpenNJet应用引擎实践——从 0-1 体验感受

目录 一. &#x1f981; 写在前面二. &#x1f981; 安装使用2.1 安装环境2.2 配置yum源2.3 安装软件包2.4 编译代码2.5 启动 三. &#x1f981; 使用效果3.1 编辑配置文件3.2 编辑 HTML 代码 四. &#x1f981; 使用感受 一. &#x1f981; 写在前面 现在互联网体系越来越往云…

小丑的身份证和复印件 (BFS + Floyd)

本题链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 题目&#xff1a; 样例&#xff1a; 输入 2 10 (JOKERjoke #####asdr) 输出 12 思路&#xff1a; 根据题意&#xff0c;要求最短时间&#xff0c;实际上也可以理解为最短距离。 所以应该联想到有关最短距离的算法&…

css z-Index 详解--子元素盖在父元素的兄弟元素上

前置知识 1、z-index 只有在定位元素上才会生效&#xff08;即非static定位的元素上&#xff09; 2、同级元素&#xff0c;无论是z-index 相同还是没设置。后面的元素层级比前面 3、元素上有 transform 属性 z-index 会失效 dom结构如下 // dom部分 <div><div id&quo…

latex algorithm2e 库学习总结

案例1 \documentclass{article}\usepackage{xeCJK} \usepackage[]{algorithm2e} %\usepackage{ctex} % 中文包\begin{document}\renewcommand{\algorithmcfname}{算法} % 把标题设置为“算法” \begin{algorithm…

html table thead打印时带重复表头不生效

今天做一个打印功能时要求每页都带相同的表头&#xff0c;使用的方式是table的thead标签来实现&#xff0c;结果发现thead里边的内容放多了之后只有第一页才会有表头。最后发现问题是 thead的内容不能超过table的25%。

实例分割——Mask R-CNN、YOLOV8、RTMDET、DeepLab四种实例分割算法比对

1.概述 1.1 语义分割与实例分割 实例分割和语义分割都是计算机视觉领域中图像分割的任务&#xff0c;它们在目标和方法上有一些区别&#xff1a; 语义分割&#xff1a; 语义分割的目标是对图像中的每个像素打上类别标签&#xff0c;即识别出图像中每个像素属于哪个预定义的…

云动态摘要 2024-05-09

给您带来云厂商的最新动态&#xff0c;最新产品资讯和最新优惠更新。 最新优惠与活动 [免费试用]即刻畅享自研SaaS产品 腾讯云 2024-04-25 涵盖办公协同、营销拓客、上云安全保障、数据分析处理等多场景 云服务器ECS试用产品续用 阿里云 2024-04-14 云服务器ECS试用产品续用…

YOLOv5,YOLOv7改进之结合​SOCA

1.SOCA moudle结构图 2,YOLOv5,YOLOv7改进之结合​SOCA 1.配置common.py文件 #SOCA moudle 单幅图像超分辨率 class Covpool(Function):@staticmethoddef forward(ctx, input):x = inputbatchSize = x.data.shape[0]dim = x.data.shape[1]h = x.data.shape[2]w = x.data.sha…

PLC学习笔记

PLC学习笔记 前言一、一些基操知识二、GX works2编程2.1 位逻辑1.2 中间寄存器1.3 PLC的扫描方式 总结 前言 我这个人真的是太渴望知识了~ 一、一些基操知识 一般X表示输入&#xff0c;Y表示输出。一般八个为一组X0~X7M表示中间寄存器&#xff0c;M0~M7时间T、计数C 二、GX …

短信群发公司

伴随着移动互联网和智能手机的普及&#xff0c;短信群发成为了企业与个人之间高效沟通的一种重要方式。短信群发公司应运而生&#xff0c;致力于为用户提供专业、安全、高效的群发服务。 服务内容 短信群发公司提供多样化的服务内容&#xff0c;满足不同用户的需求。短信群发公…
最新文章