一、在执行器中分离任务的启动与结果的处理
1、通常情况下,使用线程执行器来执行并发任务,将runnable或callable任务发送给线程执行器,并获得Future对象来控制任务
2、特殊情形:在一个对象里发送任务给执行器,然后在另一个对象里处理结果
3、应运而生的CompletionService类
二、CompletionService
1、CompletionService类里有一个方法迎来发送任务给线程执行器,还有一个方法为下一个已经执行结束的任务获取Future对象
2、内部实现机制:CompletionService类使用Executor对象来执行任务
3、优势:可以共享CompletionService对象,并发送任务到执行器,然后其他的对象可以处理任务的结果
4、缺点:只能为已经执行结束的任务获取Future对象,因此这些Future对象只能被用来获取任务的结果
5、CompletionService可以执行Runnable类型的任务或者Callable的任务,但是Runnable并不返回结果,所以基本没用
三、CompletionService提供的方法
Future<V> poll();
用于检查队列是否有Future对象,如果队列为空,返回null,否则,返回第一个元素,并移除这个元素
Future<V> poll(long timeout, TimeUnit unit) throws InterruptedException;
访问执行任务的队列,查看是否有任务已经完成,如果有,返回队列的第一个元素,然后删除这个元素
Future<V> take() throws InterruptedException;
检查队列中是否有Future对象,如果队列为空,它将阻塞线程直到队列中有可用的元素,否则,返回第一个元素,并移除这个元素
四、模拟
ReportRequest执行CompletionService中的两个ReportGenerator任务
ReportProcessor将处理被发送到执行器里的ReportRequest所产生的结果
package com.concurrency.executor; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; /** * 模拟生成一份报告 * @author Nicholas * */ public class ReportGenerator implements Callable<String> { private String sender; private String title; public ReportGenerator(String sender, String title) { this.sender = sender; this.title = title; } @Override public String call() throws Exception { try { long duration = (long) (Math.random() * 10); System.out .printf("%s_%s : ReportGenerator : Generating a report during %d seconds", this.sender, this.title, duration); TimeUnit.SECONDS.sleep(duration); } catch (InterruptedException e) { e.printStackTrace(); } String retString = sender + " : " + title; return retString; } }
package com.concurrency.executor; import java.util.concurrent.CompletionService; /** * 这个类模拟请求获取报告 * 但是不在这个线程里面处理报告 * @author Nicholas * */ public class ReportRequest implements Runnable { private String name; //创建CompletionService属性 private CompletionService<String> completionService; public ReportRequest(String name, CompletionService<String> completionService) { this.name = name; this.completionService = completionService; } @Override public void run() { //生成一份报告 ReportGenerator reportGenerator = new ReportGenerator(name, "Report"); //将报告交给completionService对象 completionService.submit(reportGenerator); } }
package com.concurrency.executor; import java.util.concurrent.CompletionService; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; /** * 处理报告,也就是说报告的请求和处理不在一个线程中 * * @author Nicholas * */ public class ReportProcessor implements Runnable { private CompletionService<String> completionService; private boolean end; public ReportProcessor(CompletionService<String> completionService) { this.completionService = completionService; end = false; } @Override public void run() { // end 为false,调用completionService接口的poll()方法,来获取下一个已经完成任务的Future对象 // 这个任务是采用completionService完成的 while (!end) { try { Future<String> result = completionService.poll(20, TimeUnit.SECONDS); if (result != null) { // 调用Future对象的get()方法获取任务的结果 String report = result.get(); System.out.println("ReportReceiver : Report Received : " + report); } } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } System.out.println("ReportSender : End"); } public void setEnd(boolean end) { this.end = end; } }
package com.concurrency.executor; import java.util.concurrent.CompletionService; import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; public class Main { public void testReportProcessor() { // 创建线程执行器 ExecutorService executorService = Executors.newCachedThreadPool(); // 创建completionService对象,使用executorService初始化 CompletionService<String> completionService = new ExecutorCompletionService<String>( executorService); // 创建两个ReportRequest对象,然后创建两个线程分别执行他们 ReportRequest faceRequest = new ReportRequest("Face", completionService); ReportRequest onlineRequest = new ReportRequest("Online", completionService); Thread feceThread = new Thread(faceRequest); Thread onlineThread = new Thread(onlineRequest); // 创建一个ReportProcessor对象,然后创建一个线程对象执行 ReportProcessor reportProcessor = new ReportProcessor(completionService); Thread threadReportProcessor = new Thread(reportProcessor); // 启动这三个线程 System.out.println("Main : Starting for the report generators"); feceThread.start(); onlineThread.start(); threadReportProcessor.start(); // 等待ReportRequest线程处理结束 try { System.out.println("Main : waiting for the report generators"); feceThread.join(); onlineThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } // 结束线程执行器 System.out.println("Main : shutting down the executor"); executorService.shutdown(); // 调用awaitTermination等待所有的任务执行结束 try { executorService.awaitTermination(1, TimeUnit.DAYS); } catch (InterruptedException e) { e.printStackTrace(); } // 结束ReportProcessor的执行 reportProcessor.setEnd(true); System.out.println("Main : Ends"); } public static void main(String[] args) { new Main().testReportProcessor(); } }