转载请注明出处 http://www.paraller.com
原文排版地址 点击跳转-任务执行/)
相关知识点
- 大多数并发应用,都是通过
任务执行
来构造的,通过将任务分成小的工作单元
,提供一种自然的事务边界
来优化错误恢复过程. - 任务执行(Task Execution)的重点在于:
独立性
和明确的任务执行策略
-
无限制创建线程的不足
- 线程的创建需要时间,消耗大量的运算资源
- 活跃的线程消耗系统资源,特别是
内存
;可运行的线程数量多于CPU的数量将会造成闲置,占用内存,大量线程还会引起竞争 - 稳定性:JVM和
Thread构造函数指定的栈大小
,以及系统对线程的限制都会造成崩溃。
- future可以设置超时时间。
Note:
32位的机器,限制因素主要是线程栈的地址空间,每个线程维护两个执行栈,一个用于Java代码,一个用于原生代码,通常JVM会默认创建一个复合栈,大概是0.5兆(通过 -Xss或者Thread构造函数来设置),2的32次方除以栈大小,会将线程限制在几万内。
Executor
- 任务是一组逻辑
工作单元
, 而线程
则是任务异步执行的机制
- Executor能支持多种不同类型的任务执行策略
- 提供了一种标准的方法将 任务的提交 和 任务的执行 分开,使用
Runnable
表示任务 - 提供了对生命周期、统计信息收集、程序管理、性能监控的支持。
- 基于生产者-消费者模式,提交任务是生产,执行任务的线程相当于消费者
- 通过不同的 Executor的实现就能改变程序的行为。
- Java类库中,任务执行的主要抽象不是 Thread,而是 Executor
interface Executor{
void execute(Runnable command);
}
class Demo{
private final Executor exec = Executors.newFixedThreadPool(100);
void test(){
// 运行
Runnable task = new Runnable(){
public void run(){
//...
}
}
// 提交
exec.execute(task);
}
}
线程池
通过管理一组工作线程的资源池,能够减少创建和销毁的开销(资源层面),并且不需要等待,提高响应性
Executor静态工厂方法提供以下几种资源池:
- newFixedThreadPool: 固定大小,如果线程异常结束会补充
- newCachedThreadPool: 可缓存线程池,少了创建,多了回收
- newSingleThreadExecutor: 单线程,会按照队列中的顺序(可设置)串行执行
- newScheduledThreadPool: 固定大小,能延迟或者定时执行
Executor生命周期
Executor实现通常创建线程执行,JVM只有在所有的非守护线程结束才能关闭,
类库提供了 基于 Executor的 ExecutorService接口
-
shutdown:
不接受新任务
,等待开始的任务结束 -
shutdownNow: 尝试取消所有开始的任务,不再启动
尚未开始
(可能是已接受的新任务)执行的任务。
interface ExecutorService extends Executor{
void shutdown();
List<Runnable> shutdownNow();
boolean isShutdown();
...//
}
生命周期三种状态 运行、关闭、已终止
- ExecutorService关闭后,提交新的任务会抛出
RejectExecutionException
- 所有任务完成会变成已终止状态
- awaitTermination会等待 Executor到达终止状态,并且会立即调用shutdown方法。
- ExecutorService所有submit方法,都会返回一个Future
Timer和ScheduledThreadPoolExecutor
Timer负责管理 延迟任务 和 周期任务;缺陷如下:
- 只会创建一个线程,如果任务耗时过长会影响其他任务
- Timer线程不捕获异常, TimerTask抛出异常整个Timer任务都会取消。
如果要构建自己的调度器,可以使用DelayQueue和ScheduledThreadPoolExecutor组合。
异构任务
- 定义: 不同类型的任务平均分配给每个消费者。当消费者增加,在分配工作和协同工作的时候会存在考验。
- 只有大量相互独立 并且 同构的任务并发处理才能最大限度的提升性能
ExecutorCompletionService
- 一组Future任务,如果需要知道哪些完成了,需要不停的循环每个Future的Get方法,非常繁琐。
- CompletionService 将 Executor 和BlockingQueue 功能融合在一起
- 多个 ExecutorCompletionService 可以共享一个 Executor,
class Demo{
final ExecutorService executor;
void test(){
CompletionService cs = new ExecutorCompletionService(executor);
for(...){
cs.submit(new Callable(){
//...
});
}
for(...){
// 返回的都是已经计算好结果的Callable
Future<T> future = cs.take();
future.get();
}
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。