线程池及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

相关文章

Springboot的ThreadPoolTaskScheduler线程池轻松搞定15分钟不操作自动取消订单

《Springboot的ThreadPoolTaskScheduler线程池轻松搞定15分钟不操作自动取消订单》:本文主要介绍Springboot的ThreadPoolTaskScheduler线... 目录ThreadPoolTaskScheduler线程池实现15分钟不操作自动取消订单概要1,创建订单后

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

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

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

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

MyBatis框架实现一个简单的数据查询操作

《MyBatis框架实现一个简单的数据查询操作》本文介绍了MyBatis框架下进行数据查询操作的详细步骤,括创建实体类、编写SQL标签、配置Mapper、开启驼峰命名映射以及执行SQL语句等,感兴趣的... 基于在前面几章我们已经学习了对MyBATis进行环境配置,并利用SqlSessionFactory核

cross-plateform 跨平台应用程序-03-如果只选择一个框架,应该选择哪一个?

跨平台系列 cross-plateform 跨平台应用程序-01-概览 cross-plateform 跨平台应用程序-02-有哪些主流技术栈? cross-plateform 跨平台应用程序-03-如果只选择一个框架,应该选择哪一个? cross-plateform 跨平台应用程序-04-React Native 介绍 cross-plateform 跨平台应用程序-05-Flutte

Spring框架5 - 容器的扩展功能 (ApplicationContext)

private static ApplicationContext applicationContext;static {applicationContext = new ClassPathXmlApplicationContext("bean.xml");} BeanFactory的功能扩展类ApplicationContext进行深度的分析。ApplicationConext与 BeanF

数据治理框架-ISO数据治理标准

引言 "数据治理"并不是一个新的概念,国内外有很多组织专注于数据治理理论和实践的研究。目前国际上,主要的数据治理框架有ISO数据治理标准、GDI数据治理框架、DAMA数据治理管理框架等。 ISO数据治理标准 改标准阐述了数据治理的标准、基本原则和数据治理模型,是一套完整的数据治理方法论。 ISO/IEC 38505标准的数据治理方法论的核心内容如下: 数据治理的目标:促进组织高效、合理地

ZooKeeper 中的 Curator 框架解析

Apache ZooKeeper 是一个为分布式应用提供一致性服务的软件。它提供了诸如配置管理、分布式同步、组服务等功能。在使用 ZooKeeper 时,Curator 是一个非常流行的客户端库,它简化了 ZooKeeper 的使用,提供了高级的抽象和丰富的工具。本文将详细介绍 Curator 框架,包括它的设计哲学、核心组件以及如何使用 Curator 来简化 ZooKeeper 的操作。 1

【Kubernetes】K8s 的安全框架和用户认证

K8s 的安全框架和用户认证 1.Kubernetes 的安全框架1.1 认证:Authentication1.2 鉴权:Authorization1.3 准入控制:Admission Control 2.Kubernetes 的用户认证2.1 Kubernetes 的用户认证方式2.2 配置 Kubernetes 集群使用密码认证 Kubernetes 作为一个分布式的虚拟

Spring Framework系统框架

序号表示的是学习顺序 IoC(控制反转)/DI(依赖注入): ioc:思想上是控制反转,spring提供了一个容器,称为IOC容器,用它来充当IOC思想中的外部。 我的理解就是spring把这些对象集中管理,放在容器中,这个容器就叫Ioc这些对象统称为Bean 用对象的时候不用new,直接外部提供(bean) 当外部的对象有关系的时候,IOC给它俩绑好(DI) DI和IO