[改善Java代码]适时选择不同的线程池来实现
Java的线程池实现从最根本上来说只有两个:ThreadPoolExecutor类和ScheduledThreadPoolExecutor类,这两个类还是父子关系,但是Java为了简化并行计算,还提供了一个Executors的静态类,它可以直接生成多种不同的线程池执行器,比如单线程执行器,带缓冲功能的执行器等.但归根结底还是使ThreadPoolExecutor类或ScheduledThreadPoolExecutor类的封装类.
为了了解这些个执行器,看ThreadPoolExecutor类,其中它复杂的构造函数可以很好的解释该线程池的作用:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
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;
}
上面第二个是ThreadPoolExecutor最完整的构造函数,其他的构造函数都是引用该构造函数实现的.
1.corePoolSize:最小线程数
线程池启动后,池中保持线程的最小数量,需要说明的是线程数量是逐步到达corePoolSize值的,例如corePoolSize被设置为10,而任务数量只有5,则线程池中最多启动5个线程,而不是一次性启动10个线程.
2.maximumPoolSize:最大线程数量
这是池中能够荣达的最大线程数,如果超出,则使用RejectedExecutionHandler拒绝策略处理.
3.keepAliveTime:线程最大生命期
这个生命周期有两个约束条件:一是该参数针对的是超过corePoolSize数量的线程,二是处于非运行状态的线程.
如果corePoolSize为10,maximumPoolSize为20,此时线程池中有15个线程在运行,一段时间后,其中有3个线程处于等待状态的时间超过了keepAliveTime指定的时间,则结束这3个线程,
此时线程中则还有12个线程正在运行.
4.unit:时间单位
这是keepAliveTime的时间单位,可以是纳秒,毫秒,秒,分钟等选项
5.workQueue:任务队列
当线程池中的线程都处于运行状态,而此时任务数量继续增加,则需要有一个容器来容纳这些任务,这就是任务队列.
6.threadFactory:线程工厂
定义如何启动一个线程,可以设置线程名称,并且可以确认是否是后台线程等.
7.handler:拒绝任务处理器
由于超出线程数量和任务队列容量而对继续增加的任务进行处理的程序.
Executors提供的几个创建线程池的便捷方法:
1.newSingleThreadExecutors:单线程池
顾名思义就是一个池中就只有一个线程,该线程用不超时,而且由于是一个线程,当有多个任务需要处理时,会将它们放置到一个无界阻塞队列中逐个处理.
/**
* Creates an Executor that uses a single worker thread operating
* off an unbounded queue. (Note however that if this single
* thread terminates due to a failure during execution prior to
* shutdown, a new one will take its place if needed to execute
* subsequent tasks.) Tasks are guaranteed to execute
* sequentially, and no more than one task will be active at any
* given time. Unlike the otherwise equivalent
* <tt>newFixedThreadPool(1)</tt> the returned executor is
* guaranteed not to be reconfigurable to use additional threads.
*
* @return the newly created single-threaded Executor
*/
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
改方法的使用代码如下:
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future; public class Client {
public static void main(String[] args) throws Exception {
//创建单线程执行器
ExecutorService es = Executors.newSingleThreadExecutor();
//执行一个任务
Future<String> future = es.submit(new Callable<String>() {
public String call() throws Exception {
return "";
}
});
//获得任务执行后的返回值
System.out.println("返回值:" + future.get());
//关闭执行器
es.shutdown();
}
}
2.newCachedThreadPool:缓冲功能的线程池
建立了一个线程池,该线程池的数量是没有限制的(不能超过Integer的最大值),新增一个任务就有一个线程处理,或者复用之前的空闲线程,或者启动一个新的线程.但是一旦一个线程在60秒内一直是处于等待状态时,也就是1分钟没有事情可做,就会被终止,源代码:
/**
* Creates a thread pool that creates new threads as needed, but
* will reuse previously constructed threads when they are
* available. These pools will typically improve the performance
* of programs that execute many short-lived asynchronous tasks.
* Calls to <tt>execute</tt> will reuse previously constructed
* threads if available. If no existing thread is available, a new
* thread will be created and added to the pool. Threads that have
* not been used for sixty seconds are terminated and removed from
* the cache. Thus, a pool that remains idle for long enough will
* not consume any resources. Note that pools with similar
* properties but different details (for example, timeout parameters)
* may be created using {@link ThreadPoolExecutor} constructors.
*
* @return the newly created thread pool
*/
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
这里需要说明的是,任务队列使用了同步阻塞队列,这意味着向队列中加入一个元素,即可唤醒一个线程(新创建的线程或复用池中空闲线程)来处理.这种队列已经没有队列深度的概念了.
3.newFixedThreadPool:固定线程数量的线程池
在初始化时已经决定了线程的最大数量,若任务添加的能力超出线程处理能力,则建立阻塞队列容纳多余的任务,源代码:
/**
* Creates a thread pool that reuses a fixed number of threads
* operating off a shared unbounded queue. At any point, at most
* <tt>nThreads</tt> threads will be active processing tasks.
* If additional tasks are submitted when all threads are active,
* they will wait in the queue until a thread is available.
* If any thread terminates due to a failure during execution
* prior to shutdown, a new one will take its place if needed to
* execute subsequent tasks. The threads in the pool will exist
* until it is explicitly {@link ExecutorService#shutdown shutdown}.
*
* @param nThreads the number of threads in the pool
* @return the newly created thread pool
* @throws IllegalArgumentException if {@code nThreads <= 0}
*/
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
上面返回是一个ThreadPoolExector,它的corePoolSize和maximumPoolSize是相等的,也就是说最大线程数是nThreads.
如果任务增长非常快,超过了LinkedBlockingQueue的最大容量(Integer最大值),那此时会如何处理呢?
会按照ThreadPoolExecutor默认的拒绝策略(默认是DiscardPolicy,直接丢弃)来处理.
以上三种线程池执行器都是ThreadPoolExecutor的简化版,目的是帮助开发人员屏蔽过多的线程细节,简化多线程开发.
可以这样比喻:newSingleTheadExecutor,newCachedThreadPool,newFixedThreadPool是线程池的简化版,而ThreadPoolExecutor是旗舰版.
[改善Java代码]适时选择不同的线程池来实现的更多相关文章
- [改善Java代码]适时选择getDeclaredxxx和getxxx
Java的Class类提供了很多的getDeclaredxxx方法和getxxx方法,例如getDeclaredmethod和getMethod成对出现,getDeclaredConstructors ...
- [改善Java代码]优先选择线程池
在Java1.5之前,实现多线程编程比较麻烦,需要自己启动线程,并关注同步资源,防止线程死锁等问题,在1.5版本之后引入了并行计算框架,大大简化了多线程开发. 我们知道线程有5个状态:新建状态(New ...
- [改善Java代码]自由选择字符串拼接方法
对一个字符串拼接有三种方法:加号,contact方法,StringBuffer或者StringBuilder的append方法,其中加号是最常用的.其他两种方式偶尔会出现在一些开源项目中,那么这三者有 ...
- [Java并发编程(二)] 线程池 FixedThreadPool、CachedThreadPool、ForkJoinPool?为后台任务选择合适的 Java executors
[Java并发编程(二)] 线程池 FixedThreadPool.CachedThreadPool.ForkJoinPool?为后台任务选择合适的 Java executors ... 摘要 Jav ...
- 【Java TCP/IP Socket】基于线程池的TCP服务器(含代码)
了解线程池 在http://blog.csdn.net/ns_code/article/details/14105457(读书笔记一:TCP Socket)这篇博文中,服务器端采用的实现方式是:一个客 ...
- Java通过Executors提供四种线程池
http://cuisuqiang.iteye.com/blog/2019372 Java通过Executors提供四种线程池,分别为:newCachedThreadPool创建一个可缓存线程池,如果 ...
- 《java学习三》并发编程 -------线程池原理剖析
阻塞队列与非阻塞队 阻塞队列与普通队列的区别在于,当队列是空的时,从队列中获取元素的操作将会被阻塞,或者当队列是满时,往队列里添加元素的操作会被阻塞.试图从空的阻塞队列中获取元素的线程将会被阻塞,直到 ...
- java多线程系类:JUC线程池:03之线程池原理(二)(转)
概要 在前面一章"Java多线程系列--"JUC线程池"02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明.内容包 ...
- Java 并发编程——Executor框架和线程池原理
Eexecutor作为灵活且强大的异步执行框架,其支持多种不同类型的任务执行策略,提供了一种标准的方法将任务的提交过程和执行过程解耦开发,基于生产者-消费者模式,其提交任务的线程相当于生产者,执行任务 ...
随机推荐
- Hibernate关联关系之——单向n-1
1 .单向 n-1 关联只需从n的一端可以访问1的一端 2.域模型: 从Order到Customer的多对一单向关联需要在Order类中定义一个Customer属性,而在Customer类中无需定义存 ...
- Java设计模式系列之中介者模式
中介者模式(Mediator)的定义 用一个中介对象来封装一系列的对象交互.中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互. 中介者模式(Mediator)的适 ...
- HDU 2425 DNA repair (AC自动机+DP)
DNA repair Time Limit: 5000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- TextKit学习(三)NSTextStorage,NSLayoutManager,NSTextContainer和UITextView
先上一张图: 这是使用UITextView时用到的iOS7新增加的类:NSTextContainer.NSLayoutManager.NSTextStorage及其相互关系: 这三个新出的类还没有在官 ...
- 一款多浏览器兼容的javascript多级下拉菜单
这个多级下拉菜单的脚本大小不到2K,带有动画效果,可以方便地支持多个实例,并且能良好兼容WordPress系统wp_list_cats和wp_list_pages生成的多级列表.要初始化一个菜单,只需 ...
- MVC生命周期
MVC之前的那点事儿系列 转自:http://www.cnblogs.com/TomXu/p/3756794.html http://www.cnblogs.com/Joans/archive/201 ...
- 再次理解JavaScript原型链和匿名函数
<!--------------------------------------------- 1.演示匿名加载 2.js单进程执行流 3.原型链理解 a.__proto__:属性每个对象都有 ...
- 如何克隆路由器MAC地址,怎么操作?
路由器的“MAC地址克隆”的意思是: 不克隆时,从外网访问你的电脑,获得的MAC地址是路由器的mac地址. 克隆后,从外网访问你的电脑,获得的MAC地址是你电脑网卡的mac地址. 实用举例如下: 中国 ...
- Java系的大网站架构-LinkedIn和淘宝
国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html 内部邀请码:C8E245J (不写邀请码,没有现金送) 国 ...
- TChromeTabs 优化改进
已知未解决问题 全屏时当窗体失去焦点,则会显示出未绘制完成的原标题栏(Fixed): 处于非 Areo 效果下时,窗体标题栏需要定制. 新增按钮上的 Hint 提示后再移至其它标签,将无法重新提示. ...