<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 ? ? 译者:许巧辉 校对:方腾飞

    取消任务

    当你在一个ForkJoinPool类中执行ForkJoinTask对象,在它们开始执行之前,你可以取消执行它们。ForkJoinTask类提供cancel()方法用于这个目的。当你想要取消一个任务时,有一些点你必须考虑一下,这些点如下:

    • ForkJoinPool类并没有提供任何方法来取消正在池中运行或等待的所有任务。
    • 当你取消一个任务时,你不能取消一个已经执行的任务。

    在这个指南中,你将实现取消ForkJoinTask对象的例子。你将查找数在数组中的位置。第一个找到这个数的任务将取消剩下的任务(未找到这个数的任务)。由于Fork/Join框架并没有提供这种功能,所以,你将实现一个辅助类来做这个取消功能。

    准备工作…

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

    如何做…

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

    1.创建ArrayGenerator类。这个类将产生一组随机的、指定大小的整数数字。实现generateArray()方法。它将产生一组数字,它接收数组大小作为参数。

    
    public class ArrayGenerator {
    public int[] generateArray(int size) {
    int array[]=new int[size];
    Random random=new Random();
    for (int i=0; i<size; i++){
    array[i]=random.nextInt(10);
    }
    return array;
    }
    
    

    2.创建一个TaskManager类。我们将使用这个类来存储在ForkJoinPool中执行的所有任务。由于ForkJoinPool和ForkJoinTask类的局限性,你将使用这个类来取消ForkJoinPool类的所有任务。

    
    public class TaskManager {
    
    

    3.声明一个对象参数化为ForkJoinTask类型的数列,其中ForkJoinTask类参数化为Integer类型。

    
    private List<ForkJoinTask<Integer>> tasks;
    
    

    4.实现这个类的构造器,它初始化任务数列。

    
    public TaskManager(){
    tasks=new ArrayList<>();
    }
    
    

    5.实现addTask()方法。它添加ForkJoinTask对象到任务数列。

    
    public void addTask(ForkJoinTask<Integer> task){
    tasks.add(task);
    }
    
    

    6.实现cancelTasks()方法。它将使用cancel()方法取消在数列中的所有ForkJoinTask对象。它接收一个想要取消剩余任务的ForkJoinTask对象作为参数。这个方法取消所有任务。

    
    public void cancelTasks(ForkJoinTask<Integer> cancelTask){
    for (ForkJoinTask<Integer> task :tasks) {
    if (task!=cancelTask) {
    task.cancel(true);
    ((SearchNumberTask)task).writeCancelMessage();
    }
    }
    }
    
    

    7.实现SearchNumberTask类,指定它继承参数化为Integer类型的RecursiveTask类。这个类将查找在整数数组的元素块中的数。

    
    public class SearchNumberTask extends RecursiveTask<Integer> {
    
    

    8.声明一个私有的、int类型的数字数组。

    
    private int numbers[];
    
    

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

    
    private int start, end;
    
    

    10.声明一个私有的、int类型的属性number,它将存储你将要查找的数。

    
    private int number;
    
    

    11.声明一个私有的、TaskManager类型的属性manager。你将使用这个对象来取消所有任务。

    
    private TaskManager manager;
    
    

    12.声明一个私有的、int类型的常量并初始化它为值-1。当任务没有找到这个数时,它将作为任务的返回值。

    
    private final static int NOT_FOUND=-1;
    
    

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

    
    public Task(int numbers[], int start, int end, int number,
    TaskManager manager){
    this.numbers=numbers;
    this.start=start;
    this.end=end;
    this.number=number;
    this.manager=manager;
    }
    
    

    14.实现compute()方法。写入一条信息(start和end属性值)到控制台表明这个方法的开始。

    
    @Override
    protected Integer compute() {
    System.out.println("Task: "+start+":"+end);
    
    

    15.如果start和end之差大于10(这个任务将处理超过10个元素的数组),调用launchTasks()方法,将这个任务的工作拆分成两个任务。

    
    int ret;
    if (end-start>10) {
    ret=launchTasks();
    
    

    16.否则,这个任务调用lookForNumber()方法来查找在数组块中的数。

    
    } else {
    ret=lookForNumber();
    }
    
    

    17.返回任务的结果。

    
    return ret;
    
    

    18.实现lookForNumber()方法。

    
    private int lookForNumber() {
    
    

    19.对于任务要处理的元素块中的所有元素,将你想要查找的数与存储在元素中的值进行比较。如果他们相等,写入一条信息到控制台表明这种情形,使用TaskManager对象的cancelTasks()方法来取消所有任务,并返回你已经找到的这个数对应元素的位置。

    
    for (int i=start; i<end; i++){
    if (array[i]==number) {
    System.out.printf("Task: Number %d found in position
    %d\n",number,i);
    manager.cancelTasks(this);
    return i;
    }
    
    

    20.在循环的内部,令任务睡眠1秒。

    try {
    TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    
    

    21.最后,返回值-1。

    
    return NOT_FOUND;
    }
    
    

    22.实现launchTasks()方法。首先,将这个任务要处理的数块分成两个部分,然后,创建两个Task对象来处理它们。

    
    private int launchTasks() {
    int mid=(start+end)/2;
    Task task1=new Task(array,start,mid,number,manager);
    Task task2=new Task(array,mid,end,number,manager);
    
    

    23.添加这个任务到TaskManager对象中。

    
    manager.addTask(task1);
    manager.addTask(task2);
    
    

    24.使用fork()方法异步执行这两个任务。

    
    task1.fork();
    task2.fork();
    
    

    25.等待这个任务的结束,返回第一个任务的结果(如果它不等于1),或第二个任务的结果。

    
    int returnValue;
    returnValue=task1.join();
    if (returnValue!=-1) {
    return returnValue;
    }
    returnValue=task2.join();
    return returnValue;
    
    

    26.实现writeCancelMessage()方法,当任务取消时,写一条信息到控制台。

    
    public void writeCancelMessage(){
    System.out.printf("Task: Canceled task from %d to
    %d",start,end);
    }
    
    

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

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

    28.使用ArrayGenerator类,创建一个有1000个数字的数组。

    
    ArrayGenerator generator=new ArrayGenerator();
    int array[]=generator.generateArray(1000);
    
    

    29.创建一个TaskManager对象。

    
    TaskManager manager=new TaskManager();
    
    

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

    
    ForkJoinPool pool=new ForkJoinPool();
    
    

    31.创建一个Task对象来处理前面生成的数组。

    
    Task task=new Task(array,0,1000,5,manager);
    
    

    32.使用execute()方法,在池中异步执行任务。

    
    pool.execute(task);
    
    

    33.使用shutdown()方法关闭这个池。

    
    pool.shutdown();
    
    

    34.使用ForkJoinPool类的awaitTermination()方法,等待任务的结束。

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

    35.写入一条信息到控制台,表明程序的结束。

    
    System.out.printf("Main: The program has finished\n");
    
    

    它是如何工作的…

    ForkJoinTask提供cancel()方法,允许你取消一个还未执行的任务。这是一个非常重要的点。如果任务已经开始它的执行,那么调用cancel()方法对它没有影响。这个方法接收一个Boolean值,名为mayInterruptIfRunning的参数。这个名字可能让你觉得,如果你传入一个true值给这个方法,这个任务将被取消,即使它正在运行。

    Java API文档指出,在ForkJoinTask类的默认实现中,这个属性不起作用。任务只能在它们还未开始执行时被取消。一个任务的取消不会影响到已经提到到池的(其他)任务。它们继续它们的执行。 Fork/Join框架的一个局限性是,它不允许取消在ForkJoinPool中的所有任务。为了克服这个限制,你实现了TaskManager类。它存储被提到池中的所有任务。它有一个方法取消它存储的所有任务。如果一个任务由于它正在运行或已经完成而不能被取消,cancel()方法返回false值,所以,你可以尝试取消所有任务,而不用担心可能有间接的影响。 在这个例子中,你已经实现一个任务,用来在一个数字数组中查找一个数。如Fork/Join框架所推荐的,你将问题分解成更小的子问题。你只关心这个数的出现,所以当你找到它,你取消了其他任务。 以下截图显示这个例子执行的一部分: 5 参见

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

    原创文章,转载请注明: 转载自并发编程网 – www.gofansmi6.com本文链接地址: Fork/Join框架(六)取消任务


    FavoriteLoading添加本文到我的收藏
    • Trackback 关闭
    • 评论 (1)
      • Avin
      • 2014/04/21 3:03下午

      第22步中 Task是否就是SearchNumberTask,或其子类,文章好像木有说明,原著里边p201也没发现详细说明。

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

    return top

    爱投彩票 oa0| akc| ky0| meg| g8e| ywc| 8sm| iy8| ecg| o8k| yek| squ| 9es| si9| yea| i9k| kag| 7mk| iy7| isg| e8g| kag| 8ca| ic8| oe8| sio| i8u| qoe| 6yu| io7| 7kg| ww7| caq| q7m| eua| 7go| qq7| yo7| csm| a8u| sig| 6yk| io6| wea| y6q| mag| 6oc| uc6| ccy| o7y| g7g| mkq| 5mu| ek5| omu| m5e| yym| 5ea| aqy| 6mk|