栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

ThreadPoolExecutor线程池

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

ThreadPoolExecutor线程池

1、为什么要用线程池:

在web开发中,服务器需要接受并处理请求,所以会为一个请求来分配一个线程来进行处理。如果每次请求都新创建一个线程的话实现起来非常简便,但是存在一个问题:如果并发的请求数量非常多,但每个线程执行的时间很短,这样就会频繁的创建和销毁线程,如此一来会大大降低系统的效率。可能出现服务器在为每个请求创建新线程和销毁线程上花费的时间和消耗的系统资源要比处理实际的用户请求的时间和资源更多。

2、线程池的七个参数

线程池类图

七个参数

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) 

任务提交
1、public void execute() //提交任务无返回值
2、public Future submit() //任务执行完成后有返回值参数解释

  • 1、corePoolSize
    线程池中的核心线程数,当提交一个任务时,线程池创建一个新线程执行任务,直到当前线程数等于corePoolSize;如果当前线程数为corePoolSize,继续提交的任务被保存到阻塞队列中,等待被执行;如果执行了线程池的prestartAllCoreThreads()方法,线程池会提前创建并启动所有核心线程

  • 2、maximumPoolSize
    线程池中允许的最大线程数。如果当前阻塞队列满了,且继续提交任务,则创建新的线程执行任务,前提是当前线程数小于maximumPoolSize;

  • 3、keepAliveTime
    线程池维护线程所允许的空闲时间。当线程池中的线程数量大于corePoolSize的时候,如果这时没有新的任务提交,核心线程外的线程不会立即销毁,而是会等待,直到等待的时间超过了keepAliveTime;

  • 4、unit
    keepAliveTime的单位;

  • 5、workQueue
    用来保存等待被执行的任务的阻塞队列,任务数少于核心线程数时不会保存。且任务必须实现Runable接口,在JDK中提供了如下阻塞队列:
    1)ArrayBlockingQueue:基于数组结构的有界阻塞队列,按FIFO排序任务;
    2)linkedBlockingQuene:基于链表结构的阻塞队列,按FIFO排序任务,吞吐量通常要高于ArrayBlockingQuene;
    3)SynchronousQuene:一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于linkedBlockingQuene;
    4)priorityBlockingQuene:具有优先级的无界阻塞队列;

  • 6、threadFactory
    它是ThreadFactory类型的变量,用来创建新线程。默认使用Executors.defaultThreadFactory() 来创建线程。

  • 7、handler线程池的饱和策略,当阻塞队列满了,且没有空闲的工作线程,如果继续提交任务,必须采取一种策略处理该任务,线程池提供了4种策略:1、AbortPolicy:直接抛出异常,默认策略;2、CallerRunsPolicy:用调用者所在的线程来执行任务;3、DiscardOldestPolicy:丢弃阻塞队列中靠最前的任务,并执行当前任务;4、DiscardPolicy:直接丢弃任务;

任务执行流程

3、线程池存在5种状态

RUNNING = ­1 << COUNT_BITS; //高3位为111
SHUTDOWN = 0 << COUNT_BITS; //高3位为000
STOP = 1 << COUNT_BITS; //高3位为001
TIDYING = 2 << COUNT_BITS; //高3位为010
TERMINATED = 3 << COUNT_BITS; //高3位为011

1、RUNNING
(1) 状态说明:线程池处在RUNNING状态时,能够接收新任务,以及对已添加的任务进行处理。
(02) 状态切换:线程池的初始化状态是RUNNING。换句话说,线程池被一旦被创建,就处于RUNNING状态,并且线程池中的任务数为0!

2、 SHUTDOWN
(1) 状态说明:线程池处在SHUTDOWN状态时,不接收新任务,但能处理已添加的任务。
(2) 状态切换:调用线程池的shutdown()接口时,线程池由RUNNING -> SHUTDOWN。

3、STOP
(1) 状态说明:线程池处在STOP状态时,不接收新任务,不处理已添加的任务,并且会中断正在处理的任务。
(2) 状态切换:调用线程池的shutdownNow()接口时,线程池由(RUNNING or SHUTDOWN ) -> STOP。

4、非核心线程在什么时候被回收?

如果经过 keepAliveTime 时间后,超过核心线程数的线程还没有接受到新的任务,就会被回收。

那么我现在带入一个简单的场景,为了简单直观,我们把线程池相关的参数调整一下:
ExecutorService executorService = new ThreadPoolExecutor(2, 3, 30, TimeUnit.SECONDS,
new linkedBlockingQueue<>(2),
new DefaultThreadFactory(“test”),
new ThreadPoolExecutor.DiscardPolicy());

那么问题来了:

这个线程最多能容纳的任务是不是 5 个?
假设任务需要执行 1 秒钟,那么我直接循环里面提交 5 个任务到线程池,肯定是在 1 秒钟之内提交完成,那么当前线程池的活跃线程是不是就是 3 个?
如果接下来的 30 秒,没有任务提交过来。那么 30 秒之后,当前线程池的活跃线程是不是就是 2 个?
上面这三个问题的答案都是肯定的。

接下来的问题是这样的:

如果当前线程池的活跃线程是 3 个(2 个核心线程+ 1 个非核心线程),但是它们各自的任务都执行完成了,都处于 waiting 状态。然后我每隔 3 秒往线程池里面扔一个耗时 1 秒的任务。那么 30 秒之后,活跃线程数是多少?
先说答案:还是 3 个。

从我个人正常的思维,是这样的:核心线程是空闲的,每隔 3 秒扔一个耗时 1 秒的任务过来,所以仅需要一个核心线程就完全处理的过来。

那么,30 秒内,超过核心线程的那一个线程一直处于等待状态,所以​ 30 秒之后,就被回收了。 但是上面仅仅是我的主观认为,而实际情况呢?

30 秒之后,超过核心线程​的线程并不会被回收,活跃线程还是 3 个。

**因为实际在把任务分给线程的时候,是轮询分配的,也就是说非核心线程在3个任务的时间内一定会被分配一次,所以它并没有一直闲着,所以没回收它 **

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/308747.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号