第六章 CompletionService的使用
接口CompletionService的功能是以异步的方式一边生产新的任务,一边处理已完成任务的结果,这样可以将执行任务与处理任务分离开来进行处理。使用submit执行任务,使用take取得已完成的任务,并按照完成这些任务的时间顺序处理它们的结果。
public static void main(String[] args) {
try {
MyCallable callable1 = new MyCallable("username1", 5000);
MyCallable callable2 = new MyCallable("username2", 4000);
MyCallable callable3 = new MyCallable("username3", 3000);
MyCallable callable4 = new MyCallable("username4", 2000);
MyCallable callable5 = new MyCallable("username5", 1000);
List<Callable> callableList = new ArrayList<Callable>();
callableList.add(callable1);
callableList.add(callable2);
callableList.add(callable3);
callableList.add(callable4);
callableList.add(callable5);
ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 5,
TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>());
CompletionService csRef = new ExecutorCompletionService(executor);
for (int i = 0; i < 5; i++) {
csRef.submit(callableList.get(i));
}
for (int i = 0; i < 5; i++) {
System.out.println("等待打印第" + (i + 1) + "个返回值");
System.out.println(csRef.take().get());
}
// 按乱序打印的效果
// 说明一个Future对应当前先执行完的Callable任务
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
CompletionService完全解决了Future阻塞的特性,也就是使用CompletionService接口后,哪个任务先执行完,哪个任务的返回值就先打印。
- 方法take()取得最先完成任务的Future对象,谁执行时间最短谁最先返回。
- 接口CompletionService完全可以避免FutureTask类阻塞的缺点,可更加有效地处理Future的返回值,也就是哪个任务先执行完,CompletionService就先取得这个任务的返回值再处理
第七章 接口ExecutorService的方法使用
- 方法invokeAny()和invokeAll()具有阻塞特性。
第八章 计划任务ScheduledExecutorService的使用
- 类ScheduledExecutorService的主要作用就是可以将定时任务与线程池功能结合使用。
public static void main(String[] args) {
try {
List<Callable> callableList = new ArrayList();
callableList.add(new MyCallableA());
callableList.add(new MyCallableB());
// 调用方法newSingleThreadScheduledExecutor
// 取得一个单任务的计划任务执行池
ScheduledExecutorService executor = Executors
.newSingleThreadScheduledExecutor();
ScheduledFuture<String> futureA = executor.schedule(callableList
.get(0), 4L, TimeUnit.SECONDS);
ScheduledFuture<String> futureB = executor.schedule(callableList
.get(1), 4L, TimeUnit.SECONDS);
System.out.println(" X=" + System.currentTimeMillis());
System.out.println("返回值A:" + futureA.get());
System.out.println("返回值B:" + futureB.get());
System.out.println(" Y=" + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
- 使用scheduleAtFixedRate()方法实现周期性执行
- 方法getQueue()的作用是取得队列中的任务,而这些任务是未来将要运行的,正在运行的任务不在此队列中
第九章 Fork-Join分治编程
- 使用类RecursiveAction执行的任务是具有无返回值的,仅执行一次任务。
- 使用类RecursiveTask执行的任务具有返回值的功能。
- 方法join()与get()虽然都能取得计算后的结果值,但它们之间还是在出现异常时有处理上的区别,get可以直接在主线程捕获异常,join会直接抛出异常
第十章 并发集合框架
- 类ConcurrentHashMap是支持并发操作的Map对象。