详解线程池的作用和实际应用以及拒绝策略

news/2024/11/7 23:50:19/

目录

线程池的作用?

线程池的意义:

线程池的参数

​编辑

 线程池任务执行的顺序

线程池拒绝策略

四种策略

 应用场景分析

AbortPolicy

DiscardPolicy

DiscardOldestPolicy

CallerRunsPolicy


线程池的作用?

优化系统架构通常包括在时间和空间之间进行权衡。对于线程池的创建,采用线程池预先创建并维护一定数量的线程,以空间换取时间的方式,可以有效减少每次任务执行时创建线程所带来的开销。

通过预先创建一定数量的线程并将其放入线程池中,可以避免在任务到来时动态创建线程的开销。相反,任务可以直接从线程池中获取可用的线程并执行,这样可以显著降低任务处理的延迟时间。这种池化思想利用了空间来存储预先创建的线程,以提高整体系统性能。

通过将线程池用作线程的缓存,可以避免重复创建和销毁线程的开销,提高系统的吞吐量和响应性能。此外,线程池还可以根据系统负载的变化动态调整线程的数量,以提供更好的性能和资源利用率。

因此,通过采用线程池来预先创建和维护线程的方式,可以在一定程度上优化系统架构,通过牺牲一部分空间,来换取更高的执行效率和响应能力。

线程池的意义:

  1. 降低资源的消耗:线程的创建和销毁需要消耗一定的计算机资源,包括内存和CPU时间。通过线程池,可以避免重复地创建和销毁线程,提高资源的利用率。

  2. 提高响应的速度:线程池中的线程已经预先创建并准备好执行任务。当任务到达时,可以直接分配一个可用的线程来处理,而不需要等待线程创建。这样可以大大降低任务的响应时间,提供更快的服务。

  3. 方便管理:线程池提供了对线程的统一管理和调度。通过线程池的接口,可以方便地控制线程的数量、设置线程的优先级、监测线程的执行状态等。此外,线程池中的线程通常有一个名称,方便在日志或调试信息中进行追踪和定位,从而方便排查问题和进行故障诊断。

线程池的参数

最小线程数:项目启动的时候,初始化的线程数 1

核心线程数:当线程池的线程都忙碌时,再进来新任务时,由最小线程数扩容到核心线程数 4

最大线程数 8:当核心线程数满了,当队列也满了,再来新任务,就会创建新线程来执行这个新任务,直到线程数达到最大线程数

队列大小 1000:当线程数达到核心线程数,再进来的任务就会进入到队列。

线程同一时刻只能做一件事,如下图需要等待上一步完成才能进行下一步

现在采用多线程,就可以同一时刻去进行多个任务,等最慢的线程结束就认为当前任务完成

 线程池任务执行的顺序

 最开始线程池中会有空线程在等待任务,当有任务出现就会安排线程去执行,如果没有空线程就会创建新的线程,当线程达到了核心线程数并且没有线程是空闲的 就开始往队列里面添加线程,如果队列中线程也达到饱和状态则继续创建新线程,直到线程数量达到最大线程数,开始进行拒绝策略

需要注意的是当任务队列已满且线程池的最大线程数尚未达到上限时,此时有新的线程出现,新线程将会被创建,并且会执行这个新的任务,而不是从队列中取出任务。

具体来说,当任务队列已满时,线程池会创建新的线程,并将新的任务分配给这个新线程来执行。这样可以避免将新任务放入已满的队列中,而是直接创建线程来处理新任务。

当线程池的核心线程数、任务队列容量和最大线程数都达到上限时,才会根据拒绝策略来处理新的任务

线程池拒绝策略

四种策略

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

线程池的默认拒绝策略为AbortPolicy,即丢弃任务并抛出RejectedExecutionException异常。

通过代码来验证这一点,现有如下代码:

public class ThreadPoolTest {public static void main(String[] args) {BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(60);ThreadFactory factory = r -> new Thread(r, "test-thread-pool");ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5,0L, TimeUnit.SECONDS, queue, factory);while (true) {executor.submit(() -> {try {System.out.println(queue.size());Thread.sleep(10000);} catch (InterruptedException e) {e.printStackTrace();}});}}
}

 设置了最大队列数为60,没有设置拒绝策略,运行代码则会抛出RejectedExecutionException异常

 应用场景分析

AbortPolicy

ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。

A handler for rejected tasks that throws a {@code RejectedExecutionException}.

这是线程池默认的拒绝策略,在任务不能再提交的时候,抛出异常,及时反馈程序运行状态。如果是比较关键的业务,推荐使用此拒绝策略,这样子在系统不能承载更大的并发量的时候,能够及时的通过异常发现。

DiscardPolicy

ThreadPoolExecutor.DiscardPolicy:丢弃任务,但是不抛出异常。如果线程队列已满,则后续提交的任务都会被丢弃,且是静默丢弃。

A handler for rejected tasks that silently discards therejected task.

使用此策略,可能会使我们无法发现系统的异常状态。建议是一些无关紧要的业务采用此策略。

DiscardOldestPolicy

ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新提交被拒绝的任务。

A handler for rejected tasks that discards the oldest unhandled request and then retries {@code execute}, unless the executor is shut down, in which case the task is discarded.

此拒绝策略,是一种喜新厌旧的拒绝策略。是否要采用此种拒绝策略,还得根据实际业务是否允许丢弃老任务来认真衡量。

CallerRunsPolicy

ThreadPoolExecutor.CallerRunsPolicy:由主线程处理该任务

A handler for rejected tasks that runs the rejected task directly in the calling thread of the {@code execute} method, unless the executor has been shut down, in which case the task is discarded.
import java.util.concurrent.*;public class Test {public static void main(String[] args) {BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(10);ThreadFactory factory = r -> new Thread(r, "test-thread-pool");ThreadPoolExecutor executor = new ThreadPoolExecutor(5,5,0,TimeUnit.MILLISECONDS,queue, factory,new ThreadPoolExecutor.CallerRunsPolicy());for (int i = 0; i < 1000; i++) {executor.submit(() -> {try {System.out.println(Thread.currentThread().getName() + ":执行任务");Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}});}}}

运行结果如下:

 前三种都适用于并发量高的业务,但是第四种适用于业务重要的场景,不能够丢失数据


http://www.ppmy.cn/news/654882.html

相关文章

WINRAR -- CRC校验失败,文件被破坏

下载了一个将近一G的软件&#xff0c;在解压时&#xff0c;提示“CRC校验失败,文件被破坏”&#xff0c;不至于再重新下载吧&#xff0c;需要好几个小时&#xff0c;这是用以下的办法通常可以不用理会rar的警告&#xff0c;把能解压的都解压出来。 办法一&#xff1a;WinRAR本…

CRC校验 java modbus

/*** crc16 X16x15x21* 16进制报文是 02 03 00 00 00 40 CRC16* 传输的str&#xff1a;“020300000040”* 结果&#xff1a;4409* param str* return*/public static String getCRC(String str) {byte[] bytes ByteUtil.hexStr2bytes(str);int CRC 0x0000ffff;int POLYNOMIAL…

【科普】CRC校验(一)什么是CRC校验?

目录 CRC&#xff08;循环冗余校验&#xff09; CRC 校验码的生成 CRC 的发送方与接收方 发送方 接收方 除法异或运算示意图 CRC&#xff08;循环冗余校验&#xff09; CRC&#xff08;Cyclic Redundancy Check&#xff09;循环冗余检验&#xff0c;是一种用于检测数字数…

十六、基于FPGA的CRC校验设计实现

1&#xff0c;CRC校验 循环冗余校验&#xff08;Cyclic Redundancy Check&#xff0c; CRC&#xff09;是一种根据网络数据包或计算机文件等数据产生简短固定位数校验码的一种信道编码技术&#xff0c;主要用来检测或校验数据传输或者保存后可能出现的错误。它是利用除法及余数…

CRC校验的解读

一、基础知识 1、CRC简介&#xff1a; CRC即循环冗余校验码&#xff08;Cyclic Redundancy Check&#xff09;&#xff1a;是数据通信领域中最常用的一种查错校验码&#xff0c;其特征是信息字段和校验字段的长度可以任意选定。循环冗余检查&#xff08;CRC&#xff09;是一种数…

ctf 文件头crc错误_[CTF隐写]png中CRC检验错误的分析

[CTF隐写]png中CRC检验错误的分析 最近接连碰到了3道关于png中CRC检验错误的隐写题&#xff0c;查阅了相关资料后学到了不少姿势&#xff0c;在这里做一个总结 题目来源&#xff1a; bugku-MISC-隐写2 bugku-MISC-再来一道隐写 JarvisOJ-MISC-炫酷的战队logo 基础知识&#xff…

CRC校验学习总结

1、CRC校验简介&#xff1a; CRC校验又称为循环冗余校验&#xff0c;是数据通信领域中最常用的一种查错校验码&#xff0c;其特征是信息字段和校验字段的长度可以任意选定。循环冗余检查&#xff08;CRC&#xff09;是一种数据传输检错功能&#xff0c;对数据进行多项式计算&a…

CRC校验原理

原文地址&#xff1a;https://blog.csdn.net/wenqiang1208/article/details/71641414 为什么引入CRC 现实的通信链路都不会是理想的。这就是说&#xff0c;比特在传输的过程中可能会产生差错&#xff1a;1可能会变成0&#xff0c;0可能会变成1&#xff0c;这就叫做比特差错。在…