ThreadPool用法与优势
1. 线程池的优点:
合理利用线程池能够带来三个好处。第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。第三:提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。但是要做到合理的利用线程池,必须对其原理了如指掌。
2. 线程池框架Executor:
java中的线程池是通过Executor框架实现的,ThreadPoolExecutor:线程池的具体实现类,一般用的各种线程池都是基于这个类实现的。构造方法如下:
参数介绍:
corePoolSize:线程池的核心线程数,线程池中运行的线程数永远不会超过 corePoolSize 个,默认情况下可以一直存活。
keepAliveTime: 默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize,即当线程池中的线程数大于corePoolSize时,如果一个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。但是如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0;所以如果任务很多,并且每个任务执行的时间比较短,可以调大这个时间,提高线程的利用率。
maximumPoolSize:线程池允许的最大线程数。如果队列满了,并且已创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务。值得注意的是如果使用了无界的任务队列这个参数就没什么效果。
unit :表示 keepAliveTime 的单位;可选的单位有天,小时,分钟,毫秒。微秒,纳秒等。
workQueue:表示存放任务的阻塞队列。
BlockingQueue:阻塞队列(BlockingQueue)是java.util.concurrent下的主要用来控制线程同步的工具。如果BlockQueue是空的,从BlockingQueue取东西的操作将会被阻断进入等待状态,直到BlockingQueue进了东西才会被唤醒。同样,如果BlockingQueue是满的,任何试图往里存东西的操作也会被阻断进入等待状态,直到BlockingQueue里有空间才会被唤醒继续操作。
阻塞队列常用于生产者和消费者的场景,生产者是往队列里添加元素的线程,消费者是从队列里拿元素的线程。阻塞队列就是生产者存放元素的容器,而消费者也只从容器里拿元素。具体的实现类有LinkedBlockingQueue,ArrayBlockingQueued等。ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。synchronousQueue:这个队列比较特殊,它不会保存提交的任务,而是将直接新建一个线程来执行新来的任务
3. 线程池的线程程初始化
默认情况下,创建线程池之后,线程池中是没有线程的,需要提交任务之后才会创建线程。在实际中如果需要线程池创建之后立即创建线程,可以通过以下两个方法办到:
prestartCoreThread():初始化一个核心线程;
prestartAllCoreThreads():初始化所有核心线程
4. worker类
在ThreadPoolExecutor主要Worker类来控制线程的复用。线程池创建线程时,会将线程封装成工作线程Worker,Worker在执行完任务后,还会无限循环获取工作队列里的任务来执行。
5. 线程池的工作过程
线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列里面有任务,线程池也不会马上执行它们。当提交一个新任务到线程池时,线程池会做如下判断:
如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务;
如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列;
如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要创建非核心线程立刻运行这个任务;
如果队列满了,而且正在运行的线程数量大于或等于 maximumPoolSize,那么会采取任务拒绝策略,如下:
当一个线程完成任务时,它会从队列中取下一个任务来执行。
当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运行的线程数大于corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它最终会收缩到corePoolSize 的大小。
6. 线程池的关闭
ThreadPoolExecutor提供了两个方法,用于线程池的关闭,分别是shutdown()和shutdownNow(),其中:shutdown():不会立即终止线程池,而是要等所有任务缓存队列中的任务都执行完后才终止,但再也不会接受新的任务。shutdownNow():立即终止线程池,并尝试打断正在执行的任务,并且清空任务缓存队列,返回尚未执行的任务。
7. 线程池容量的动态调整
ThreadPoolExecutor提供了动态调整线程池容量大小的方法:setCorePoolSize()和setMaximumPoolSize(),
setCorePoolSize:设置核心池大小
setMaximumPoolSize:设置线程池最大能创建的线程数目大小
当上述参数从小变大时,ThreadPoolExecutor进行线程赋值,还可能立即创建新的线程来执行任务。
8. 几种类型的线程池
1) SingleThreadExecutor:单个后台线程 (其缓冲队列是LinkedBlockingQueue,无界的)
创建一个单线程的线程池。这个线程池只有一个核心线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
举例子:比如一个村里只有一口井,每次只能一个人打水,先来先打。
2) FixedThreadPool:只有核心线程的线程池,大小固定(其缓冲队列是LinkedBlockingQueue,无界的) 。
创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。
举例子:村里有3口井,大家排队打井水,可以无数人排队,井只有3口,每次最多只能有3个人打井水。没人打水时,3口井也在那里。由于线程不会回收,FixThreadPool会更快地响应外界请求,这也很容易理解,就好像有人突然想打井水,井不是现用现建的。
3) CachedThreadPool:无界线程池,可以进行自动线程回收。(其缓冲队列是SynchronousQueue,一个是缓冲区为1的阻塞队列
如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。
举个例子:CachedThreadPool就像是一堆人去一个很大的咖啡馆喝咖啡,里面服务员也很多,随时去,随时都可以喝到咖啡。但是为了响应国家的“光盘行动”,一个人喝剩下的咖啡会被保留60秒,供新来的客人使用,哈哈哈哈哈,好恶心啊。如果你运气好,没有剩下的咖啡,你会得到一杯新咖啡。但是以前客人剩下的咖啡超过60秒,就变质了,会被服务员回收掉。比较适合执行大量的耗时较少的任务。喝咖啡人挺多的,喝的时间也不长。
4)ScheduledThreadPool:核心线程池固定,大小无限的线程池。核心线程数固定,非核心线程(闲着没活干会被立即回收)数没有限制。此线程池支持定时以及周期性执行任务的需求。
ThreadPool用法与优势的更多相关文章
- [Java面经]干货整理, Java面试题(覆盖Java基础,Java高级,JavaEE,数据库,设计模式等)
如若转载请注明出处: http://www.cnblogs.com/wang-meng/p/5898837.html 谢谢.上一篇发了一个找工作的面经, 找工作不宜, 希望这一篇的内容能够帮助到大 ...
- BAT的面试经验_摘抄
一.心态 心态很重要! 心态很重要! 心态很重要! 重要的事情说三遍,这一点我觉得是必须放到前面来讲. 找工作之前,有一点你必须清楚,就是找工作是一件看缘分的事情,不是你很牛逼,你就一定能进你想进的公 ...
- Android复习指南
基础无外乎几部分:语言(C/C++或java),操作系统,TCP/IP,数据结构与算法,再加上你所熟悉的领域.这里面其实有很多东西,各大面试宝典都有列举. 在这只列举了Android客户端所需要的和我 ...
- 基础1 JavaSe基础
JavaSe基础 1. 九种基本数据类型的大小,以及他们的封装类 boolean 无明确指定 Boolean char 16bits Character byte 8bits Byte short 1 ...
- j2SE基回顾(一)
1. 九种基本数据类型的大小,以及他们的封装类. 2. Switch能否用string做参数? 3. equals与==的区别. 4. Object有哪些公用方法? Object是所有类的父类,任何类 ...
- Java 面试题:百度前200页都在这里了
基本概念 操作系统中 heap 和 stack 的区别 什么是基于注解的切面实现 什么是 对象/关系 映射集成模块 什么是 Java 的反射机制 什么是 ACID BS与CS的联系与区别 Cookie ...
- 关于一些基础的Java问题的解答(六)
26. ThreadPool用法与优势 ThreadPool即线程池,它是JDK1.5引入的Concurrent包中用于处理并发编程的工具.使用线程池有如下好处: 降低资源消耗:通过重复利用已创建的线 ...
- Java面经
转载:[Java面经]干货整理, Java面试题(覆盖Java基础,Java高级,JavaEE,数据库,设计模式等) 原文:http://www.cnblogs.com/wang-meng/p/5 ...
- 史上最全java面试题
基本概念 操作系统中 heap 和 stack 的区别 什么是基于注解的切面实现 什么是 对象/关系 映射集成模块 什么是 Java 的反射机制 什么是 ACID BS与CS的联系与区别 Cookie ...
随机推荐
- Azure中配置和发布 Nginx docker到互联网
当Azure build一个Niginx docker 镜像时,无法通过浏览器访问这个镜像,于是想到了把这个网站发布到互联网中,这样就能验证网站是否正确. 本问跳过如何创建Azure Ubantu的虚 ...
- softmax函数笔记
- node-images Windows 64-bit with Unsupported runtime 错误解决办法 及 node 历史版本下载
在做项目的时候下载的最新的10.16[2019.6.12]版本,出现了模块不兼容的问题[node-images]. 在git上发现了相同问题 https://github.com/zhangyuanw ...
- python 模块使用
模块使用 定义:模块就像一个工具包一样,里面有很多工具(函数.类),使用时需要通过import导入. 分类: 标准库:random.sys.os.time 第三方:就是好人已经写好的特定功能的模块,你 ...
- 转载: Ubuntu 在命令下,安装中文环境的方法。
转载: https://blog.csdn.net/zhangchao19890805/article/details/52743380 安装英文版ubuntu,在打开含有中文字符文件时会乱码,有需要 ...
- Delphi SpeedButton组件
- 第十篇.1、python并发编程之多进程理论部分
一 什么是进程 进程:正在进行的一个过程或者说一个任务.而负责执行任务则是cpu. 举例(单核+多道,实现多个进程的并发执行): egon在一个时间段内有很多任务要做:python备课的任务,写书的任 ...
- 谷歌对Intel 10nm进度不满
Intel 在 10nm 处理器上的节奏可谓是“龟速”,一拖三年,且目前大规模发货的 10nm Ice Lake 处理器仅仅是移动平台低电压,桌面要到明年. 表面波澜不惊,实际上却暗流涌动. 首先是 ...
- python-迭代器与生成器2
python-迭代器与生成器2 def fib(max): n,a,b=0,0,1 while n<max: #print(b) yield b a,b=b,a+b #t=(b,a+b) 是一个 ...
- apache笔记
apache笔记 一)两种工作模式 Prefork和worker prefork模式: 一个进程响应一个请求 主进程生成多个工作进程,由工作进程一对一的去响应客户端的请求 过程: 1)用户空间有个具有 ...