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.");    }}
0 0
原创粉丝点击