Java: 线程池(ThreadPoolExecutor)中的参数说明

最近在看《阿里巴巴Android开发手册》,里面有这样几句话:

【强制】新建线程时,必须通过线程池提供(AsyncTask 或者ThreadPoolExecutor或者其他形式自定义的线程池),不允许在应用中自行显式创建线程。
【强制】线程池不允许使用Executors 去创建,而是通过ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。

个人对线程池的使用也有一段日子了,而且很多时候为了省事用的都是Executors的方式去创建,也没什么问题,不过既然阿里的工程师这么说,自然有这么说的道理,以后还是尽量改用ThreadPoolExecutor的方式来创建吧,不过使用ThreadPoolExecutor方式来创建时,需要传入的参数很多,为了加深记忆(老年人了脑子不好),特记录之:

为什么要引入线程池

平时在Android开发的过程中经常会用到多线程异步处理相关任务,每开一个线程都要新建一个Thread对象来处理,这种操作会造成哪些后果呢?

1、系统执行多任务时,会为每个任务创建对应的线程,当任务执行结束之后会销毁对应的线程,在这种情况下对象被频繁的创建和销毁。
2、当对线程象被频繁时会占用大量的系统资源,在并发的过程中会造成资源竞争出现问题。大量的创建线程还会造成混乱,没有一个统一的管理机制,容易造成应用卡顿。
3、大量线程对象被频繁销毁,将会频繁出发GC机制,从而降低性能。

引入线程池的好处:

1、重用线程池中的线程,避免因频繁创建和销毁线程造成的性能消耗。
2、更加有效的控制线程的最大并发数,防止线程过多抢占资源造成的系统阻塞。
3、对线程进行有效的管理。

ThreadPoolExecutor的参数说明

这个类的构造函数如下:

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

corePoolSize

核心线程数。在创建线程池之后,默认情况下线程池中并没有任何的线程,而是等待任务到来才创建线程去执行任务,当线程池中的线程数目达到 corePoolSize后,新来的任务将会被添加到缓存队列中,也就是那个workQueue,除非调用 ThreadPoolExecutor#prestartAllCoreThreads() 方法或者是 ThreadPoolExecutor # prestartCoreThread() 方法(从这两个方法的名字就可以看出是预创建线程的意思,即在没有任务到来之前就创建corePoolSize个线程或一个线程)。

PS:很多人不知道这个数该填多少合适,其实也不必特别纠结,根据实际情况填写就好,实在不知道,就按照阿里工程师的写法取下列值就好了:
int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();

maximumPoolSize

线程池中的最大线程数。表示线程池中最多可以创建多少个线程,很多人以为它的作用是这样的:”当线程池中的任务数超过 corePoolSize 后,线程池会继续创建线程,直到线程池中的线程数小于maximumPoolSize“,其实这种理解是完全错误的。它真正的作用是:当线程池中的线程数等于 corePoolSize 并且 workQueue 已满,这时就要看当前线程数是否大于 maximumPoolSize,如果小于maximumPoolSize 定义的值,则会继续创建线程去执行任务, 否则将会调用去相应的任务拒绝策略来拒绝这个任务。另外超过 corePoolSize的线程被称做"Idle Thread", 这部分线程会有一个最大空闲存活时间(keepAliveTime),如果超过这个空闲存活时间还没有任务被分配,则会将这部分线程进行回收。

keepAliveTime

控制"idle Thread"的空闲存活时间。这个idle Thread就是上面提到的超过 corePoolSize 后新创建的那些线程,默认情况下,只有当线程池中的线程数大于corePoolSize,且这些"idle Thread"并没有被分配任务时,这个参数才会起作用。另外,如果调用了 ThreadPoolExecutor#allowCoreThreadTimeOut(boolean) 的方法,在线程池中的线程数不大于corePoolSize,且这些core Thread 也没有被分配任务时,keepAliveTime 参数也会起作用。

unit

参数keepAliveTime的时间单位,共7种取值,在TimeUtil中定义:

TimeUnit.DAYS;              //天
TimeUnit.HOURS;             //小时
TimeUnit.MINUTES;           //分钟
TimeUnit.SECONDS;           //秒
TimeUnit.MILLISECONDS;      //毫秒
TimeUnit.MICROSECONDS;      //微妙
TimeUnit.NANOSECONDS;       //纳秒

workQueue

阻塞队列。如果当前线程池中的线程数目>=corePoolSize,则每来一个任务,会尝试将其添加到该队列当中,注意只要超过了 corePoolSize 就会把任务添加到该缓存队列,添加可能成功也可能不成功,如果成功的话就会等待空闲线程去执行该任务,若添加失败(一般是队列已满),就会根据当前线程池的状态决定如何处理该任务(若线程数 < maximumPoolSize 则新建线程;若线程数 >= maximumPoolSize,则会根据拒绝策略做具体处理)。

常用的阻塞队列有:

1)ArrayBlockingQueue       //基于数组的先进先出队列,此队列创建时必须指定大小;
2)LinkedBlockingQueue      //基于链表的先进先出队列,如果创建时没有指定此队列大小,则默认为Integer.MAX_VALUE;
3)synchronousQueue        //这个队列比较特殊,它不会保存提交的任务,而是将直接新建一个线程来执行新来的任务。

threadFactory

线程工厂。用来为线程池创建线程,当我们不指定线程工厂时,线程池内部会调用Executors.defaultThreadFactory()创建默认的线程工厂,其后续创建的线程优先级都是Thread.NORM_PRIORITY。如果我们指定线程工厂,我们可以对产生的线程进行一定的操作。

handler

拒绝执行策略。当线程池的缓存队列已满并且线程池中的线程数目达到maximumPoolSize,如果还有任务到来就会采取任务拒绝策略,通常有以下四种策略:

ThreadPoolExecutor.AbortPolicy:         // 丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:       // 也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:    // 丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:      // 由调用线程处理该任务

参考链接:
1. 初探Android 线程池
2. Java并发编程:线程池的使用

原文地址:https://www.cnblogs.com/yongdaimi/p/12010006.html

时间: 2024-10-07 01:11:13

Java: 线程池(ThreadPoolExecutor)中的参数说明的相关文章

Java线程池ThreadPoolExecutor使用和分析(三) - 终止线程池原理

相关文章目录: Java线程池ThreadPoolExecutor使用和分析(一) Java线程池ThreadPoolExecutor使用和分析(二) - execute()原理 Java线程池ThreadPoolExecutor使用和分析(三) - 终止线程池原理 以下是本文的目录大纲: 一.shutdown()  --  温柔的终止线程池 interruptIdleWorkers()  --  中断空闲worker tryTerminate()  --  尝试终止线程池 二.shutdown

JAVA线程池ThreadPoolExecutor与阻塞队列BlockingQueue .

从Java5开始,Java提供了自己的线程池.每次只执行指定数量的线程,java.util.concurrent.ThreadPoolExecutor 就是这样的线程池.以下是我的学习过程. 首先是构造函数签名如下: [java] view plain copy print ? public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<

java 线程池ThreadPoolExecutor 如何与 AsyncTask() 组合使用。

转载请声明出处谢谢!http://www.cnblogs.com/linguanh/ 这里主要使用Executors中的4种静态创建线程池实例方法中的 newFixedThreadPool()来举例讲解. 简单说下Executors类,提供的一系列创建线程池的方法: 他们都有两个构造方法 1. --------newFixedThreadPool (创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待.) public static ExecutorService newFixed

java 线程池 ---- ThreadPoolExecutor 类

执行流程 1, 创建线程池后, 默认不会创建线程, 等到有任务带来才创建线程, 即一个线程处理一个任务 2, 当线程数量达到核心线程数时, 任务放进队列, 如果放入队列失败, 创建新线程处理任务(此时线程池线程数大于核心线程数) 3, 如果线程数大于最大线程数, 执行拒绝策略处理任务 构造方法 public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, Block

Java线程池--ThreadPoolExecutor

一.线程池的处理流程 向线程池提交一个任务后,它的主要处理流程如下图所示: 一个线程从被提交(submit)到执行共经历以下流程: 线程池判断核心线程池里的线程是否都在执行任务,如果不是,则创建一个新的工作线程来执行任务.如果核心线程池里的线程都在执行任务,则进入下一个流程; 线程池判断工作队列是否已满.如果工作队列没有满,则将新提交的任务储存在这个工作队列里.如果工作队列满了,则进入下一个流程; 线程池判断其内部线程是否都处于工作状态.如果没有,则创建一个新的工作线程来执行任务.如果已满了,则

Java线程池ThreadPoolExecutor

线程池的好处 1. 降低资源的消耗 通过重复利用已创建的线程降低线程创建和销毁所造成的消耗 2. 提高响应速度 当任务到达时,任务可以不需要等到线程创建就能立即执行 3. 提高线程的可管理型 线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一分配.调优和监控. 实现原理 当提交一个新任务到线程池时,线程池的处理流程为: 1). 线程池判断核心线程池里的线程是否都在执行任务. 如果不是,则创建一个新的工作线程来执行任务.如果核心线程池里的线程都在执行

java线程池ThreadPoolExecutor理解

Java通过Executors提供四种线程池,分别为:newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程.newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待.newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行.newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有

深入理解java线程池—ThreadPoolExecutor

几句闲扯:首先,我想说java的线程池真的是很绕,以前一直都感觉新建几个线程一直不退出到底是怎么实现的,也就有了后来学习ThreadPoolExecutor源码.学习源码的过程中,最恶心的其实就是几种状态的转换了,这也是ThreadPoolExecutor的核心.花了将近小一周才大致的弄明白ThreadPoolExecutor的机制,遂记录下来. 线程池有多重要##### 线程是一个程序员一定会涉及到的一个概念,但是线程的创建和切换都是代价比较大的.所以,我们有没有一个好的方案能做到线程的复用呢

java线程池ThreadPoolExecutor类使用详解

在<阿里巴巴java开发手册>中指出了线程资源必须通过线程池提供,不允许在应用中自行显示的创建线程,这样一方面是线程的创建更加规范,可以合理控制开辟线程的数量:另一方面线程的细节管理交给线程池处理,优化了资源的开销.而线程池不允许使用Executors去创建,而要通过ThreadPoolExecutor方式,这一方面是由于jdk中Executor框架虽然提供了如newFixedThreadPool().newSingleThreadExecutor().newCachedThreadPool(