java并发编程第四章 线程执行器(5)

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.");

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值