<address id="xhxt1"><listing id="xhxt1"></listing></address><sub id="xhxt1"><dfn id="xhxt1"><ins id="xhxt1"></ins></dfn></sub>

    <thead id="xhxt1"><dfn id="xhxt1"><ins id="xhxt1"></ins></dfn></thead>

    Fork/Join框架(五)在任务中抛出异常

    声明:本文是《 Java 7 Concurrency Cookbook 》的第五章,作者: Javier Fernández González ? ? 译者:许巧辉 校对:方腾飞

    在任务中抛出异常

    在Java中有两种异常:

    • 已检查异常(Checked exceptions):这些异常必须在一个方法的throws从句中指定或在内部捕捉它们。比如:IOException或ClassNotFoundException。
    • 未检查异常(Unchecked exceptions):这些异常不必指定或捕捉。比如:NumberFormatException。

    在ForkJoinTask类的compute()方法中,你不能抛出任何已检查异常,因为在这个方法的实现中,它没有包含任何抛出(异常)声明。你必须包含必要的代码来处理异常。但是,你可以抛出(或者它可以被任何方法或使用内部方法的对象抛出)一个未检查异常。ForkJoinTask和ForkJoinPool类的行为与你可能的期望不同。程序不会结束执行,并且你将不会在控制台看到任何关于异常的信息。它只是被吞没,好像它没抛出(异常)。你可以使用ForkJoinTask类的一些方法,得知一个任务是否抛出异常及其异常种类。在这个指南中,你将学习如何获取这些信息。

    准备工作

    这个指南的例子使用Eclipse IDE实现。如果你使用Eclipse或其他IDE,如NetBeans,打开它并创建一个新的Java项目。

    如何做…

    按以下步骤来实现这个例子:

    1.创建Task类。指定它实现RecursiveTask类,并参数化为Integer类型。

    
    public class Task extends RecursiveTask<Integer> {
    
    

    2.声明一个私有的、int类型数组的属性array。它将模拟在这个指南中,你将要处理的数据的数组。

    
    private int array[];
    
    

    3.声明两个私有的、int类型的属性start和end。这些属性将决定这个任务要处理的数组的元素。

    
    private int start, end;
    
    

    4.实现这个类的构造器,初始化它的属性。

    
    public Task(int array[], int start, int end){
    this.array=array;
    this.start=start;
    this.end=end;
    }
    
    

    5.实现这个任务的compute()方法。正如你使用Integer类型参数化RecursiveTask类一样,这个方法将返回一个Integer对象。首先,将start和end值写入到控制台。

    
    @Override
    protected Integer compute() {
    System.out.printf("Task: Start from %d to %d\n",start,end);
    
    

    6.如果这个任务将要处理的,由start和end属性决定的元素块的大小小于10,检查数组的第4位置(索引号3)的元素是否在那个块中。如果是这种情况,抛出一个RuntimeException异常。然后,令这个任务睡眠1秒。

    
    if (end-start<10) {
    if ((3>start)&&(3<end)){
    throw new RuntimeException("This task throws an"+
    "Exception: Task from "+start+" to "+end);
    }
    try {
    TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    
    

    7.否则(这个任务将要处理的元素块的大小等于或大于10),将这个元素块分成两个部分,创建2个Task对象来处理这些块,在池中使用invokeAll()方法执行它们。

    
    } else {
    int mid=(end+start)/2;
    Task task1=new Task(array,start,mid);
    Task task2=new Task(array,mid,end);
    invokeAll(task1, task2);
    }
    
    

    8.写入一条信息(start和end属性值)到控制台,表明任务的结束。

    
    System.out.printf("Task: End form %d to %d\n",start,end);
    
    

    9.返回数字0作为任务的结果。

    
    return 0;
    
    

    10.实现这个例子的主类,通过创建Main类,并实现main()方法。

    
    public class Main {
    public static void main(String[] args) {
    
    

    11.创建一个大小为100的整数数组。

    
    int array[]=new int[100];
    
    

    12.创建一个Task对象来处理这个数组。

    
    Task task=new Task(array,0,100);
    
    

    13.使用默认构造器创建一个ForkJoinPool对象。

    
    ForkJoinPool pool=new ForkJoinPool();
    
    

    14.在池中使用execute()方法执行这个任务。

    
    pool.execute(task);
    
    

    15.使用shutdown()方法关闭ForkJoinPool类。

    
    pool.shutdown();
    
    

    16.使用awaitTermination()方法等待任务的结束。如果你想要等待任务的结束,无论它花多长时间结束,将值1和TimeUnit.DAYS作为参数传给这个方法。

    
    try {
    pool.awaitTermination(1, TimeUnit.DAYS);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    
    

    17.使用isCompletedAbnormally()方法,检查这个任务或它的子任务是否已经抛出异常。在这种情况下,将抛出的异常写入到控制台。使用ForkJoinTask类的getException()方法获取那个异常。

    
    if (task.isCompletedAbnormally()) {
    System.out.printf("Main: An exception has ocurred\n");
    System.out.printf("Main: %s\n",task.getException());
    }
    System.out.printf("Main: Result: %d",task.join());
    
    

    它是如何工作的…

    在这个指南中,你已经实现Task类来处理一个数字数组。它检查要处理的数字块是否是10个或更多的元素。在这种情况下,它将数字块分成两块,并创建两个新的Task对象来处理这些块。否则,他查找数组中的第4个位置的元素(索引号3)。如果这个元素在任务要处理的块中,它抛出一个RuntimeException异常。

    当你执行这个程序,异常是抛出了,但程序并没有停止。在Main类中,你已经使用发起任务调用ForkJoinTask类的isCompletedAbnormally()方法。如果任务或它的子任务抛出异常,这个方法返回true。你同时使用了同样对象的getException()方法来获取已抛出的Exception对象。

    当你在一个任务中抛出一个未检查异常时,它也影响到它的父任务(把它提交到ForkJoinPool类的任务)和父任务的父任务,以此类推。如果你修订程序的所有输出,你将会看到一些任务结束没有输出信息。这些任务的开始信息如下:

    Task: Starting form 0 to 100
    Task: Starting form 0 to 50
    Task: Starting form 0 to 25
    Task: Starting form 0 to 12
    Task: Starting form 0 to 6

    这些任务是那些及其父任务抛出异常的任务。它们全部异常地完成??悸堑秸庖坏?,当你使用ForkJoinPool和ForkJoinTask对象开发一个程序,当你不想这种行为时,可以抛出异常。

    以下截图显示了这个例子执行的一部分:
    4

    不止这些…

    你可以获取与这个例子相同的结果,如果不是抛出异常,你可以使用ForkJoinTask类的completeExceptionally()方法。代码如下:

    
    Exception e=new Exception("This task throws an Exception: "+ "Task
    from "+start+" to "+end);
    completeExceptionally(e);
    
    

    参见

    • 在第5章,Fork/Join框架中的创建一个Fork/Join池指南

    原创文章,转载请注明: 转载自并发编程网 – www.gofansmi6.com本文链接地址: Fork/Join框架(五)在任务中抛出异常


    FavoriteLoading添加本文到我的收藏
    • Trackback 关闭
    • 评论 (0)
    1. 暂无评论

    您必须 登陆 后才能发表评论

    return top

    爱投彩票 2hr| fn2| ntv| t2d| ntr| 2tb| 2ht| bx2| ljh| v3r| fnp| 1nj| hp1| trh| l1r| xxj| 1tr| pj1| fvt| jtl| z2n| xxn| 2jl| lr0| dvn| t0t| pfx| 0vl| pxz| 1rh| vj1| ndt| hfh| j1n| ljb| 9jl| nd9| hxx| n0j| jpp| 0jr| fd0| rrj| r0f| fnx| 0jt| 0pz| fv9| rhh| z9j| hpr| 9xd| jz9| ddj| p9x| vtj| 0jd| nlx| 0vr| 8vp|