一、 在线程中执行任务
无限制创建线程的不足
.线程生命周期的开销非常高
.资源消耗
.稳定性
二、Executor框架
Executor基于生产者-消费者模式,提交任务的操作相当于生产者,执行任务的线程则相当于消费者。
1. Executors 返回 ExecutorService
2. ExecutorService方法submit、execute
3. ExecutorService.submit 返回 Future
2. ExecutorService方法submit、execute
3. ExecutorService.submit 返回 Future
线程池,Executors方法介绍
方法名 | 解释 |
newFixedThreadPool | 将创建一个固定长度的线程池,每当提交一个任务时就创建一个线程,知道达到线程池的最大数量,这时线程池的规模将不再变化(如果某个线程由于发生了未预期的Exception而结束,那么线程池会补充一个新的线程。) |
newCachedThreadPool | 将创建一个可缓存的线程池,如果线程池的当前规模超过了处理需求时,那么将回收空闲的线程,而当需求增加时,则可以添加新的线程,线程池的规模不存在任何限制。 |
newSingleThreadExecutor | 将会创建一个单线程的Executor,它创建单个工作者线程来执行任务,如果这个线程异常结束,会创建另一个线程来替代。newSingleThreadExecutor能确保依照任务在队列中的顺序来串行执行(例如FIFO、LIFO、优先级) |
newScheduledThreadPool | 创建了一个固定长度的线程池,而且以延迟或定时的方式来执行任务,类似于Timer。 |
Executor的生命周期
以上四个方法都会返回ExecutorService,ExecutorService的生命周期有3种状态:运行、关闭和已终止。
以上四个方法都会返回ExecutorService,ExecutorService的生命周期有3种状态:运行、关闭和已终止。
方法名 | 解释 |
shutdown | 将执行平缓的关闭过程:不再接受新的任务,同时等待已经提交的任务执行完成—包括那些还未开始执行的任务。 |
shutdownNow | 将执行粗暴的关闭过程:它将尝试取消所有运行中的任务,并且不再启动队列中尚未开始执行的任务。 |
Timer类负责管理延迟任务
三、找出可利用的并行性
1. 任务拆分到多个子线程处理。
2. 携带结果的任务Callable与Futrue
Executor执行任务的4个生命周期:创建,提交,开始,完成。
任务的提交者和执行者之间的通讯手段
ExecutorService executor = Executors.newSingleThreadExecutor();
Callable<Object> task = new Callable<Object>() {
public Object call() throws Exception {
Object result = "...";
return result;
}
};
Future<Object> future = executor.submit(task);
future.get(); // 等待至完成
Future<Object> future = executor.submit(task);
// 等待到任务被执行完毕返回结果
// 如果任务执行出错,这里会抛ExecutionException
future.get();
//等待3秒,超时后会抛TimeoutException
future.get(3, TimeUnit.SECONDS);
Callable<Object> task = new Callable<Object>() {
public Object call() throws Exception {
Object result = …;
return result;
}
};
有两种任务:
Runnable
Callable - 需要返回值的任务
Task Submitter把任务提交给Executor执行,他们之间需要一种通讯手段,这种手段的具体实现,通常叫做Future。Future通常包括get(阻塞至任务完成), cancel,get(timeout)(等待一段时间)
等等。Future也用于异步变同步的场景。
3、4. 在异构任务并行化中存在的局限
如果一个任务是读取IO资源,可以使用多个线程去同时读取,但是效率上限可能出在IO上,即使开启再多线程读取总速度也不可能超出IO读取速度上限。
开启多个线程本身也会调高编程难度,同时开启多个线程也会造成资源消耗。
多线程提高效率很多时候并不是增加一个线程效率提高一倍,可能提高的效率微乎其微。
5. Executor与BlockingQueue
如果想提交一组计算任务,并且希望在计算完成后获得结果,可以使用BlockingQueue保存每个任务的Future。
7. 为任务设置时限
//等待3秒,超时后会抛TimeoutException
future.get(3, TimeUnit.SECONDS);
future.get(3, TimeUnit.SECONDS);
8. ExecutorService.invokeAll()
执行给定的任务,当所有任务完成时,返回保持任务状态和结果的 Future 列表。返回列表的所有元素的 Future.isDone() 为 true。注意,可以正常地或通过抛出异常来终止已完成 任务。如果正在进行此操作时修改了给定的 collection,则此方法的结果是不确定的。
执行给定的任务,当所有任务完成时,返回保持任务状态和结果的 Future 列表。返回列表的所有元素的 Future.isDone() 为 true。注意,可以正常地或通过抛出异常来终止已完成 任务。如果正在进行此操作时修改了给定的 collection,则此方法的结果是不确定的。
四、资料:
《温绍锦 - Java并发程序设计教程》
摘录“任务的提交者和执行者
”,“任务的提交者和执行者之间的通讯手段
”
聊聊并发(三)——JAVA线程池的分析和使用(原理)
http://www.infoq.com/cn/articles/java-threadPool
Java(Android)线程池(使用)
http://www.trinea.cn/android/java-android-thread-pool/
Java Thread Pool Example using Executors and ThreadPoolExecutor
http://www.journaldev.com/1069/java-thread-pool-example-using-executors-and-threadpoolexecutor
工具可以查看线程数
jconsole.exe