java并发编程第四章 线程执行器(5)
来源:互联网 发布:网络舆论引导途径 编辑:程序博客网 时间:2024/05/26 19:16
10.在执行器中分离任务的启动与结果的处理
当我们要在一个对象中发送任务给执行器,在另一个对象中处理结果时,对于这种需求可以使用CompletionService类。
该类有一个方法用来发送任务给执行器,还有一个方法为下一个已经执行结束的任务获取Future对象。从内部实现机制来看,CompletionService类使用Executor对象来执行任务。
这个行为
的优势是可以共享CompletionService对象,并发送任务到执行器,然后其他的对象可以处理任务的结果。第二个方法有不足之处,只能为已经执行结束的任务获取Future对象,因此,
这些Future对象只能被用来获取任务的结果。
该类可以执行Callable或者Runnable类型的任务。由于使用Runnable接口对象不能产生结果,因此CompletionService的基本原则不适用。
CompletionService类提供了其他两种方法来获取任务已经完成的Future对象。
1.poll():无参数的poll()方法用于检查队列中是否有Future对象。如果队列为空,则立即返回null,否则将返回队列中的第一个元素,并移除该元素。
2.take(): 这个方法检查队列中是否有Future对象。如果队列为空,则会阻塞线程直到队列中有可用的元素。如果队列中有元素,它将返回队列中的第一个元素,并移除该元素。
/** * * @author fcs * @date 2015-5-8 * 描述:在执行器中分离任务的启动与结果的处理 * 说明:使用需求:需要在一个对象里发送任务给执行器,然后在另一个对象里处理结果 */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 { long duration = (long)(Math.random()*10); System.out.printf("%s_%s: ReportGenerator: Generating a report during %d seconds\n",this.sender,this.title,duration);; TimeUnit.SECONDS.sleep(duration); String ret = sender+":"+title; return ret; }}
/** * * @author fcs * @date 2015-6-16 * 描述:该类将获取到ReportGenerator任务的结果 */public class ReportProcessor implements Runnable{ private CompletionService<String> service; private boolean end; public ReportProcessor(CompletionService<String> service) { this.service = service; end = false; } @Override public void run() { while(!end){ try { //调用CompletionService的poll()方法来获取下一个已经完成任务的Future对象 Future<String> result = service.poll(20, TimeUnit.SECONDS); if(result != null){ String report; //使用该方法获取任务的结果。 report = result.get(); System.out.printf("ReportReceiver: Report Received: %s\n",report); } } catch (Exception e) { e.printStackTrace(); } System.out.println("ReportSender: End\n"); } } public void setEnd(boolean end){ this.end = end; }}
/** * * @author fcs * @date 2015-5-9 * 描述:模拟请求报告 */public class ReportRequest implements Runnable { private String name; private CompletionService<String> service; public ReportRequest(String name, CompletionService<String> service) { this.name = name; this.service = service; } /** * 调用service的submi()方法将ReportGenerator对象发送给CompletionService对象 */ @Override public void run() { ReportGenerator reportGenerator = new ReportGenerator(name, "Report"); service.submit(reportGenerator); }}
public class Main { public static void main(String[] args) { ExecutorService executorService = (ExecutorService)Executors.newCachedThreadPool(); CompletionService<String> service = new ExecutorCompletionService<String>(executorService); //创建两个ReportRequest对象,然后创建两个线程Thread对象分别执行他们 ReportRequest faceRequest = new ReportRequest("Face", service); ReportRequest onlineRequest = new ReportRequest("Online",service); Thread faceThread = new Thread(faceRequest); Thread onlineThread = new Thread(onlineRequest); ReportProcessor processor = new ReportProcessor(service); Thread senderThread = new Thread(processor); System.out.println("Main: Starting the Threads\n"); faceThread.start(); onlineThread.start(); senderThread.start(); System.out.println("Main: Waiting for the report generators.\n"); //等待ReportRequest线程的结束 try { faceThread.join(); onlineThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("Main: Shutting down the executor.\n"); executorService.shutdown(); try { //调用该方法等待所有的任务执行结束 executorService.awaitTermination(1, TimeUnit.DAYS); } catch (InterruptedException e) { e.printStackTrace(); } processor.setEnd(true); System.out.println("Main: Ends"); }}
11.处理在执行器中被拒绝的任务
如果在shutdown()方法与执行器结束之间发送一个任务给执行器,这个任务会被拒绝,因为这个时间段执行器不再接收任务了,
ThreadPoolExecutor类提供了一套机制,当任务被拒绝时调用
这套机制来处理它们。
使用RejectedExecutionHandler接口。
为了处理在执行器中被拒绝的任务,需要创建一个实现RejectedExecutionHandler接口的处理类。这个接口有一个rejectedExecution方法,其中有两个参数:
1.一个Runnable对象,用来存储被拒绝的任务,。
2.一个Executor对象,用来存储任务被拒绝的执行器。
被执行器拒绝的每一个任务都将调用该方法,需要先调用Executor类的setRejectedExecutionHandler()方法来设置用于被拒绝的任务的处理程序。
当执行器接收一个任务并开始执行时,先检查shutdown()方法是否已经被调用了,如果是那么执行器就会拒绝这个任务。首先,执行器会寻找通过setRejectedExecutionHandler()方法设置的
用于被拒绝的任务的处理程序,如果找到一个处理程序,执行器就会调用其rejectedExecution()方法,否则就会抛出RejectedExecutionException异常,这是一个运行时异常,
因此并不需要catch语句来对其进行处理。
/** * * @author fcs * @date 2015-5-9 * 描述:处理在执行器中被拒绝的任务 * 说明:当我们想结束执行器的执行时,调用shutdown()方法来表示执行器应当结束,但是,执行器只有等待 * 正在运行的任务或者等待执行的任务结束后,才能真正结束。 * 如果在shutdown()方法与执行器结束之间发送一个任务给执行器,这个任务会被拒绝, * 因为这个时间段执行器已经不再接受任务了,ThreadPoolExecutor类提供了一套机制, * 当任务呗拒绝时调用这套机制来处理它们 * 本节使用RejectedExecutionHandler接口,该接口只有一个方法 * rejectedExecution方法 * */public class RejectedTaskController implements RejectedExecutionHandler{ @Override //在控制台输出已被拒绝的任务的名称和执行器的状态 public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { System.out.printf("RejectedTaskController: The task %s has been rejected \n",r.toString()); System.out.printf("RejectedTaskController: %s\n",executor.toString()); System.out.printf("RejectedTaskController: Terminating: %s\n",executor.isTerminating()); System.out.printf("RejectedTaskController: Terminated: %s\n",executor.isTerminated()); }}
public class Task implements Runnable{ private String name; public Task(String name) { this.name = name; } @Override public void run() { System.out.println("Task "+name+ ": starting"); long duration = (long)(Math.random() *10); System.out.printf("Task %s: ReportGenerator: Generatint a report during %d seconds\n",name,duration); try { TimeUnit.SECONDS.sleep(duration); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("Task %s: Ending \n",name); } @Override //重写toString方法,返回任务的名称 public String toString() { return name; }}
public class Main { public static void main(String[] args) { RejectedTaskController controller = new RejectedTaskController(); ThreadPoolExecutor executor = (ThreadPoolExecutor)Executors.newCachedThreadPool(); //设置用于被拒绝的任务的处理程序 executor.setRejectedExecutionHandler(controller); System.out.printf("Main: Starting.\n"); for(int i =0;i< 3;i++){ Task task = new Task("Task_"+i); executor.submit(task); } System.out.println("Main:Shutting down the executor.\n"); executor.shutdown(); System.out.println("Main: Sending another Task\n"); //关闭执行器后再发送一个任务给执行器 Task task = new Task("RejectedTask"); executor.submit(task); System.out.println("Main: End."); }}
- java并发编程第四章 线程执行器(5)
- java并发编程第四章 线程执行器(1)
- java并发编程第四章 线程执行器(2)
- java并发编程第四章线程执行器(3)
- java并发编程第四章 线程执行器(4)
- java并发编程之线程执行器
- Java7并发编程指南——第四章:线程执行器
- Java并发编程-16-线程执行器-Executor Framework
- Java并发编程类学习三(线程的执行)
- 第四章线程执行器
- 并发编程--创建线程执行器
- java并发编程第四章 总结
- java编程思想---第四章(控制执行流程)
- Java并发编程:线程的创建和执行
- Java并发编程示例(六):等待线程执行终止
- Java编程思想第四版-第四章(控制执行流程 )笔记
- java并发编程(五)任务执行
- 利用对象限制和委托构建线程安全的类(java并发编程实战第四章内容)
- leetcode: Contains Duplicate
- java 以 yyyy-MM-dd hh:mm:ss 获取系统时间
- 动画特效五:灌水动画
- hdu5286 wyh2000 and sequence 分块处理
- hdu 3363 Ice-sugar Gourd
- java并发编程第四章 线程执行器(5)
- 视图翻转
- 字母重排
- java并发编程第四章 总结
- 拓撲排序學習
- 认识一下身边的互联网---经典互联网书籍阅读总结
- CentOS 7.0 VMware虚拟机 查找不到网卡 查找不到eth0
- 【猫猫的Unity Shader之旅】之纹理映射
- perror和strerror的问题