线程池及Executor框架

2023-12-27 05:48
文章标签 线程 框架 executor 池及

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

为什么要使用线程池?

    诸如web服务器、数据库服务器、文件服务器或邮件服务之类的许多服务器应用程序都面向处理来自远程的大量短小的任务。请求以某种方式到达服务器,这种方式可以通过网络协议(HTTP、FTP)通过JMS队列或者可能通过轮询数据库。不管请求如何到达,服务器应用程序经常出现的情况是:单个任务处理的时间很短而请求的数目却巨大。如果每一个请求到达就创建一个新的线程,然后在新线程中处理请求,这样频繁的创建线程、销毁线程对系统的开销是非常大的。

    线程池为线程生命周期开销问题和资源不足问题提供了解决方案。通过对多个任务重用线程,线程创建的开销被分摊到多个任务上。优点是,1、在请求到达时线程已经存在,所以无意中消除了线程创建带来的时间延迟。这样就可以立即处理请求,减少应用的响应时间。2、通过适当的调整线程池中的线程数目,也就是当请求的数目超过某个阀值时,就强制其他任何新到的请求一直等待,直到获得一个线程来处理为止,从而可以防止资源不足。

风险与机遇

    用线程池构建应用程序容易遭受任何其他多线程应用程序容易遭受的并发风险,诸如同步错误和死锁,还容易遭受特定于线程池的少量风险,诸如与池有关的死锁、资源不足和线程泄漏。

Future与Callable、FutureTask

    Callable与Runnable功能相似,Callable的call有返回值,可以返回给客户端,而Runable没有返回值,一般情况下,Callable与FutureTask一起使用,或者通过线程池的submit方法返回相应的Future。

   Future就是对具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果、设置结果操作。get方法阻塞,直到任务返回结果。

  FutureTask则是一个RunnableFuture,而RunnableFuture实现了Runnable又实现了Future这两个接口。

线程池的核心组成部分及其运行机制

    corePoolSize:核心线程池大小 cSize

    maximumPoolSize:线程池最大容量 mSize

    keepAliveTime:当线程数量大于核心时,多余的空闲线程在终止之前等待新任务的最大时间。

    unit:时间单位

    workQueue:工作队列 nworks

    ThreadFactory:线程工厂

    handler:拒绝策略

运行机制

    通过new创建线程池时,除非调用prestartAllCoreThread方法初始化核心线程,否则此时线程池中有0个线程,即时工作队列中存在多个任务,同样不会执行。

    任务数X

    x<=cSize 只启动x个线程

    x>=cSize && x<nWork +cSize  会启动<=cSize 个线程 其他任务就放在工作队列里

   当  x > cSize && x > nWork+cSize 时

        x-(nworks) <= mSize 会启动x-(nworks) 个线程

        x-(nworks) > mSize 会启动mSize个线程来执行任务,其余的执行相应的拒绝策略    

线程池拒绝策略

   AbortPolicy:该策略直接抛出异常,阻止系统正常工作。

   CallerRunsPolicy:只要线程没有关闭,该策略直接在调用线程执行当前被丢弃的任务。

   DiscardPolicy:什么事都不做,直接把任务丢弃。

   DiscardOldestPolicy:丢弃最老的一个请求(任务队列里面的第一个)

 

import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class ThreadPoolExecutorDemo {public static void main(String[] args) {LinkedBlockingQueue<Runnable> linkedBlockingQueue = new LinkedBlockingQueue<>(20);ThreadPoolExecutor threadPoolExecutor  = new ThreadPoolExecutor(10,20,3L, TimeUnit.SECONDS,linkedBlockingQueue);Future<?> future = null;for (int i = 0;i<40;i++){threadPoolExecutor.submit(()->{try {Thread.sleep(2000L);}catch (InterruptedException e){e.printStackTrace();}});System.out.println(threadPoolExecutor.getActiveCount());}threadPoolExecutor.prestartAllCoreThreads();}
}

运行结果

通过修改代码中的初始化参数可以验证上面的理论。

Executor框架

   通过相应的方法,能创建出6种线程池。

ExecutorService executorService = Executors.newCachedThreadPool();

ExecutorService fixedThreadPool = Executors.newFixedThreadPool(2);

ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(2);

ExecutorService workStealingPool = Executors.newWorkStealingPool();

ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();

ScheduledExecutorService singleThreadScheduledExecutor = Executors.newSingleThreadScheduledExecutor();

newCachedThreadPool:创建一个可以根据需要 创建新线程的线程池,如有空闲线程,优先使用空闲的线程。

newFixedThreadPool:创建一个固定大小的线程池,在任何时候,最多只有N个线程在处理任务

newScheduledThreadPool:能延迟执行、定时执行的线程池。

newWorkStealingPool:工作窃取,使用多个队列来减少竞争。

newSingleThreadExecutor:单一线程的线程池,只是用唯一一个线程来执行任务,即时提交再多的任务,也都是会放在等待队列。

线程池的使用建议

   尽量避免使用Executor框架创建线程池

      newFixedThreadPool newSingleThreadExecutor 

      允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM

      newCachedThreadPool newScheduledThreadPool

      允许的创建线程数量为 Integer.MAX_VALUE,可能就会创建大量的线程,从而导致OOM

      为什么第二个例子,在限定的堆的内存之后,还会把整个电脑的内存撑爆

            创建线程池时,核心线程数不要过大

            相应的逻辑,发现异常时要时常处理

            submit 如果发生异常,不会立即抛出,而是在get的时候,再抛异常。

            execute 直接抛出异常。

 

 

 

 

 

 

 

 

 

 

这篇关于线程池及Executor框架的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

JAVA保证HashMap线程安全的几种方式

《JAVA保证HashMap线程安全的几种方式》HashMap是线程不安全的,这意味着如果多个线程并发地访问和修改同一个HashMap实例,可能会导致数据不一致和其他线程安全问题,本文主要介绍了JAV... 目录1. 使用 Collections.synchronizedMap2. 使用 Concurren

Spring Boot3虚拟线程的使用步骤详解

《SpringBoot3虚拟线程的使用步骤详解》虚拟线程是Java19中引入的一个新特性,旨在通过简化线程管理来提升应用程序的并发性能,:本文主要介绍SpringBoot3虚拟线程的使用步骤,... 目录问题根源分析解决方案验证验证实验实验1:未启用keep-alive实验2:启用keep-alive扩展建

Python Dash框架在数据可视化仪表板中的应用与实践记录

《PythonDash框架在数据可视化仪表板中的应用与实践记录》Python的PlotlyDash库提供了一种简便且强大的方式来构建和展示互动式数据仪表板,本篇文章将深入探讨如何使用Dash设计一... 目录python Dash框架在数据可视化仪表板中的应用与实践1. 什么是Plotly Dash?1.1

基于Flask框架添加多个AI模型的API并进行交互

《基于Flask框架添加多个AI模型的API并进行交互》:本文主要介绍如何基于Flask框架开发AI模型API管理系统,允许用户添加、删除不同AI模型的API密钥,感兴趣的可以了解下... 目录1. 概述2. 后端代码说明2.1 依赖库导入2.2 应用初始化2.3 API 存储字典2.4 路由函数2.5 应

Python GUI框架中的PyQt详解

《PythonGUI框架中的PyQt详解》PyQt是Python语言中最强大且广泛应用的GUI框架之一,基于Qt库的Python绑定实现,本文将深入解析PyQt的核心模块,并通过代码示例展示其应用场... 目录一、PyQt核心模块概览二、核心模块详解与示例1. QtCore - 核心基础模块2. QtWid

Java终止正在运行的线程的三种方法

《Java终止正在运行的线程的三种方法》停止一个线程意味着在任务处理完任务之前停掉正在做的操作,也就是放弃当前的操作,停止一个线程可以用Thread.stop()方法,但最好不要用它,本文给大家介绍了... 目录前言1. 停止不了的线程2. 判断线程是否停止状态3. 能停止的线程–异常法4. 在沉睡中停止5

最新Spring Security实战教程之Spring Security安全框架指南

《最新SpringSecurity实战教程之SpringSecurity安全框架指南》SpringSecurity是Spring生态系统中的核心组件,提供认证、授权和防护机制,以保护应用免受各种安... 目录前言什么是Spring Security?同类框架对比Spring Security典型应用场景传统

Java捕获ThreadPoolExecutor内部线程异常的四种方法

《Java捕获ThreadPoolExecutor内部线程异常的四种方法》这篇文章主要为大家详细介绍了Java捕获ThreadPoolExecutor内部线程异常的四种方法,文中的示例代码讲解详细,感... 目录方案 1方案 2方案 3方案 4结论方案 1使用 execute + try-catch 记录

Python结合Flask框架构建一个简易的远程控制系统

《Python结合Flask框架构建一个简易的远程控制系统》这篇文章主要为大家详细介绍了如何使用Python与Flask框架构建一个简易的远程控制系统,能够远程执行操作命令(如关机、重启、锁屏等),还... 目录1.概述2.功能使用系统命令执行实时屏幕监控3. BUG修复过程1. Authorization

SpringBoot集成图片验证码框架easy-captcha的详细过程

《SpringBoot集成图片验证码框架easy-captcha的详细过程》本文介绍了如何将Easy-Captcha框架集成到SpringBoot项目中,实现图片验证码功能,Easy-Captcha是... 目录SpringBoot集成图片验证码框架easy-captcha一、引言二、依赖三、代码1. Ea