java多线程中,线程池的最上层接口是Executor,ExecutorService实现了Executor,是真正的管理线程池的接口,ThreadPoolExecutor间接继承了ExecutorService,提供了多种具体的线程池实现,在日常开发中一般直接使用Executors工具类提供的几种常用ThreadPoolExecutor,下面详细介绍下ThreadPoolExecutor.

ThreadPoolExecutor基本参数

ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 1000L, 
TimeUnit.SECONDS,
new LinkedBlockingDeque<Runnable>(20),
new ThreadPoolExecutor.CallerRunsPolicy());

  corePoolSize:核心线程数的大小,也有说线程池最小线程数

  maximumPoolSize:线程池最大线程数

  keepAliveTime:当没有任务执行时,线程能存活的最大时间,这里说的线程是指大于corePoolSize,小于maximumPoolSize的线程

  timeunit:keepAliveTime的时间单位

  workQueue:用来存放task的堵塞队列,队列的选择和size的大小对线程池的运行有直接影响,默认有几种实现,后面详说.

  rejectHandler:拒绝策略,当队列已满并且线程数达到maximumPoolSize时,再有新任务进来时会执行拒绝策略,默认集中实现,后面详说.

ThreadPool模型初始化

  ThreadPool线程池初始化时,不会创建corePoolSIze的线程,也就是说在没有task进来的时候,线程池是空的,当有task进来的时候,开始创建线程,并且线程执行完task后不会销毁,而是驻留内存,直至达到corePoolSize,那什么时候线程数会再度增加达到maxPoolSize呢,这就取决于存放task的queue的size了,如果task的数量一直不超过指定的size那么就不会创建新的线程出来,反之,则会创建新的线程去执行task,那么新建出来的线程执行完task也会一直驻留内存吗?答案是不会,这时候就要看设置的keepAliveTime,如果在超过了这个时间后还是没有task去使用这个线程,则线程销毁,直至线程数等于corePoolSize.那么如果queue也满了,线程数也达到maxPoolsize,这时候怎么办呢,这时rejectHandler就会发挥作用,会根据我们指定的拒绝策略去处理这种场景.

Executors的几个默认实现

public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()));
}

  1.newSingleThreadExecutor:创建一个单线程的线程池.如果这个线程在执行霍城中因为异常结束,则会创建一个新的线程来代替它,这个线程池保证所有任务的执行顺序是按照任务提交顺序进行.

 public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
}

  2.newFixedThreadPool:创建一个固定大小的线程池.看源码可知,该实现创建了一个corePoolSize等于maximumPoolSize的线程池.

public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());
}

  3.newCachedThreadPool:创建一个可缓存的线程池.看源码可知corePoolSize=0,即当线程空闲时会被回收,当线程忙碌时又可以"源源不断"的创建新线程来执行task.

  默认线程池实现中还有ScheduledThreadPoolExecutor,可以实现定时的一些功能,可用来代替Timer或者TimeTask.这里不再展开说.

线程池的堵塞队列

  如何选择线程池的堵塞队列,取决我们的业务场景,即我们希望以一种什么样的排队策略来处理任务.排队通常有3种策略,对应下面几种queue.

  直接提交(SynchronousQueue):不排队,这个队列不会存储task,会将调用方的task直接提交给线程,指定了SynchronousQueue的线程池通常会把maximumPoolSize配置的比较大,否则可能会导致没有足够的线程来执行task,而导致task无法放入queue而被丢弃或拒绝.

  有界队列(ArrayBlockingQueue):通过指定ArrayBlockingQueue的size可以设置队列的最大存储个数,当超出这个个数时就会新建线程去执行task直至线程数达到maximumPoolSize,有界队列size的设置和maximumPoolSize的设置息息相关.会影响CPU的使用率以及系统吞吐量.

  无界队列(不设定size的LinkedBlockingQueue):当线程数达到corePoolSize的仍有task进来时,会源源不断进队列,由于无解,maximumPoolSize参数会失效,线程数最大只能达到corPoolSize.

线程池拒绝策略

  CallerRunsPolicy:使用调用方的线程来执行task,通常情况下调用方线程就是指我们所说的主线程,这样的好处是不会丢弃task,但是缺点也很明显,使用这种策略会堵塞主线程,进而拖慢主线程的整个调用时长.而基于此,该策略同时也减缓了新的task提交进来的速度(因为主线程本来只需要用来提交task就好了,现在直接去执行task,后面的task进来的速度就慢了).

  AbortPolicy:这个策略简单粗暴,直接抛出异常,不跟你多BB,需要注意的是,这个是jdk的默认策略.

  DiscardPolicy:这个和AbortPolicy差不多,区别是不会抛出异常,直接丢弃.

  DiscardOldestPolicy:这也是一种丢弃策略,不过和上面的DiscardPolicy刚好相反,她丢弃的不是新进来的task而是在堵塞队列中存在时间最久的那个task,即丢弃最早进入队列并且还没有被执行的task.

多线程学习笔记-深入理解ThreadPoolExecutor的更多相关文章

  1. java多线程学习笔记——详细

    一.线程类  1.新建状态(New):新创建了一个线程对象.        2.就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法.该状态的线程位于可运行线程池中, ...

  2. 多线程学习笔记九之ThreadLocal

    目录 多线程学习笔记九之ThreadLocal 简介 类结构 源码分析 ThreadLocalMap set(T value) get() remove() 为什么ThreadLocalMap的键是W ...

  3. JAVA多线程学习笔记(1)

    JAVA多线程学习笔记(1) 由于笔者使用markdown格式书写,后续copy到blog可能存在格式不美观的问题,本文的.mk文件已经上传到个人的github,会进行同步更新.github传送门 一 ...

  4. java进阶-多线程学习笔记

    多线程学习笔记 1.什么是线程 操作系统中 打开一个程序就是一个进程 一个进程可以创建多个线程 现在系统中 系统调度的最小单元是线程 2.多线程有什么用? 发挥多核CPU的优势 如果使用多线程 将计算 ...

  5. 微信小程序开发:学习笔记[7]——理解小程序的宿主环境

    微信小程序开发:学习笔记[7]——理解小程序的宿主环境 渲染层与逻辑层 小程序的运行环境分成渲染层和逻辑层. 程序构造器

  6. Java多线程学习笔记(一)——多线程实现和安全问题

    1. 线程.进程.多线程: 进程是正在执行的程序,线程是进程中的代码执行,多线程就是在一个进程中有多个线程同时执行不同的任务,就像QQ,既可以开视频,又可以同时打字聊天. 2.线程的特点: 1.运行任 ...

  7. java 多线程学习笔记

    这篇文章主要是个人的学习笔记,是以例子来驱动的,加深自己对多线程的理解. 一:实现多线程的两种方法 1.继承Thread class MyThread1 extends Thread{ public ...

  8. Java多线程学习笔记--生产消费者模式

    实际开发中,我们经常会接触到生产消费者模型,如:Android的Looper相应handler处理UI操作,Socket通信的响应过程.数据缓冲区在文件读写应用等.强大的模型框架,鉴于本人水平有限目前 ...

  9. Java多线程学习笔记

    进程:正在执行中的程序,其实是应用程序在内存中运行的那片空间.(只负责空间分配) 线程:进程中的一个执行单元,负责进程汇总的程序的运行,一个进程当中至少要有一个线程. 多线程:一个进程中时可以有多个线 ...

随机推荐

  1. Linux基础知识第四讲,文件内容命令

    目录 一丶常用命令 1.cat命令演示以及常用选项 2.grep 搜索命令的使用 3.echo 以及 重定向的使用 4.管道概念 一丶常用命令 序号 命令 对应英文 作用 01 cat 文件名 con ...

  2. Java开发知识之Java的集成开发环境

    Java开发知识之Java的集成开发环境 一丶Eclipse 开发环境 Eclipse是IBM公司花了4000万美金开发的一个集成开发环境.是一个免费开源的. 下载官网: http://www.ecl ...

  3. PE知识复习之PE新增节

    PE知识复习之PE新增节 一丶为什么新增节.以及新增节的步骤 例如前几讲.我们的PE文件在空白区可以添加代码.但是这样是由一个弊端的.因为你的空白区节属性可能是只读的不能执行.如果你修改了属性.那么程 ...

  4. 从0到1,了解NLP中的文本相似度

    本文由云+社区发表 作者:netkiddy 导语 AI在2018年应该是互联网界最火的名词,没有之一.时间来到了9102年,也是项目相关,涉及到了一些AI写作相关的功能,为客户生成一些素材文章.但是, ...

  5. Spark框架详解

    一.引言 作者:Albert陈凯链接:https://www.jianshu.com/p/f3181afec605來源:简书 Introduction 本文主要讨论 Apache Spark 的设计与 ...

  6. 第44章 添加新协议 - Identity Server 4 中文文档(v1.0.0)

    除了对OpenID Connect和OAuth 2.0的内置支持之外,IdentityServer4还允许添加对其他协议的支持. 您可以将这些附加协议端点添加为中间件或使用例如MVC控制器.在这两种情 ...

  7. 安装VS时,双击setup.exe后界面一闪而过的问题

    问题:安装VS时,双击setup.exe界面一闪而过的问题 解决: 百度后说需要到"控制面板/添加和管理程序"关闭系统自带的netframework3.x及以上版本. 1.查看所有 ...

  8. Mac下如何用SSH连接远程Linux服务器

     终端命令 a).打开Mac的命令终端 b).输入ssh -p 22 root@102.210.86.213 它会提示你输入密码,输入正确的密码之后,你就发现已经登陆成功了.(22: 端口号 root ...

  9. [PHP] 按位与& 或| 异或^ 的日常使用

    按位与:0&0=0; 0&1=0; 1&0=0; 1&1=1;按位或:0|0=0: 0|1=1: 1|0=1: 1|1=1;按位异或,在或的基础上1 1也为0:0^0= ...

  10. Java开发笔记(二十九)大整数BigInteger

    早期的编程语言为了节约计算机的内存,给数字变量定义了各种存储规格的数值类型,比如字节型byte只占用一个字节大小,短整型short占用两个字节大小,整型int占用四个字节大小,长整型long占用八个字 ...