网站首页 > java教程 正文
问:生产环境如何使用线程池?
答:参见文章最底部。
Java中最著名和最常用的线程池当然是Executors。
Executors提供了好几种工厂方法来创建线程池,内部都是用了ThreadPoolExecutor,配合着不同的BlockingQueue和RejectExceptionHandler一起工作。
Executors.newSingleThreadExecutor
ExecutorService executorService1 = Executors.newSingleThreadExecutor();
我们来看一下这个方法的源码:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
newSingleThreadExecutor会创建一个具有单一线程的线程池。也就是说创建的线程池中只会有一个线程。我们可以不断的往这个线程池里提交新的Runnable执行,但这些提交的Runnable只会串行的执行。
newSingleThreadExecutor配合着LinkedBlockingQueue一起工作。LinkedBlockingQueue是无界的阻塞队列,当不断有新任务(Runnable)提交时,可能抛出OutOfMemoryError。在日常使用的过程中需要注意这点。这也是我们不推荐在生产环境使用它的原因!
Executors.newFixedThreadPool
ExecutorService executorService2 = Executors.newFixedThreadPool(10);
newFixedThreadPool会创建一个具有固定数量线程的线程池。也就是说,创建的线程池中线程数量是固定值,在任何时候,这个线程池中都会那个固定数量的线程在运行。
我们来看一下源码:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
可以看到,它与newSingleThreadExecutor不用的地方就是ThreadPoolExecutor方法中的前两个参数。newFixedThreadPool把最小存活线程数量和最大线程数量都设成了nThreads,也就是参数值。同样的,newFixedThreadPool也是配合着LinkedBlockingQueue一起工作。当不断有新任务(Runnable)提交时,可能抛出OutOfMemoryError。这同样也是我们不推荐在生产环境使用它的原因!
注意:
- newFixedThreadPool是固定大小的线程池;
- corePoolSize和maximunPoolSize都为用户设定的线程数量nThreads;
- keepAliveTime为0,意味着一旦有多余的空闲线程,就会被立即停止掉,但这里keepAliveTime无效;
- 阻塞队列采用了LinkedBlockingQueue,是一个无界队列;
- 由于阻塞队列是一个无界队列,因此永远不可能拒绝任务;由于采用了无界队列,实际线程数量将永远维持在nThreads,因此maximumPoolSize和keepAliveTime将无效。
Executors.newScheduledThreadPool
ExecutorService executorService3 = Executors.newScheduledThreadPool(10);
这是一个调度线程池,支持定时及周期性任务执行。
用法如下:
延迟3秒执行
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(int corePoolSize);
// 3秒后输出schedule run
scheduledExecutorService.schedule(new Runnable() {
@Override
public void run() {
log.warn("schedule run");
}
}, 3, TimeUnit.SECONDS);
周期性执行
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
// 每隔3秒输出schedule run
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
log.warn("schedule run");
}
}, 0, 3, TimeUnit.SECONDS);
来看一下newScheduledThreadPool的源码:
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
看一下super方法调用的是什么:
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler);
}
newScheduledThreadPool源码中的ScheduledThreadPoolExecutor类实现了ScheduledExecutorService接口。maximumPoolSize被设置成了Integer.MAX_VALUE。因此,当不断有新任务(Runnable)提交时,如果阻塞队列(delayedWorkQueue)满了,会不断创建新线程来执行任务,可能抛出OutOfMemoryError。这同样也是我们不推荐在生产环境使用它的原因!
Executors.newCachedThreadPool
ExecutorService executorService4 = Executors.newCachedThreadPool();
这将会创建一个具备缓冲能力的线程池。
来看一下源码:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
可以看到,ThreadPoolExecutor构造函数中的maximumPoolSize参数被设置成了Integer.MAX_VALUE,当不断有新任务提交(Runnable)时,如果阻塞队列满了,会不断创建新线程来执行任务(Runnable),可能抛出OutOfMemoryError。这同样也是我们不推荐在生产环境使用它的原因!
注意:
- newCachedThreadPool是一个可以无限扩大的线程池;
- newCachedThreadPool比较适合处理执行时间比较小的任务;
- newCachedThreadPool的corePoolSize为0,maximumPoolSize为无限大,意味着线程数量可以无限大;
- keepAliveTime为60S,意味着线程空闲时间超过60S就会被销毁;
- 采用SynchronousQueue装等待的任务,这个阻塞队列没有存储空间,这意味着只要有请求到来,就必须要找到一条工作线程处理他,如果当前没有空闲的线程,那么就会再创建一条新的线程。
生产环境使用线程池?
问:既然Executors线程池中的方法都不推荐在生产环境使用,那么我们生产环境该怎么创建线程池?
答:可以看考《阿里巴巴Java开发手册》。
私信“阿里巴巴”,即可获得《阿里巴巴Java开发手册》!
私信“阿里巴巴”,即可获得《阿里巴巴Java开发手册》!
私信“阿里巴巴”,即可获得《阿里巴巴Java开发手册》!
猜你喜欢
- 2024-09-16 java-线程池详解(java线程池入门)
- 2024-09-16 线程进阶:实战应用之Java线程池全面解析
- 2024-09-16 Java开发之高并发必备篇(七)——线程池
- 2024-09-16 Java-线程池专题(什么是线程池,如何使用,为什么要用)
- 2024-09-16 Java的四种线程池的使用,以及自定义线程工厂
- 2024-09-16 探索JAVA并发 - 线程池详解(java多线程并发编程 线程池)
- 2024-09-16 Java线程池的概念及使用(java 线程池原理详解)
- 2024-09-16 Java线程池核心(十一):线程池状态
- 2024-09-16 Java 线程池(java线程池原理)
- 2024-09-16 技术进阶:Java线程池的使用和原理分析
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)