线程池ThreadPoolExcutor详解

摘要:
Java线程池概述线程池技术在并发时经常会使用到,java中的线程池的使用是通过调用ThreadPoolExecutor来实现的。注:KeepAliveTime=0的话,表示不等待摘自阿里巴巴开发手册:线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。说明:Executors返回的线程池对象的弊端如下:1)FixedThreadPool和SingleThreadPool:允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM。

Java线程池概述

线程池技术在并发时经常会使用到,java中的线程池的使用是通过调用ThreadPoolExecutor来实现的。

ThreadPoolExecutor提供了四个构造函数,最后都会归结于下面这个构造方法:

/**
     * Creates a new {@code ThreadPoolExecutor} with the given initial
     * parameters.
     *
     * @param corePoolSize the number of threads to keep in the pool, even
     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
     * @param maximumPoolSize the maximum number of threads to allow in the
     *        pool
     * @param keepAliveTime when the number of threads is greater than
     *        the core, this is the maximum time that excess idle threads
     *        will wait for new tasks before terminating.
     * @param unit the time unit for the {@code keepAliveTime} argument
     * @param workQueue the queue to use for holding tasks before they are
     *        executed.  This queue will hold only the {@code Runnable}
     *        tasks submitted by the {@code execute} method.
     * @param threadFactory the factory to use when the executor
     *        creates a new thread
     * @param handler the handler to use when execution is blocked
     *        because the thread bounds and queue capacities are reached
     * @throws IllegalArgumentException if one of the following holds:<br>
     *         {@code corePoolSize < 0}<br>
     *         {@code keepAliveTime < 0}<br>
     *         {@code maximumPoolSize <= 0}<br>
     *         {@code maximumPoolSize < corePoolSize}
     * @throws NullPointerException if {@code workQueue}
     *         or {@code threadFactory} or {@code handler} is null
     */
    public ThreadPoolExecutor(intcorePoolSize,
                              intmaximumPoolSize,
                              longkeepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable>workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)

这些参数的意义如下:

corePoolSize:该线程池中核心线程数最大值

maximumPoolSize: 该线程池中线程总数最大值

keepAliveTime:该线程池中非核心线程闲置超时时长

unit:keepAliveTime的单位

workQueue:阻塞队列BlockingQueue,维护着等待执行的Runnable对象

threadFactory:创建线程的接口,需要实现他的Thread newThread(Runnable r)方法。

RejectedExecutionHandler:饱和策略,最大线程和工作队列容量且已经饱和时execute方法都将调用RejectedExecutionHandler

ThreadPoolExecutor工作流程

线程池ThreadPoolExcutor详解第1张

大致过程陈述为:

1. 向线程池中添加任务,当任务数量少于corePoolSize时,会自动创建thead来处理这些任务;

2.当添加任务数大于corePoolSize且少于maximmPoolSize时,不在创建线程,而是将这些任务放到阻塞队列中,等待被执行;

3.接上面2的条件,且当阻塞队列满了之后,继续创建thread,从而加速处理阻塞队列;

4. 当添加任务大于maximmPoolSize时,根据饱和策略决定是否容许继续向线程池中添加任务,默认的饱和策略是AbortPolicy(直接丢弃)。

线程池中使用的阻塞队列

ArrayBlockingQueue:基于数组结构的有界阻塞队列,构造函数一定要传大小,FIFO(先进先出);

LinkedBlockingQueue:无界,默认大小65536(Integer.MAX_VALUE),当大量请求任务时,容易造成内存耗尽。

SynchronousQueue:同步队列,是一个特殊的BlockingQueue,它没有容量(这是因为在SynchronousQueue中,插入将等待另一个线程的删除操作,反之亦然)。具体可以参考:《Java SynchronousQueue Examples(译)》

PriorityBlockingQueue: 优先队列,无界。DelayedWorkQueue:这个队列接收到任务时,首先先入队,只有达到了指定的延时时间,才会执行任务

阻塞队列常见的方法如下表所示:

线程池ThreadPoolExcutor详解第2张

常见四种线程池

newCachedThreadPool

newFixedThreadPool

newSingleThreadExecutor

newScheduledThreadPool

线程池ThreadPoolExcutor详解第3张

它们通过Executors以静态方法的方式直接调用,实质上是它们最终调用的是ThreadPoolExecutor的构造方法,也就是本文最前面那段代码。

注:KeepAliveTime=0的话,表示不等待

摘自阿里巴巴开发手册:

【强制】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样 的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。

说明:Executors 返回的线程池对象的弊端如下:

1)FixedThreadPool 和 SingleThreadPool: 允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。

2)CachedThreadPool 和 ScheduledThreadPool: 允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。

应用样例,更多请参看我的github

package multiThread;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public classThreadPoolExecutorTest {
    public static voidmain(String[] args) {

        ThreadPoolExecutor threadPool = newThreadPoolExecutor(
                1, 2, 10, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(1),
                newThreadPoolExecutor.DiscardPolicy());

        System.out.println("getQueue:" +threadPool.getQueue().size());
        System.out.println("remainingCapacity:" +threadPool.getQueue().remainingCapacity());

        threadPool.execute(() ->{
            try{
                int count = 0;
                Thread.currentThread().setName("aa");
                while (count <= 10) {
                    System.out.println(Thread.currentThread().getName() + "getQueue:" +threadPool.getQueue().size());
                    System.out.println(Thread.currentThread().getName() +System.currentTimeMillis());
                    Thread.sleep(1000);
                    count++;
                }
            } catch(Exception e) {
                e.printStackTrace();
            }
        });

        threadPool.execute(() ->{
            try{
                int count = 0;
                Thread.currentThread().setName("bbb");
                while (count <= 100) {
                    System.out.println(Thread.currentThread().getName() + "getQueue:" +threadPool.getQueue().size());
                    System.out.println(Thread.currentThread().getName() +System.currentTimeMillis());
                    Thread.sleep(1000);
                    count++;
                }
            } catch(Exception e) {
                e.printStackTrace();
            }
        });

    }
}

免责声明:文章转载自《线程池ThreadPoolExcutor详解》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇基于Linux平台的高级IO扩展函数spring data jpa的动态查询封装(转)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Java并发知识总结,超详细!

首先给大家分享一个github仓库,上面放了200多本经典的计算机书籍,包括C语言、C++、Java、Python、前端、数据库、操作系统、计算机网络、数据结构和算法、机器学习、编程人生等,可以star一下,下次找书直接在上面搜索,仓库持续更新中~ github地址:https://github.com/Tyson0314/java-books 如果gi...

基于Linux/C++简单线程池的实现

我们知道Java语言对于多线程的支持十分丰富,JDK本身提供了很多性能优良的库,包括ThreadPoolExecutor和ScheduleThreadPoolExecutor等。C++11中的STL也提供了std:thread(然而我还没有看,这里先占个坑)还有很多第三方库的实现。这里我重复“造轮子”的目的还是为了深入理解C++和Linux线程基础概念,主...

Nodejs事件引擎libuv源码剖析之:高效线程池(threadpool)的实现

     声明:本文为原创博文,转载请注明出处。      Nodejs编程是全异步的,这就意味着我们不必每次都阻塞等待该次操作的结果,而事件完成(就绪)时会主动回调通知我们。在网络编程中,一般都是基于Reactor线程模型的变种,无论其怎么演化,其核心组件都包含了Reactor实例(提供事件注册、注销、通知功能)、多路复用器(由操作系统提供,比如kque...

线程池:Execution框架

每问题每线程:在于它没有对已创建线程的数量进行任何限制,除非对客户端能够抛出的请求速率进行限制。 下边 有些图片看不到,清看原地址:http://www.360doc.com/content/10/1027/21/495229_64583490.shtml 无限制创建线程的缺点: 1.线程生命周期的开销:线程的创建和关闭并不是“免费的”。 2.资源消耗量:...

C#异步编程的实现方式——ThreadPool线程池

在需要创建的线程很多,且都是比较小的线程的情况下,可以使用线程池(ThreadPool类)。ThreadPool是一个静态方法,提供了对一个线程集合的操作,它会在线程数不足时增加线程,空闲线程数过多时释放资源。 1、ThreadPool简单应用 调用ThreadPool.QueueUserWorkItem()方法,传递一个WaitCallBack委托类型的...

长沙社区团购独角兽《兴盛优选》 18k 面试题记录,已拿offer!

长沙或者想从北上广大回长沙的小伙伴,应该都听说过《兴盛优选》,一家位于长沙市从事社区团购业务的独角兽企业。 目前日订单1000+万,在长沙薪资也较有诱惑力,要不要来挑战一下? 我在里面潜伏过一段时间,发现里面缺人非常严重,大家都知道长沙互联网发展的晚,目前《兴盛优选》的招人要求也比较高(相对长沙其他企业),所以招到满意的人非常少,100份简历可能只能进1到...