精华内容
下载资源
问答
  • 线程池参数详解

    2019-06-19 16:18:38
    一、线程池参数和意义 ThreadPoolExecutor mExecutor = new ThreadPoolExecutor(corePoolSize,// 核心线程数 maximumPoolSize, // 最大线程数 keepAliveTime, // 闲置线程存活时间 TimeUnit....

    一、线程池参数和意义

    ThreadPoolExecutor mExecutor = new ThreadPoolExecutor(corePoolSize,// 核心线程数
    						maximumPoolSize, // 最大线程数
    						keepAliveTime, // 闲置线程存活时间
    						TimeUnit.MILLISECONDS,// 时间单位
    						new LinkedBlockingDeque<Runnable>(),// 线程队列
    						Executors.defaultThreadFactory(),// 线程工厂
    						new AbortPolicy()// 队列已满,而且当前线程数已经超过最大线程数时的异常处理策略
    				);
    

    1、corePoolSize:核心线程数
    * 核心线程会一直存活,及时没有任务需要执行
    * 当线程数小于核心线程数时,即使有线程空闲,线程池也会优先创建新线程处理
    * 设置allowCoreThreadTimeout=true(默认false)时,核心线程会超时关闭
    2、queueCapacity:任务队列容量(阻塞队列)
    * 当核心线程数达到最大时,新任务会放在队列中排队等待执行
    3、maxPoolSize:最大线程数
    * 当线程数>=corePoolSize,且任务队列已满时。线程池会创建新线程来处理任务
    * 当线程数=maxPoolSize,且任务队列已满时,线程池会拒绝处理任务而抛出异常
    4、 keepAliveTime:线程空闲时间
    * 当线程空闲时间达到keepAliveTime时,线程会退出,直到线程数量=corePoolSize
    * 如果allowCoreThreadTimeout=true,则会直到线程数量=0
    5、allowCoreThreadTimeout:允许核心线程超时
    6、rejectedExecutionHandler:任务拒绝处理器
    * 两种情况会拒绝处理任务:
    - 当线程数已经达到maxPoolSize,切队列已满,会拒绝新任务
    - 当线程池被调用shutdown()后,会等待线程池里的任务执行完毕,再shutdown。如果在调用shutdown()和线程池真正shutdown之间提交任务,会拒绝新任务
    * 线程池会调用rejectedExecutionHandler来处理这个任务。如果没有设置默认是AbortPolicy,会抛出异常
    * ThreadPoolExecutor类有几个内部实现类来处理这类情况:
    - AbortPolicy 丢弃任务,抛运行时异常
    - CallerRunsPolicy 执行任务
    - DiscardPolicy 忽视,什么都不会发生
    - DiscardOldestPolicy 从队列中踢出最先进入队列(最后一个执行)的任务
    * 实现RejectedExecutionHandler接口,可自定义处理器

    二、ThreadPoolExecutor执行顺序
    线程池按以下行为执行任务
    1. 当线程数小于核心线程数时,创建线程。
    2. 当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列。
    3. 当线程数大于等于核心线程数,且任务队列已满
    - 若线程数小于最大线程数,创建线程
    - 若线程数等于最大线程数,抛出异常,拒绝任务

    三、拒绝策略
    在这里插入图片描述

    展开全文
  • 平凡也就两个字: 懒和惰;成功也就两个字: 苦和勤;优秀也就两个字: 你和我。跟着我从0学习JAVA、spring...ThreadPoolExecutor线程池使用详解【图文教程】ThreadPoolExecutor源码的学习(基于JDK 1.7)1 继承关系 Thre...

    平凡也就两个字: 懒和惰;
    成功也就两个字: 苦和勤;
    优秀也就两个字: 你和我。
    跟着我从0学习JAVA、spring全家桶和linux运维等知识,带你从懵懂少年走向人生巅峰,迎娶白富美!
    每一篇文章都是心得总结,跟我学习你就是大牛!

    ThreadPoolExecutor线程池使用详解【图文教程】

    ThreadPoolExecutor源码的学习(基于JDK 1.7)

    1 继承关系

          ThreadPoolExecutor就是我们经常说的大名鼎鼎的线程池,Executors工厂创建的线程池都是该类的实例,通过调节参数的大小创建适用于各个场景的线程池。通过源码我们了解到ThreadPoolExecutor继承了AbstractExecutorService,该抽象类为线程池提供了默认实现。

    6a45db95c9ec600ef721ed3b9177b00e.png

    2 ThreadPoolExecutor的构造方法

         ThreadPoolExecutor有很多重载的构造函数,所有构造函数最终都调用了一个构造函数,只是有些构造函数有默认参数而已,看下最终调用的构造函数:

    25e58f07b09748582c091c7bbdb388c4.png

    2.1 构造方法参数详解

     上面这个构造函数有很多参数,我们分别来解释每一个参数的意义:

    (1)corePoolSize:核心线程数

          核心线程池的大小。当总的创建的线程个数小于CorePoolSize个时,都会创建一个新线程来执行提交的任务请求,核心线程池中的线程创建之后不会销毁(任务执行完之后不会销毁,而是处于空闲状态)。默认情况下核心线程会一直存活,即使处于闲置状态也不会受存keepAliveTime限制。除非将allowCoreThreadTimeOut设置为true

    (2)maximumPoolSize:线程池允许最大的线程数

          线程池所能容纳的最大线程数。表示设置线程池的大小,指定线程池允许的最大线程数量。超过这个数的线程将被阻塞。当任务队列为没有设置大小的LinkedBlockingDeque时,这个值无效。

    (3)keepAliveTime:闲置线程最长存活时间

          非核心线程中闲置线程最长可以存活的时间,超过这个时间就会被回收。unit:时间单位。

          1)如果线程池中的线程个数大于corePoolSize核心线程池大小,且多余的线程(非核心线程)处于空闲状态的时间超过了keepAliveTime设置时间,那么多余的线程将会被终止。当线程池没被使用的时候,这种机制可减少资源消耗。

          2)keepAliveTime线程存活时间参数可以被动态改变,通过setKeepAliveTime(long time, TimeUnit unit)方法来动态设置keepAliveTime值。将time设置成Long.MAX_VALUE,且unit设置成NANOSECONDS(纳秒),则表示在线程池关闭(shut down)之前超出核心线程池的且处于空闲状态的线程永远不会终止,永远处于空闲状态!(即:线程永远存活)。

          默认情况下(allowCoreThreadTimeOut=false), keep-alive策略只有当线程池中的线程数超过了核心线程池大小(corePoolSize)的时候才会起作用,且只对超出核心线程池大小的线程数起作用,对核心线程池不起作用(核心线程池中的线程永远不会终止,除非线程池shut down关闭)。但是只要keepAliveTime值不为0,就可以通过               

          allowCoreThreadTimeOut(boolean)方法来将这个超时策略应用到核心线程。(也就是说如何将超时策略用到了核心线程池上之后,当核心线程池中的线程处于空闲状态,且空闲时间超过keepAliveTime设定时间后会被终止掉!)。

    (4)unit:指定keepAliveTime的单位

          指定keepAliveTime的单位,如:TimeUnit.SECONDS。当将allowCoreThreadTimeOut设置为true时对corePoolSize生效。

    (5)workQueue:线程池中的任务队列

          当池中线程数大于corePoolSize时,新来的任务保存到该队列。常用的有三种队列,SynchronousQueueLinkedBlockingDequeArrayBlockingQueue

    (6)threadFactory:线程工厂

          线程池中的所有线程都是通过这个工厂创建的。用ThreadFactory来创建线程。如果没指定用哪个ThreadFactory,则会使用defaultThreadFactory默认线程工厂来创建线程。defaultThreadFactory默认线程工厂创建的线程具有相同的优先级(NORM_PRIORITY),非守护进程(non-daemon)状态,并且在相同的线程组(ThreadGroup)里。

          通过指定自定义ThreadFactory线程工厂(实现ThreadFactory接口的自定义类),在线程工厂里可以设置创建的每个线程的名称,线程所在组,优先级和守护进程状态等等。【By supplying a different ThreadFactory, you can alter the thread's name, thread group, priority, daemon status,etc】

    (7)handler:任务拒绝执行的策略

        当线程池无法处理新来任务时的处理策略。当Executor执行器shut down关闭 或 工作线程超过maximumPoolSize最大线程数 或 工作队列超过了设置的最大capacity能力的情况下,execute(Runnable)方法提交的任务将会被拒绝(不会执行)!当上述3种情况的任意一种情况发生时,会回调RejectedExecutionHandler接口的rejectedExecution(Runnable, ThreadPoolExecutor)方法,可以实现RejectedExecutionHandler接口的rejectedExecution(Runnable, ThreadPoolExecutor)方法,在其中做一些抛出异常或日志记录的操作!

    3 线程池工作示例图

    4d6379ae2170e2e3df2ff1cc4db4f231.png

    (1)当一个任务通过submit或者execute方法提交到线程池的时候,如果当前池中线程数(包括闲置线程)小于coolPoolSize,即使其他工作线程是空闲的,也会创建一个新线程来处理该任务

    (2)如果当前池中线程数大于等于coolPoolSize个,则将该任务加入到等待队列。只要有核心线程空闲,那么就会从队列中去获取任务进行处理(重用空闲的核心线程);

    (3)如果任务不能入队列,说明等待队列已满,若当前池中线程数小于maximumPoolSize,则创建一个临时线程(非核心线程)执行该任务。

    (4)如果当前池中线程数已经等于maximumPoolSize,此时无法执行该任务,根据拒绝执行策略处理,后面还会详细讲解具体的拒绝执行策略。

          以上4步是线程池处理到达任务的主要流程。当池中线程数大于coolPoolSize,超过keepAlive时间的闲置线程会被回收掉。注意,回收的是非核心线程,核心线程一般是不会回收的。如果设置allowCoreThreadTimeOut(true),则核心线程在闲置keepAlive时间后也会被回收。任务队列是一个阻塞队列,核心线程执行完任务后会去队列取任务来执行,如果队列为空,线程就会阻塞,直到取到任务。

    4  代码实现:初始化线程池,使用线程池跑多线程任务

    package com.test.alltest.java.thread.threadPool;import java.util.concurrent.*;import java.util.concurrent.atomic.AtomicInteger;//线程池测试public class Main {    private static AtomicInteger count = new AtomicInteger(0);//线程计数    private static int corePoolSize = 2;//核心线程数    private static int maximumPoolSize = 4;//最大线程数。可以计算,非核心线程数 = maximumPoolSize - corePoolSize = 2    private static long keepAliveTime = 10;//非核心空闲线程最长存活时间    private static TimeUnit timeUnit = TimeUnit.SECONDS;//非核心空闲线程最长存活时间的单位    //指定阻塞队列的类型和队列长度。可以计算,被核心线程数同时处理的任务个数 = corePoolSize + 队列容量 = 2 + 2 = 4    private static BlockingQueue workQueue = new ArrayBlockingQueue(2);    //定义线程工厂    private static ThreadFactory myThreadFactory = new ThreadFactory() {        @Override        public Thread newThread(Runnable runnable) {            String threadName = "线程" + count.addAndGet(1);            Thread t = new Thread(runnable, threadName);            return t;        }    };    //定义任务拒绝执行的策略    private static RejectedExecutionHandler rejectedExecutionHandler = new RejectedExecutionHandler() {        @Override        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {            // 记录异常            // 报警处理等            int iActiveCount = executor.getActiveCount();            int iRemainQueue = executor.getQueue().remainingCapacity();            int iexsitQueue = executor.getQueue().size();            System.out.println("Warn:当前运行的线程数:"+String.valueOf(iActiveCount) +                    ",当前队列剩余数:" + iRemainQueue +                    ",当前队列排队的任务数:" + iexsitQueue);        }    };    public static void main(String[] args) {        //1.初始化线程池        ThreadPoolExecutor executor = new ThreadPoolExecutor(                corePoolSize,                maximumPoolSize,                keepAliveTime,                timeUnit,                workQueue,                myThreadFactory,                rejectedExecutionHandler                );        /**         * 2.使用线程池         * 创建7个任务: 根据线程池的初始化参数配置可推测:         * (1)2个任务立即执行;         * (2)2个任务加入到阻塞队列中等待核心线程执行;         * (3)2个任务被2个非核心线程执行;         * (4)剩下的1个任务没有线程来执行(被拒绝执行),因此调用【拒绝执行策略】来处理。         */        for(int i=0; i<7; i++){            //执行任务            executor.execute(new Runnable() {                @Override                public void run() {                    System.out.println("当前执行任务的线程名:" + Thread.currentThread().getName());                    long start = System.currentTimeMillis();                    while (true){                        long end = System.currentTimeMillis();                        if((end - start) > 10000){//10秒                            break;                        }                    }                }            });        }    }}

    Tips:

          1)将CorePoolSize和maximumPoolSize值设置成一样,即:创建一个固定大小的线程池.

          2)将maximumPoolSize设置成最大值(Integer.MAX_VALUE),表示设置线程池可以容纳任意数量的并发任务(即:任意数量的线程)。

          3)大多数情况下,核心(CorePoolSize)和最大线程(maximumPoolSize)池的大小在构造线程池对象的时候进行设置(构造方法中设置);但是也可以使用{setCorePoolSize}和{setMaximumPoolSize}方法动态地更改它们。

    展开全文
  • JDK1.5中引入了强大的concurrent包,其中最常用的莫过了线程池的实现ThreadPoolExecutor,它给我们带来了极大的方便,但同时,对于该线程池不恰当的设置也可能使其效率并不能达到预期的效果,甚至仅相当于或低于单...

    JDK1.5中引入了强大的concurrent包,其中最常用的莫过了线程池的实现ThreadPoolExecutor,它给我们带来了极大的方便,但同时,对于该线程池不恰当的设置也可能使其效率并不能达到预期的效果,甚至仅相当于或低于单线程的效率。

    ThreadPoolExecutor类可设置的参数主要有:

    corePoolSize

    核心线程数,核心线程会一直存活,即使没有任务需要处理。当线程数小于核心线程数时,即使现有的线程空闲,线程池也会优先创建新线程来处理任务,而不是直接交给现有的线程处理。

    核心线程在allowCoreThreadTimeout被设置为true时会超时退出,默认情况下不会退出。

    maxPoolSize

    当线程数大于或等于核心线程,且任务队列已满时,线程池会创建新的线程,直到线程数量达到maxPoolSize。如果线程数已等于maxPoolSize,且任务队列已满,则已超出线程池的处理能力,线程池会拒绝处理任务而抛出异常。

    keepAliveTime

    当线程空闲时间达到keepAliveTime,该线程会退出,直到线程数量等于corePoolSize。如果allowCoreThreadTimeout设置为true,则所有线程均会退出直到线程数量为0。

    allowCoreThreadTimeout

    是否允许核心线程空闲退出,默认值为false。

    queueCapacity

    任务队列容量。从maxPoolSize的描述上可以看出,任务队列的容量会影响到线程的变化,因此任务队列的长度也需要恰当的设置。

    线程池按以下行为执行任务

    当线程数小于核心线程数时,创建线程。

    当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列。

    当线程数大于等于核心线程数,且任务队列已满

    若线程数小于最大线程数,创建线程

    若线程数等于最大线程数,抛出异常,拒绝任务

    系统负载

    参数的设置跟系统的负载有直接的关系,下面为系统负载的相关参数:

    tasks,每秒需要处理的最大任务数量

    tasktime,处理第个任务所需要的时间

    responsetime,系统允许任务最大的响应时间,比如每个任务的响应时间不得超过2秒。

    参数设置

    corePoolSize:

    每个任务需要tasktime秒处理,则每个线程每钞可处理1/tasktime个任务。系统每秒有tasks个任务需要处理,则需要的线程数为:tasks/(1/tasktime),即tasks*tasktime个线程数。假设系统每秒任务数为100~1000,每个任务耗时0.1秒,则需要100*0.1至1000*0.1,即10~100个线程。那么corePoolSize应该设置为大于10,具体数字最好根据8020原则,即80%情况下系统每秒任务数,若系统80%的情况下第秒任务数小于200,最多时为1000,则corePoolSize可设置为20。

    queueCapacity:

    任务队列的长度要根据核心线程数,以及系统对任务响应时间的要求有关。队列长度可以设置为(corePoolSize/tasktime)*responsetime: (20/0.1)*2=400,即队列长度可设置为400。

    队列长度设置过大,会导致任务响应时间过长,切忌以下写法:

    LinkedBlockingQueue queue = new LinkedBlockingQueue();

    这实际上是将队列长度设置为Integer.MAX_VALUE,将会导致线程数量永远为corePoolSize,再也不会增加,当任务数量陡增时,任务响应时间也将随之陡增。

    maxPoolSize:

    当系统负载达到最大值时,核心线程数已无法按时处理完所有任务,这时就需要增加线程。每秒200个任务需要20个线程,那么当每秒达到1000个任务时,则需要(1000-queueCapacity)*(20/200),即60个线程,可将maxPoolSize设置为60。

    keepAliveTime:

    线程数量只增加不减少也不行。当负载降低时,可减少线程数量,如果一个线程空闲时间达到keepAliveTiime,该线程就退出。默认情况下线程池最少会保持corePoolSize个线程。

    allowCoreThreadTimeout:

    默认情况下核心线程不会退出,可通过将该参数设置为true,让核心线程也退出。

    以上关于线程数量的计算并没有考虑CPU的情况。若结合CPU的情况,比如,当线程数量达到50时,CPU达到100%,则将maxPoolSize设置为60也不合适,此时若系统负载长时间维持在每秒1000个任务,则超出线程池处理能力,应设法降低每个任务的处理时间(tasktime)。

    展开全文
  • 线程池参数详解和线程状态解释 什么是线程? 线程池主要是为了解决,应用程序在执行一个新的任务时,需要新建一个线程来执行以及任务执行完毕后销毁线程所带来的消耗。线程池可以在项目初始化时创建一个线程集合,有...

    线程池参数详解和线程状态解释


    什么是线程?
    线程池主要是为了解决,应用程序在执行一个新的任务时,需要新建一个线程来执行以及任务执行完毕后销毁线程所带来的消耗。线程池可以在项目初始化时创建一个线程集合,有新的任务需要执行时直接从线程池中获取线程,任务执行完毕再归还线程池等待下次任务分配,从而达到资源复用。

    线程池方法
    public ThreadPoolExecutor(int corePoolSize,
    int maximumPoolSize,
    long keepAliveTime,
    TimeUnit unit,
    BlockingQueue workQueue,
    RejectedExecutionHandler handler) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
    Executors.defaultThreadFactory(), handler);
    }
    参数解释:
    corePoolSize:核心线程数量
    maximumPoolSize:最大线程数量,当workQueue(队列缓存已满)并且核心线程<最大线程数量时,会创建一个非核心线程
    keepAliveTime:空闲线程的存活时间
    unit:keepAliveTime空闲线程存活的时间单位
    workQueue:缓存队列
    handler:拒绝策略,缓存队列满了,最大线程数量也满了,还有任务在进入时会触发拒绝策略
    四种拒绝策略:
    DiscardPolicy:直接拒绝不抛异常
    AbortPolic:直接抛异常(默认)
    DiscardOldestPolicy:丢弃队列中等待时间最久的任务
    CallerRunsPolicy:由调用线程来处理该任务
    线程的状态:
    Thread t1 = new Thread();:初始状态
    t1.start();:就绪状态
    t1.run();:运行时状态
    t1.stop();:阻塞状态
    线程结束:终止状态:

    展开全文
  • 所以,多线程技术是服务端开发人员必须掌握的技术。线程的创建和销毁,都涉及到系统调用,比较消耗系统资源,那么有没有一种办法使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以...所以就引入了线程池...
  • 我是一个一直在一线互联网踩坑十余年的编码爱好者,现在将我们的各种经验以及架构实战分享出来,如果大家喜欢,就关注我,一起将技术学深学透,我会每一篇分享结束都会预告下一专题线程池的创建分为两种方式:...
  • 之前我们介绍了线程池的四种拒绝策略,了解了线程池参数的含义,那么今天我们来聊聊Java 中常见的几种线程池,以及在jdk7 加入的 ForkJoin 新型线程池 首先我们列出Java 中的六种线程池如下在了解集中线程池时我们先...
  • 线程池是并发编程中必不可少的一种工具,也是面试高频话题。线程池,即管理着若干线程的资源池(字面意思)。相比于为每个任务分配一个线程,在线程池中执行任务优势更多:1.线程复用:线程池中的线程是可以复用的,省...
  • java线程池参数详解

    2019-08-19 14:47:59
    一、线程池的三种创建方式(采坑点...二、线程池有以下七个参数,且线程池的底层的是ThreadPoolExecutor 对照上图的七个参数 三、线程池的底层工作原理 四、几个注意点 线程池的四种拒绝策略 ...
  • 背景:这两天接触一个使用线程池做异步...一、线程池参数配置 主要参考下面这篇文章:https://blog.csdn.net/ye17186/article/details/89467919 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
  • 分别是单一线程的线程池、固定数量的线程池、周期性执行线程池、可缓存线程池 **单一线程的线程池:**一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯
  • Java线程池参数详解

    2018-11-09 17:22:00
    JDK1.5中引入了强大的concurrent包,其中最常用的莫过了线程池的实现ThreadPoolExecutor,它给我们带来了极大的方便,但同时,对于该线程池不恰当的设置也可能使其效率并不能达到预期的效果,甚至仅相当于或低于单...
  • 线程池的几个参数 1.corePoolSize线程池核心线程大小 线程池会维护一个最小的线程数量即为核心线程,核心线程指的是,及时这些线程出处于空闲状态,也不会被销毁,当然,也有销毁的方法,便是通过...
  • 线程池的作用及优势 线程池做的工作主要是控制运行的线程的数量,处理过程中将任务加入队列,然后在线程创建后启动这些任务,如果提交的任务超过了线程能执行的最大数量,超出的数量的任务会被提交到一个阻塞队列排队...
  • 一、线程池简介 1.底层都是ThreadPoolExecutor实现 2. 3.核心线程数corePoolSize:线程池的常驻核心线程数 4.maximumPoolSize线程池能够容纳同时执行的最大线程数 5.keepAliveTime:多余的空闲线程的存活时间。当...
  • java线程池参数详解及工作原理

    千次阅读 2019-03-14 16:08:21
    一、线程池简介 1.底层都是ThreadPoolExecutor实现 2. 3.核心线程数corePoolSize:线程池的常驻核心线程数 4.maximumPoolSize线程池能够容纳同时执行的最大线程数 5.keepAliveTime:多余的空闲线程的存活时间。...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 719
精华内容 287
关键字:

线程池参数详解