线程池:Execution框架
每问题每线程:在于它没有对已创建线程的数量进行任何限制,除非对客户端能够抛出的请求速率进行限制。
下边 有些图片看不到,清看原地址:http://www.360doc.com/content/10/1027/21/495229_64583490.shtml
无限制创建线程的缺点:
1.线程生命周期的开销:线程的创建和关闭并不是“免费的”。
2.资源消耗量:活动线程会消耗系统资源,尤其是内存。
3.稳定性。
1 线程池(Thread Pool)
在java中,任务执行的首要抽象不是Thread,而是Executor。
public interface Executor {
/**
* Executor只是一个简单的接口,但是他却为一个灵活而且强大的框架创造了基础。
*/
void execute(Runnable command);
}
这个框架可以用于异步任务执行,而且支持很多不同类型的任务执行策略。它还为任务提交和任务执行之间的解耦提供了标准的方法。另外,还提供了对生命周期的支持以及钩子函数,可以添加诸如统计收集、应用程序管理机制和监视器等扩展。
1.1 创建/关闭
1.newCachedThreadPool
创建可缓存的线程池,多的话回收,少的话增加,没有限制
N2.ewFixedThreadPool(int nThreads)
创建定长的线程池,每提交一个任务就创建一个线程,直到最大。如果某个以外终止,会补充一个新的
3.newScheduledThreadPool(int corePoolSize)
定长线程池,而且支持定时的以及周期性的任务执行。相当于timer。
4.newSingleThreadExecutor()
单线程化的executor,只创建唯一的工作线程来之心吧任务。如果它意外结束,会有另一个取代它。它会保证任务队列所规定的顺序执行。
5.newSingleThreadScheduledExecutor()
创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行。
private static final Executor
exec=Executors.newFixedThreadPool(100);
ServerSocket socket=new ServerSocket(80);
while(true){
final Socket connection=socket.accept();
Runnable task=new Runnable(){
public void run(){
handleRequest(connection);
}
};
exec.execute(exec);
}
1.2 ExecutorService
线程如果无法正常关闭,则会阻止JVM的结束。线程池中的任务,可能已经完成,可能正在运行,其他还有在队列中等待执行。关闭的时候可能平缓的关闭,到唐突的关闭(拔掉电源)。为了解决生命周期的问题,ExecutorService扩展了Executor,并且添加了一些用于生命周期管理的方法。
public interface ExecutorService extends Executor {
void shutdown();
List<Runnable> shutdownNow();
boolean isShutdown();
boolean isTerminated();
boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException;
。。。。。
}
可以关闭 ExecutorService,这将导致其拒绝新任务。提供两个方法来关闭 ExecutorService。shutdown() 方法在终止前允许执行以前提交的任务,而 shutdownNow() 方法阻止等待任务启动并试图停止当前正在执行的任务。在终止时,执行程序没有任务在执行,也没有任务在等待执行,并且无法提交新任务。应该关闭未使用的 ExecutorService 以允许回收其资源。
exec.shutdown();
1.3 延迟,并且周期性的任务,newScheduledThreadPool
Timer的问题:
1.只能创建唯一的线程来执行所有timer任务。
2.如果一个timerTask很耗时,会导致其他TimerTask的时效准确性出问题
3.如果TimerTask抛出未检查的异常,Timer将会产生无法预料的行为。Timer不会重新恢复。另外一个Timer中的Task出现异常以后,后面再给这个Timer的任务也将会无法执行。
1.4 结合DelayQueue
如果要自己构建调度服务,那还可以考虑使用DelayQueue,它里面的每个对象低耦合一个延迟时间有关联,只有过期以后,DelayQueue才能让你执行take操作获取元素。那么当它里面的对象是FutureTask的时候,就可以构成一个简单的调度队列。
2 Runnable和Future、CallBack
2.1 Runnable
Executor框架让定制一个执行策略变得简单,不过想要使用它,你的任务还必须实现Runnable接口。在许多服务器请求中,都存在一个情况,那就是:单一的客户请求。它能执行一些简单的任务,但是他不能返回一个值或者抛出受检查的异常。
2.2 Callback
很多任务都会引起计算延迟,包括执行数据库查询、从网络上获取资源、进行复杂的计算。这些任务Callback抽象更好。它也可以被Executor框架执行

Executors包含很多静态方法,可以吧Runnable和PrivilegedAction封装为Callable。
2.3 FutureTask
Runnable和Callable描述的是抽象的计算性任务,这些任务通常是有限的,他们有开始,而且最终会结束。
一个Executor执行的任务有4个周期,创建、提交、开始、完成。由于任务的执行会花很长时间,我们也希望可以取消任务。
Future描述了任务的生命周期,并提供了相关的方法来获得任务的结果、取消任务以及检验任务是否完成还是取消。对应的isDone、isCancelled() 方法,它不能后退,一旦完成,就永远停在完成状态上。用get(等待)获得结果。
/**
* @param args
* @throws InterruptedException
* @throws ExecutionException
*/
public static void main(String[] args) throws
InterruptedException {
int threadCounts = 19;// 使用的线程数
long sum = 0;
ExecutorService exec = Executors.newFixedThreadPool(threadCounts);
List<Callable<Long>> callList = new ArrayList<Callable<Long>>();
// 生成很大的List
List<Integer> list = new ArrayList<Integer>();
for (int i = 0; i <= 1000000; i++) {
list.add(i);
}
int len = list.size() / threadCounts;// 平均分割List
// List中的数量没有线程数多(很少存在)
if (len == 0) {
threadCounts = list.size();// 采用一个线程处理List中的一个元素
len = list.size() / threadCounts;// 重新平均分割List
}
for (int i = 0; i < threadCounts; i++) {
final List<Integer> subList;
if (i == threadCounts - 1) {
subList = list.subList(i * len, list.size());
} else {
subList = list.subList(i * len,
len * (i + 1) > list.size() ? list.size() : len
* (i + 1));
}
// 采用匿名内部类实现
callList.add(new Callable<Long>() {
public Long call() throws Exception {
long subSum = 0L;
for (Integer i : subList) {
subSum += i;
}
System.out.println("分配给线程:"
+ Thread.currentThread().getName()
+ "那一部分List的整数和为:\tSubSum:" + subSum);
return subSum;
}
});
}
List<Future<Long>> futureList = exec.invokeAll(callList);
for (Future<Long> future : futureList) {
sum += future.get();
}
exec.shutdown();
System.out.println(sum);
}
2.4 和Service的结合
Runnable和Callable类都可以通过Service的submit方法提交,并且返回一个Future,它表示这个任务,可以获得该任务的执行结果或者取消它。
另外,可以给为Runnable/Callable显示的实例化一个FutureTask:
Callable pAccount = new PrivateAccount();
FutureTask futureTask = new FutureTask(pAccount);
3 CompletionService
向Executor提交一个批处理任务,并且希望获得结果,那么你将会使用Future,然后不断的调用isDone来检验是否完成,这样太麻烦,还有更好的方法,那就是完成服务,CompletionService。poll方法不会等待,返回null。take方法会等待。
它整合了Executor和BlockingQueue的功能,你可以将Callable任务交给他执行,然后使用类似于队列中的take何poll方法,在结果完整时可用时获得这个结果。ExecutorCompletionService是它的实现类。
它的实现也比较简单,在构造函数中创建一个BlockingQueue,用它保存结果:
private final BlockingQueue<Future<V>> completionQueue;
提交的任务被包装成QueueFuture:
private class QueueingFuture extends FutureTask<Void> {
QueueingFuture(RunnableFuture<V> task) {
super(task, null);
this.task = task;
}
protected void done() { completionQueue.add(task); }
private final Future<V> task;
}
覆写done方法,将结果置入BlockingQueue。
它与上面获得一堆FutureTask,然后遍历的去get等返回还不一样。它只能一个个获取,代表有一个拿一个。FutureTask的get可能后面的FutureTask都已经好了,可是有一个还没好,那就卡在中间了。
线程池:Execution框架的更多相关文章
- Java并发——线程池Executor框架
线程池 无限制的创建线程 若采用"为每个任务分配一个线程"的方式会存在一些缺陷,尤其是当需要创建大量线程时: 线程生命周期的开销非常高 资源消耗 稳定性 引入线程池 任务是一组逻辑 ...
- Java线程池 Executor框架概述
线程池的意义 循环利用线程资源,避免重复创建和销毁线程 线程池的任务是异步执行的,只要提交完成就能快速返回,可以提高应用响应性 Java线程池还有一个很重要的意义:Java线程池就是JDK 5 推出的 ...
- Java 线程池 Executor 框架
在Java中,可以通过new Thread 的方法来创建一个新的线程执行任务,但是线程的创建是非常耗时的,而且创建出来的新的线程都各自运行.缺乏统一的管理,这样的后果是可能导致创建过多的线程从而过度消 ...
- (转)深入详解Java线程池——Executor框架
转:https://yq.aliyun.com/articles/633782?utm_content=m_1000015330 在Java中,使用线程来异步执行任务.Java线程的创建与销毁需要一定 ...
- JAVA Executor(线程池)框架
一.Executor概述 为更好控制线程,jdk提供一套线程管理框架Executor,帮助开发人员有效地进行线程控制.它们都位于java.util.concurrent包中,是jdk并发包的核心.其中 ...
- [转载] Java线程池框架源码分析
转载自http://www.linuxidc.com/Linux/2014-11/108791.htm 相关类Executor,Executors,AbstractExecutorService,Ex ...
- 并发新特性—Executor 框架与线程池
兰亭风雨 · 更新于 2018-11-14 09:00:31 并发新特性-Executor 框架与线程池 Executor 框架简介 在 Java 5 之后,并发编程引入了一堆新的启动.调度和管理线程 ...
- 线程池及Executor框架
1.为什么要使用线程池? 诸如 Web 服务器.数据库服务器.文件服务器或邮件服务器之类的许多服务器应用程序都面向处理来自某些远程来源的大量短小的任务.请求以某种方式到达服务器,这种方式可能是通过 ...
- Java并发(基础知识)—— Executor框架及线程池
在Java并发(基础知识)—— 创建.运行以及停止一个线程中讲解了两种创建线程的方式:直接继承Thread类以及实现Runnable接口并赋给Thread,这两种创建线程的方式在线程比较少的时候是没有 ...
- 谈谈Java的线程池设计
在实际项目中,如果因为想异步执行暂时性的任务而不断创建线程是很浪费资源的事情(当一个任务执行完后,线程也没用了).这种情况下,最好是将任务提交给线程池执行. 所谓池,就是将管理某一种资源,对资源进行复 ...
随机推荐
- Redis(十二):redis请求转发的实现
请求转发一般的原因为: 1. 该请求自身无法处理,需要转发给对应的服务器处理: 2. 为实现负载均衡,使用路由服务,选择目标实例进行转发: 在集群模式下,请求可以打到任何一台redis服务器上.然而并 ...
- cmdb 配置
cmdb客户端文件夹创建 客户端:client:-bin:启动文件-src:源文件(核心代码)-conf:配置文件-lib:全局的一些方法 和配置-test:测试文件
- hdu1015+hdu1016 都是十分钟以内的深搜题
hdu1015:给定一串可用序列值,每个字符映射到一个1-26之间的整数,选择五个有序数使得满足 a-b2+c3-d4+e5=target. #include<iostream> #inc ...
- 洛谷 P5221 Product 题解
原题链接 庆祝!第二道数论紫题. 推式子真是太有趣了! \[\prod_{i=1}^n \prod_{j=1}^n \frac{\operatorname{lcm}(i,j)}{\gcd(i,j)} ...
- 熟悉使用Webdriver ---- 商品自动秒杀
前几天下载了Webdriver模块,经过简单的研究,发现这个模块可以做很多有意思的事情,下面我就用一个实例来理解webdriver的此处操作(完整代码在文章末尾). *浏览器:谷歌chrome浏览器 ...
- [模板] LCA-最近公共祖先-倍增法
2019-11-07 09:25:45 C.树之呼吸-叁之型-树上两点路径长度 Time Limit: 1000 MS Memory Limit: 32768 K Total Submit: 7 (4 ...
- [状态压缩,折半搜索] 2019牛客暑期多校训练营(第九场)Knapsack Cryptosystem
链接:https://ac.nowcoder.com/acm/contest/889/D来源:牛客网 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 262144K,其他语言52428 ...
- Building Applications with Force.com and VisualForce (DEV401) (二) : Application Essentials:Designing Application on the Force.com Platform
Dev 401-002:Application Essentials:Designing Application on the Force.com Platform Course Objectives ...
- C的变量类型、作用域与生命周期的总结
C的变量类型.作用域与生命周期的总结 最近在看"C Programing Language" (Kernighan, Ritchie)关于外部变量的讨论,之前在学C的时候对这些ex ...
- SpringBoot 集成ehcache
1, 项目实在springboot 集成mybatis 的基础上的: https://www.cnblogs.com/pickKnow/p/11189729.html 2,pom 如下,有的不需要加, ...