Fork/Join框架


  Fork/Join框架的核心是由下列兩個類組成的。

  工作竊取算法

  工作竊取(work-stealing)算法是指某個線程從其他隊列里竊取任務來執行。

  那么為什么需要使用工作竊取算法呢?假如我們需要做一個比較大的任務,我們可以把這個任務分割為若干互不依賴的子任務,為了減少線程間的競爭,於是把這些子任務分別放到不同的隊列里,並為每個隊列創建一個單獨的線程來執行隊列里的任務,線程和隊列一一對應,比如A線程負責處理A隊列里的任務。但是有的線程會先把自己隊列里的任務干完,而其他線程對應的隊列里還有任務等待處理。干完活的線程與其等着,不如去幫其他線程干活,於是它就去其他線程的隊列里竊取一個任務來執行。而在這時它們會訪問同一個隊列,所以為了減少竊取任務線程和被竊取任務線程之間的競爭,通常會使用雙端隊列,被竊取任務線程永遠從雙端隊列的頭部拿任務執行,而竊取任務的線程永遠從雙端隊列的尾部拿任務執行。

  • ForkJoinPool:這個類實現了ExecutorService接口和工作竊取算法(Work-Stealing Algorithm)。它管理工作者線程,並提供任務的狀態信息,以及任務的執行信息。
  • ForkJoinTask:這個類是一個將在ForkJoinPool中執行的任務的基類。

  Fork/Join框架提供了在一個任務里執行fork()和join()操作的機制和控制任務狀態的方法。通常,為了實現Fork/Join任務,需要實現一個以下兩個類之一的子類。

  • RecursiveAction:用於任務沒有返回結果的場景。
  • RecursiveTask:用於任務有返回結果的場景。

1. 創建Fork/join線程池

  下面我們將學習如何使用Fork/Join框架的基本元素。它包括:

  • 創建用來執行任務的ForkJoinPool對象;
  • 創建即將在線程池中被執行的任務ForkJoinTask子類。

  本范例中即將使用的Fork/Join框架的主要特性如下:

  • 采用默認的構造器創建ForkJoinPool對象;
  • 在任務中將使用JavaAPI文檔推薦的結構。
if (problem size > default size) {
    tasks = divide(task);
    execute(tasks);
} else {
    resolve problem using another algorithm;
}
  • 我們將以同步的方式執行任務。當一個主任務執行兩個或者更多的子任務時,這個主任務將等待子任務的完成。用這種方法,執行主任務的線程,稱之為工作者線程(Worker Thread),它將尋找其它的子任務來執行,並在子任務執行的時間里利用所有的線程優勢。
  • 如果將要實現的任務沒有返回任何結果,那么,采用RecursiveAction類作為實現任務的基類。

  在本節,我們將實現一項更新產品價格的任務。最初的任務將負責更新列表中的所有元素。我們使用10來作為參考大小(ReferenceSize),如果一個任務需要更新大於10個元素,它會將這個列表分解成為兩部分,然后分別創建兩個任務用來更新各自部分的產品價格。

1. 創建一個名為Product的類,用來存儲產品的名稱和價格。

public class Product {
    
    private String name;
    private double price;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public double getPrice() {
        return price;
    }
    public void setPrice(double price) {
        this.price = price;
    }
        
}

2. 創建一個名為ProductListGenerator的類,用來生成一個隨機的產品列表。

import java.util.ArrayList;
import java.util.List;

public class ProductListGenerator {
    
    public List<Product> generate(int size){
        List<Product> ret = new ArrayList<Product>();
        for(int i=0;i<size;i++){
            Product product = new Product();
            product.setName("Product " + i);
            product.setPrice(10);
            ret.add(product);
        }
        return ret;
    }
}

3. 創建一個名為Task的類,並繼承RecursiveAction類。

import java.util.List;
import java.util.concurrent.RecursiveAction;


public class Task extends RecursiveAction {

    private static final long serialVersionUID = 1L;
    private List<Product> products;
    private int first;
    private int last;
    private double increasement;
    
    public Task(List<Product> products, int first, int last, double increasement){
        this.products = products;
        this.first = first;
        this.last = last;
        this.increasement = increasement;
    }
    
    @Override
    protected void compute() {
        if(last-first<10){
            updatePrices();
        }else{
            int middle = (last+first)/2;
            System.out.printf("Task: Pending tasks: %s\n", this.getQueuedTaskCount());
            Task t1 = new Task(products, first, middle+1,increasement);
            Task t2 = new Task(products, middle+1, last, increasement);
            this.invokeAll(t1, t2);
        }
        
    }
    
    private void updatePrices(){
        for(int i=first;i<last;i++){
            Product product = products.get(i);
            product.setPrice(product.getPrice()*(1+increasement));
        }
    }
    
}

4. 實現范例的主類,創建Main主類,並實現main()方法。

import java.util.List;
import java.util.concurrent.ForkJoinPool;


public class Main {

    public static void main(String[] args) {
        ProductListGenerator generator = new ProductListGenerator();
        List<Product> products = generator.generate(10000);
        Task task = new Task(products, 0, products.size(), 0.20);
        //通過無參的類構造器創建一個ForkJoinPool
        ForkJoinPool pool = new ForkJoinPool();
        //調用execute()方法執行任務
        pool.execute(task);
        //顯示關於線程池演變的信息
        try {
            while(!task.isDone()){
                System.out.printf("Main: Thread Count: %d\n", pool.getActiveThreadCount());
                System.out.printf("Main: Thread Steal: %d\n", pool.getStealCount());
                System.out.printf("Main: Parallelism: %d\n", pool.getParallelism());
                Thread.sleep(5);
            }
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //關閉線程池
        pool.shutdown();
        if(task.isCompletedNormally()){
            System.out.println("Main: The process has completed normally.");
        }
        //確認是否所有的價格都已經改變
        for(int i=0;i<products.size();i++){
            Product product = products.get(i);
            if(product.getPrice()!=12)
                System.out.printf("Product %s: %f\n", product.getName(), product.getPrice());
        }
        System.out.println("Main: End of the program.");
    }
}

5. 程序運行結果如下

Task: Pending tasks: 0
Main: Thread Count: 1
Main: Thread Steal: 0
Main: Parallelism: 2
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 8
Task: Pending tasks: 9
Task: Pending tasks: 10
Task: Pending tasks: 9
Task: Pending tasks: 8
Task: Pending tasks: 9
Task: Pending tasks: 7
Task: Pending tasks: 8
Task: Pending tasks: 9
Task: Pending tasks: 7
Task: Pending tasks: 8
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 8
Task: Pending tasks: 9
Task: Pending tasks: 8
Task: Pending tasks: 7
Task: Pending tasks: 8
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 8
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 8
Task: Pending tasks: 9
Task: Pending tasks: 8
Task: Pending tasks: 7
Task: Pending tasks: 8
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 8
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 8
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 8
Task: Pending tasks: 9
Task: Pending tasks: 8
Task: Pending tasks: 7
Task: Pending tasks: 8
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 8
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 8
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 8
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 0
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Main: Thread Count: 2
Main: Thread Steal: 0
Main: Parallelism: 2
Task: Pending tasks: 8
Task: Pending tasks: 9
Task: Pending tasks: 8
Task: Pending tasks: 7
Task: Pending tasks: 8
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 8
Task: Pending tasks: 6
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 8
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 8
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 8
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 7
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 8
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Main: Thread Count: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 8
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Main: Thread Steal: 0
Main: Parallelism: 2
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Main: Thread Count: 2
Main: Thread Steal: 0
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 5
Main: Parallelism: 2
Task: Pending tasks: 3
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 8
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 0
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 8
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 6
Task: Pending tasks: 4
Main: Thread Count: 2
Task: Pending tasks: 5
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Main: Thread Steal: 0
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 5
Main: Parallelism: 2
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 8
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Main: Thread Count: 2
Task: Pending tasks: 5
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 3
Task: Pending tasks: 4
Main: Thread Steal: 0
Main: Parallelism: 2
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 0
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 8
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 3
Task: Pending tasks: 2
Task: Pending tasks: 4
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Main: Thread Count: 2
Main: Thread Steal: 0
Main: Parallelism: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 0
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 0
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 4
Main: Thread Count: 2
Main: Thread Steal: 0
Main: Parallelism: 2
Task: Pending tasks: 3
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 0
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 0
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 7
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 0
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 6
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 0
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 5
Task: Pending tasks: 4
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 0
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 3
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 0
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 0
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 0
Task: Pending tasks: 1
Task: Pending tasks: 0
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 4
Task: Pending tasks: 3
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 0
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 0
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 0
Task: Pending tasks: 1
Task: Pending tasks: 0
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 3
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 0
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 0
Task: Pending tasks: 1
Task: Pending tasks: 0
Task: Pending tasks: 1
Task: Pending tasks: 2
Task: Pending tasks: 0
Task: Pending tasks: 1
Task: Pending tasks: 0
Task: Pending tasks: 1
Task: Pending tasks: 0
Task: Pending tasks: 5
Main: Thread Count: 2
Main: Thread Steal: 7
Main: Parallelism: 2
Main: The process has completed normally.
Main: End of the program.
View Code

   ForkJoinPool類還提供了一下方法用於執行任務。

  • execute(Runnabletask):這是本范例中使用的execute()方法的另一個版本。這個方法發送一個Runnable任務給ForkJoinPool類。需要注意的是,使用Runnable對象時ForkJoinPool類就不采用工作竊取算法,FrokJoinPool類僅在使用ForkJoinTask類時才采用工作竊取算法。
  • invoke(ForkJoinTask<T>task):正如范例所示,ForkJoinPool類的execute()方法是異步調用的,而ForkJoinPool類的invoke()方法則是同步調用的。這個方法傳遞進來的任務執行結束后才會返回。
  • 也可以使用ExecutorService類中聲明的invokeAll()和invokeAny()方法,這些方法接收Callalbe對象作為參數。使用Callable對象時ForkJoinPool類就不采用工作竊取算法,因此,最好使用執行器來執行Callable對象。

  ForkJoinTask類也包含了在范例中使用的invokeAll()方法的其他版本,這些版本如下。

  • invokeAll(ForkJoinTask<?>...tasks):這個版本的方法接收一個可變的參數列表,可以傳遞盡可能多的ForkJoinTask對象給這個方法作為參數。
  • invokeAll(Collection<T>tasks):這個版本的方法接受一個泛型類型T的對象集合(比如,ArrayList對象、LinkedList對象或者TreeSet對象)。這個泛型類型T必須是ForkJoinTask類或者它的子類。

  雖然ForkJoinPool類是設計用來執行ForkJoinTask對象的,但也可以直接用來執行Runnable和Callable對象。當然,也可以使用ForkJoinTask類的adapt()方法來接收一個Callable對象或者一個Runnable對象,然后將之轉換為一個ForkJoinTask對象,然后再去執行。

2. 合並任務的結果

  Fork/join框架提供了執行任務並返回結果的能力。這些類型的任務都是通過RecursiveTask類來實現的。RecursiveTask類繼承了ForkJoinTask類,並且實現了由執行器框架提供的Future接口。

  在任務中,必須使用JavaAPI文檔推薦的如下結構:

if (problem size > size) {
    tasks = Divide(task);
    execute(tasks);
    groupResults();
    return result;
} else {
    resolve problem;
    return result;
}

  如果任務需要解決的問題大於預先定義的大小,那么就要將這個問題拆分成多個子任務,並使用Fork/Join框架來執行這些子任務。執行完成后,原始任務獲取到由所有這些子任務產生的結果,合並這些結果,返回最終的結果。當原始任務在線程池中執行結束后,將高效地獲取到整個問題的最終結果。

  下面我們將學習如何使用Fork/Join框架來解決這種問題,開發一個應用程序,在文檔中查找一個詞。我們將實現以下兩種任務:

  • 一個文檔任務,它將遍歷文檔中的每一行來查找這個詞;
  • 一個行任務,它將在文檔的一部分當中查找這個詞。

  所有這些任務將返回文檔或行中所出現這個詞的次數。

1. 創建一個名為DocumentMock的類。它將生成一個字符串矩陣來模擬一個文檔。

import java.util.Random;

public class DocumentMock {
    private String words[] = {"the", "hello", "goodbye", "packet",
            "java", "thread", "pool", "random","class","main"};
    /**
     * 
     * @param numLines 行數
     * @param numWrods 每行單詞個數
     * @param word 要查找的單詞
     * @return
     */
     public String[][] generateDocument(int numLines, int numWords, String word){
         //統計要查找單詞出現次數,以便和程序並行運算合並結果做對比
         int counter = 0;
         String document[][] = new String[numLines][numWords];
         Random random = new Random();
         for(int i=0;i<numLines;i++){
             for(int j=0;j<numWords;j++){
                 int index = random.nextInt(words.length);
                 document[i][j] = words[index];
                 if(document[i][j].equals(word))
                     counter++;
             }
         }
         System.out.println("DocumentMock: The word appears "+counter+" times in the document");
         return document;
     }
}

2. 創建名為DocumentTask的類,並繼承RecursiveTask類,RecursiveTask類的泛型參數為Integer類型。這個DocumentTask類將實現一個任務,用來計算所要查詢的詞在文檔中出現的次數。

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.RecursiveTask;


public class DocumentTask extends RecursiveTask<Integer> {

    private static final long serialVersionUID = 1L;
    private String document[][];
    private String word;
    private int start, end;
    
    public DocumentTask(String document[][], int start, int end, String word){
        this.document = document;
        this.start = start;
        this.end = end;
        this.word = word;
    }
    
    @Override
    protected Integer compute() {
        int result = 0;
        if(end-start<10)
            result = processLines(document, start, end, word);
        else{
            int mid = (start+end)/2;
            DocumentTask task1 = new DocumentTask(document, start, mid+1, word);
            DocumentTask task2 = new DocumentTask(document, mid+1, end, word);
            this.invokeAll(task1, task2);
            try {
                result = groupResults(task1.get(), task2.get());
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (ExecutionException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return result;
    }
    
    private int processLines(String[][] document, int start, int end, String word){
        List<LineTask> tasks = new ArrayList<>();
        for(int i=start;i<end;i++){
            LineTask task = new LineTask(document[i], 0, document[i].length, word);
            tasks.add(task);
        }
        //執行列表中所有任務
        this.invokeAll(tasks);
        int result=0;
        try {
            for(int i=0;i<tasks.size();i++){
                LineTask task = tasks.get(i);
                result += task.get();
            }
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ExecutionException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return result;
    }
    
    private int groupResults(int num1, int num2){
        int result;
        result = num1 + num2;
        return result;
    }
}

3. 創建名為LineTask的類,並繼承RecursiveTask類,實現一個任務,用來計算所要查找的單詞在一行中出現的次數。

import java.util.concurrent.ExecutionException;
import java.util.concurrent.RecursiveTask;


public class LineTask extends RecursiveTask<Integer> {

    private static final long serialVersionUID = 1L;
    private String[] line;
    private int start, end;
    private String word;
    
    public LineTask(String[] line, int start, int end, String word){
        this.line = line;
        this.start = start;
        this.end = end;
        this.word = word;
    }
    
    @Override
    protected Integer compute() {
        int result = 0;
        if(end-start<100)
            result = count(line, start, end, word);
        else{
            int mid = (start+end)/2;
            LineTask task1 = new LineTask(line, start, mid+1, word);
            LineTask task2 = new LineTask(line, mid+1, end, word);
            //執行兩個任務
            this.invokeAll(task1, task2);
            try {
                result = groupResults(task1.get(), task2.get());
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (ExecutionException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return result;
    }
    
    private int count(String[] line, int start, int end, String word){
        int cnt = 0;
        for(int i=start;i<end;i++){
            if(line[i].equals(word))
                cnt++;
        }
        return cnt;
    }
    
    private int groupResults(int cnt1, int cnt2){
        return cnt1+cnt2;
    }
}

4. 實現范例的主類Main,並實現main()方法。

import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit;


public class Main {

    public static void main(String[] args) {
        DocumentMock mock = new DocumentMock();
        String[][] document = mock.generateDocument(100, 1000, "the");
        DocumentTask task = new DocumentTask(document, 0, 100, "the");
        ForkJoinPool pool = new ForkJoinPool();
        pool.execute(task);
        //顯示線程進展信息
        try {
            while(!task.isDone()){
                System.out.println("***************************************************");
                System.out.printf("Main: Parallelism: %d\n", pool.getParallelism());
                System.out.printf("Main: Active Threads: %d\n", pool.getActiveThreadCount());
                System.out.printf("Main: Task Count: %d\n", pool.getQueuedTaskCount());
                System.out.printf("Main: Steal Count: %d\n", pool.getStealCount());
                System.out.println("***************************************************");
                TimeUnit.SECONDS.sleep(1);
            }
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //關閉線程池
        pool.shutdown();
        try {
            pool.awaitTermination(1, TimeUnit.DAYS);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        try {
            System.out.printf("Main: The word appears %d times in the document", task.get());
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ExecutionException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

5. 程序運行結果如下

DocumentMock: The word appears 10102 times in the document
***************************************************
Main: Parallelism: 2
Main: Active Threads: 0
Main: Task Count: 0
Main: Steal Count: 2
***************************************************
Main: The word appears 10102 times in the document
View Code

  ForkJoinTask類提供了另一個complete()方法來結束任務的執行並返回結果。這個方法接收一個對象,對象的類型就是RecursiveTask類的泛型參數,然后在任務調用join()方法后返回這個對象作為結果。這一過程采用了推薦的異步任務來返回任務的結果。

3. 異步運行任務

  在ForkJoinPool中執行ForkJoinTask時,可以采用同步或者異步方式。當采用同步方式執行時,發送任務給Fork/Join線程池的方法直到任務執行完成后才會返回結果。而采用異步方式執行時,發送任務給執行器的方法將立即返回結果,但是任務仍能夠繼續執行。

  需要明白這兩種方式在執行任務時的一個很大的區別。當采用同步方式,調用這些方法(比如,invokeAll()方法)時,任務被掛起,直到任務被發送到Fork/Join線程池中執行完成。這種方式允許ForkJoinPool類采用工作竊取算法(Work-StealingAlgorithm)來分配一個新任務給在執行休眠任務的工作者線程。相反,當采用異步方法(比如,fork()方法)時,任務將繼續執行,一次ForkJoinPool類無法使用工作竊取算法來提升應用程序的性能。在這個示例中,只有調用join()或get()方法來等待任務的結束時,ForkJoinPool類才可以使用工作竊取算法。

  下面我們將學習如何使用ForkJoinPool和ForkJoinTask類所提供的異步方法來管理任務。我們將實現一個程序:在一個文件夾及其子文件夾中來搜索帶有指定擴展名的文件。ForkJoinTask類將實現處理這個文件夾的內容。而對於這個文件夾中的每一個子文件,任務將以異步的方式發送一個新的任務給ForkJoinPool類。對於每個文件夾中的文件,任務將檢查任務文件的擴展名,如果符合條件就將其增加到結果列表中。

1. 創建名為FolderProcessor的類,並繼承RecursiveTask類。

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.RecursiveTask;


public class FolderProcessor extends RecursiveTask<List<String>> {

    private static final long serialVersionUID = 1L;
    private String path;
    private String extension;
    
    public FolderProcessor(String path, String extension){
        this.path = path;
        this.extension = extension;
    }
    
    @Override
    protected List<String> compute() {
        List<String> list = new ArrayList<>();
        List<FolderProcessor> tasks = new ArrayList<>();
        File file = new File(path);
        File[] content = file.listFiles();
        if(content!=null){
            for(int i=0;i<content.length;i++){
                if(content[i].isDirectory()){
                    FolderProcessor task = new FolderProcessor(content[i].getAbsolutePath(), extension);
                    //采用異步方式執行任務
                    task.fork();
                    tasks.add(task);
                }else{
                    if(checkFile(content[i].getName()))
                        list.add(content[i].getAbsolutePath());
                }
            }
            if(tasks.size()>50)
                System.out.printf("%s: %d tasks run.\n", file.getAbsolutePath(), tasks.size());
            addResultFromTasks(list, tasks);
        }
        return list;
    }
    
    private boolean checkFile(String name){
        return name.endsWith(extension);
    }
    
    //等待所有的任務運行結束
    private void addResultFromTasks(List<String> list, List<FolderProcessor> tasks){
        for(FolderProcessor item:tasks){
            list.addAll(item.join());
        }
    }
}

2. 實現范例的主類Main,並實現main()方法。

import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.TimeUnit;


public class Main {

    public static void main(String[] args) {    
        //創建線程池
        ForkJoinPool pool = new ForkJoinPool();
        //創建三個任務
        FolderProcessor system = new FolderProcessor("C:\\Windows", "log");
        FolderProcessor apps = new FolderProcessor("C:\\Program Files", "log");
        FolderProcessor documents = new FolderProcessor("C:\\Documents And Settings", "log");
        //執行任務
        pool.execute(system);
        pool.execute(apps);
        pool.execute(documents);
        //顯示線程進展信息
        try {
            while((!system.isDone())||(!apps.isDone())||(!documents.isDone())){
                System.out.println("***************************************************");
                System.out.printf("Main: Parallelism: %d\n", pool.getParallelism());
                System.out.printf("Main: Active Threads: %d\n", pool.getActiveThreadCount());
                System.out.printf("Main: Task Count: %d\n", pool.getQueuedTaskCount());
                System.out.printf("Main: Steal Count: %d\n", pool.getStealCount());
                System.out.println("***************************************************");
                TimeUnit.SECONDS.sleep(1);
            }
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //關閉線程池
        pool.shutdown();
        List<String> results;
        results = system.join();
        System.out.printf("System: %d files found.\n", results.size());
        results = apps.join();
        System.out.printf("Apps: %d files found.\n", results.size());
        results = documents.join();
        System.out.printf("Documents: %d files found.\n", results.size());
    }
}

3. 程序部分運行結果如下

***************************************************
Main: Parallelism: 2
Main: Active Threads: 41
Main: Task Count: 323
Main: Steal Count: 10152
***************************************************
***************************************************
Main: Parallelism: 2
Main: Active Threads: 40
Main: Task Count: 297
Main: Steal Count: 10268
***************************************************
***************************************************
Main: Parallelism: 2
Main: Active Threads: 44
Main: Task Count: 237
Main: Steal Count: 10336
***************************************************
***************************************************
Main: Parallelism: 2
Main: Active Threads: 29
Main: Task Count: 150
Main: Steal Count: 10526
***************************************************
C:\Documents And Settings\DELL\Application Data\Tencent\QQ\Misc\MsgBubble: 126 tasks run.
***************************************************
Main: Parallelism: 2
Main: Active Threads: 23
Main: Task Count: 305
Main: Steal Count: 10596
***************************************************
***************************************************
Main: Parallelism: 2
Main: Active Threads: 8
Main: Task Count: 61
Main: Steal Count: 10865
***************************************************
System: 10 files found.
Apps: 1702 files found.
Documents: 611 files found.
View Code

  本范例使用join()方法來等待任務的結束,然后獲取它們的結果。也可以使用get()方法以下的兩個版本來完成這個目的。

  • get():如果ForkJoinTask類執行結束,或者一直等到結束,那么get()方法的這個版本則返回由compute()方法返回的結果。
  • get(long timeout, TimeUnit unit):如果任務的結果未准備好,那么get()方法的這個版本將等待指定的時間。如果超過了指定的時間,任務的結果仍未能准備好,那么這個方法就返回null值。

  get()方法和join()方法還存在兩個主要的區別:

  • join()方法不能被中斷,如果中斷調用join()方法的線程,方法將拋出InterruptedException異常。
  • 如果任務拋出任何運行時異常,那么get()方法將返回ExecutionException異常,但是join()方法將返回RunntimeException異常。

 4. 在任務中拋出異常

  不能在ForkJoinTask類的compute()方法中拋出任務非運行時異常,因為這個方法的實現沒有包含任何throws聲明。因此,需要包含必需的代碼來處理相關的異常。另一方面,compute()方法可以拋出運行時異常(它可以是任何方法或者方法內的對象拋出的異常)。ForkJoinTask類和ForkJoinPool類的行為與我們期待的可能不同。在控制台上,程序沒有結束執行,不能看到任務異常信息。如果異常不被拋出,那么它只是簡單地將異常吞噬掉。然而,我們能夠利用ForkJoinTask類的一些方法來獲知任務是否有異常拋出,以及拋出哪一種類型的異常。

  下面,我們將學習如何獲取這些異常信息。

1. 創建名為Task的類,並繼承RecursiveTask類。

import java.util.concurrent.RecursiveTask;
import java.util.concurrent.TimeUnit;

public class Task extends RecursiveTask<Integer> {

    private static final long serialVersionUID = 1L;
    private int array[];
    private int start, end;
    
    public Task(int array[], int start, int end){
        this.array = array;
        this.start = start;
        this.end = end;
    }
    
    @Override
    protected Integer compute() {
        System.out.printf("Task: Start from %d to %d\n", start, end);
        if(end-start<10){
            if(start<3&&end>3)
                throw new RuntimeException("This task throws an Exception: Task from "+start+" to "+end);
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }else{
            int mid = (start+end)/2;
            Task task1 = new Task(array, start, mid);
            Task task2 = new Task(array, mid, end);
            //執行兩個任務並等待完成
            this.invokeAll(task1, task2);
        }
        System.out.printf("Task: End from %d to %d\n", start, end);
        return 0;
    }

}

2. 實現范例的主類Main,並實現main()方法。

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit;

public class Main {

    public static void main(String[] args) {    
        //創建線程池
        ForkJoinPool pool = new ForkJoinPool();
        int array[] = new int[100];
        Task task = new Task(array, 0, 100);
        //執行任務
        pool.execute(task);
        pool.shutdown();
        //等待任務執行結束
        try {
            pool.awaitTermination(1, TimeUnit.DAYS);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //判斷是否非正常結束
        if(task.isCompletedAbnormally()){
            System.out.println("Main: An exception has ocurred");
            //獲取異常信息
            System.out.println("Main: "+task.getException());
        }
        System.out.println("Main: Result: "+task.join());
    }
}

3. 程序運行結果如下

Task: Start from 0 to 100
Task: Start from 0 to 50
Task: Start from 0 to 25
Task: Start from 0 to 12
Task: Start from 0 to 6
Task: Start from 6 to 12
Task: Start from 50 to 100
Task: Start from 50 to 75
Task: Start from 50 to 62
Task: Start from 50 to 56
Task: End from 50 to 56
Task: Start from 56 to 62
Task: End from 6 to 12
Task: Start from 12 to 25
Task: Start from 12 to 18
Task: End from 56 to 62
Task: End from 12 to 18
Task: Start from 18 to 25
Task: End from 50 to 62
Task: Start from 62 to 75
Task: Start from 62 to 68
Task: End from 18 to 25
Task: End from 12 to 25
Task: Start from 25 to 50
Task: Start from 25 to 37
Task: Start from 25 to 31
Task: End from 62 to 68
Task: Start from 68 to 75
Task: End from 25 to 31
Task: Start from 31 to 37
Task: End from 68 to 75
Task: End from 62 to 75
Task: End from 50 to 75
Task: Start from 75 to 100
Task: Start from 75 to 87
Task: Start from 75 to 81
Task: End from 31 to 37
Task: End from 25 to 37
Task: Start from 37 to 50
Task: Start from 37 to 43
Task: End from 75 to 81
Task: Start from 81 to 87
Task: End from 37 to 43
Task: Start from 43 to 50
Task: End from 81 to 87
Task: End from 75 to 87
Task: Start from 87 to 100
Task: Start from 87 to 93
Task: End from 43 to 50
Task: End from 37 to 50
Task: End from 25 to 50
Task: Start from 93 to 100
Task: End from 87 to 93
Task: End from 93 to 100
Task: End from 87 to 100
Task: End from 75 to 100
Task: End from 50 to 100
Main: An exception has ocurred
Main: java.lang.RuntimeException: java.lang.RuntimeException: This task throws an Exception: Task from 0 to 6
Exception in thread "main" java.lang.RuntimeException: java.lang.RuntimeException: This task throws an Exception: Task from 0 to 6
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
    at java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:533)
    at java.util.concurrent.ForkJoinTask.reportResult(ForkJoinTask.java:596)
    at java.util.concurrent.ForkJoinTask.join(ForkJoinTask.java:640)
    at Main.main(Main.java:31)
Caused by: java.lang.RuntimeException: This task throws an Exception: Task from 0 to 6
    at Task.compute(Task.java:21)
    at Task.compute(Task.java:1)
    at java.util.concurrent.RecursiveTask.exec(RecursiveTask.java:93)
    at java.util.concurrent.ForkJoinTask.doInvoke(ForkJoinTask.java:377)
    at java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:654)
    at java.util.concurrent.ForkJoinTask.invokeAll(ForkJoinTask.java:685)
    at Task.compute(Task.java:33)
    at Task.compute(Task.java:1)
    at java.util.concurrent.RecursiveTask.exec(RecursiveTask.java:93)
    at java.util.concurrent.ForkJoinTask.doInvoke(ForkJoinTask.java:377)
    at java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:654)
    at java.util.concurrent.ForkJoinTask.invokeAll(ForkJoinTask.java:685)
    at Task.compute(Task.java:33)
    at Task.compute(Task.java:1)
    at java.util.concurrent.RecursiveTask.exec(RecursiveTask.java:93)
    at java.util.concurrent.ForkJoinTask.doInvoke(ForkJoinTask.java:377)
    at java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:654)
    at java.util.concurrent.ForkJoinTask.invokeAll(ForkJoinTask.java:685)
    at Task.compute(Task.java:33)
    at Task.compute(Task.java:1)
    at java.util.concurrent.RecursiveTask.exec(RecursiveTask.java:93)
    at java.util.concurrent.ForkJoinTask.doInvoke(ForkJoinTask.java:377)
    at java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:654)
    at java.util.concurrent.ForkJoinTask.invokeAll(ForkJoinTask.java:685)
    at Task.compute(Task.java:33)
    at Task.compute(Task.java:1)
    at java.util.concurrent.RecursiveTask.exec(RecursiveTask.java:93)
    at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:334)
    at java.util.concurrent.ForkJoinWorkerThread.execTask(ForkJoinWorkerThread.java:604)
    at java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:784)
    at java.util.concurrent.ForkJoinPool.work(ForkJoinPool.java:646)
    at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:398)
View Code

  雖然運行這個程序時將拋出異常,但是程序不會停止。在Main主類中,調用原始任務ForkJoinTask類的isCompletedAbnormally()方法,如果主任務或者它的子任務之一拋出了異常,這個方法將返回true。也可以使用getException()方法來獲得拋出的Exception對象。

  當任務拋出運行時異常時,會影響它的父任務(發送到ForkJoinPool類的任務),以及父任務的父任務,以此類推。查閱程序的輸出結果,將會發現有一些任務沒有結束的信息。這些任務是那些拋出異常的任務和它的父任務。所有這些任務都是異常結束的。記住一點:在用ForkJoinPool對象和ForkJoinTask對象開發一個程序時,它們是會拋出異常的,如果不想要這種行為,就得采用其他方式。

  在范例中,不采用拋出異常,而調用ForkJoinTask類的completeExceptionally()方法也可以獲得同樣的結果。代碼如下所示:

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

5. 取消任務

   在ForkJoinPool類中執行ForkJoinTask對象時,在任務開始執行前可以取消它。ForkJoinTask類提供了cancel()方法來達到取消任務的目的。在取消一個任務時必須要注意以下兩點:

  • ForkJoinPool類不提供任何方法來取消線程池中正在運行或者等待運行的所有任務;
  • 取消任務時,不能取消已經被執行的任務。

  下面,我們將實現一個取消ForkJoinTask對象的范例。該范例將尋找數組中某個數字所處的位置。第一個任務時尋找可以被取消的剩余任務數。由於Fork/Join框架沒有提供取消功能,我們將創建一個輔助類來實現取消任務的操作。

1. 創建一個名為ArrayGenerator的類。這個類將生成一個指定大小的隨機整數數組。

import java.util.Random;

public class ArrayGenerator {
    public int[] generator(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類的局限性,將利用TaskManager類來取消ForkJoinPool類中的所有任務。

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ForkJoinTask;

public class TaskManager {
    //存放任務
    private List<ForkJoinTask<Integer>> tasks;
    
    public TaskManager(){
        tasks = new ArrayList<>();
    }
    
    public void addTask(ForkJoinTask<Integer> task){
        tasks.add(task);
    }
    
    public void cancelTasks(ForkJoinTask<Integer> cancelTask){
        for(ForkJoinTask<Integer> task:tasks){
            if(task!=cancelTask){
                task.cancel(true);
                ((SearchNumberTask)task).writeCancelMessage();
            }
        }
    }
}

3. 實現SearchNumberTask類,並繼承RecursiveTask類,RecursiveTask類的泛型參數為Integer類型。這個類將尋找在整數數組元素塊中的一個數字。

import java.util.concurrent.RecursiveTask;
import java.util.concurrent.TimeUnit;


public class SearchNumberTask extends RecursiveTask<Integer> {

    private static final long serialVersionUID = 1L;
    private int array[]; //要查找的數組
    private int start, end;
    private int number; //要查找的數字
    private TaskManager manager; //用來取消所有任務
    //聲明一個int常量,並初始化為-1,當任務找不到數字時將返回這個常量
    private final static int  NOT_FOUND = -1;
    
    public SearchNumberTask(int array[], int start, int end, int number, TaskManager manager){
        this.array = array;
        this.start = start;
        this.end = end;
        this.number = number;
        this.manager = manager;
    }
    
    @Override
    protected Integer compute() {
        System.out.println("Task: "+start+":"+end);
        int ret;
        if(end-start>10){
            ret = launchTasks();
        }else{
            ret = lookForNumber();
        }
        return ret;
    }
    
    private int launchTasks(){
        int mid = (start+end)/2;
        SearchNumberTask task1 = new SearchNumberTask(array, start, mid, number, manager);
        SearchNumberTask task2 = new SearchNumberTask(array, mid, end, number, manager);
        manager.addTask(task1);
        manager.addTask(task2);
        //采用異步方式執行兩個任務
        task1.fork();
        task2.fork();
        int ret;
        ret = task1.join();
        if(ret!=-1)
            return ret;
        ret = task2.join();
        return ret;
    }
    
    private int lookForNumber(){
        try {
            for(int i=start;i<end;i++){
                if(array[i]==number){
                    System.out.printf("SearchNumberTask: Number %d found in position %d\n", number, i);
                    manager.cancelTasks(this);
                    return i;
                }
                TimeUnit.SECONDS.sleep(1);
            }
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return NOT_FOUND;
    }

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

4. 實現范例的主類Main,並實現main()方法。

import java.util.concurrent.RecursiveTask;
import java.util.concurrent.TimeUnit;


public class SearchNumberTask extends RecursiveTask<Integer> {

    private static final long serialVersionUID = 1L;
    private int array[]; //要查找的數組
    private int start, end;
    private int number; //要查找的數字
    private TaskManager manager; //用來取消所有任務
    //聲明一個int常量,並初始化為-1,當任務找不到數字時將返回這個常量
    private final static int  NOT_FOUND = -1;
    
    public SearchNumberTask(int array[], int start, int end, int number, TaskManager manager){
        this.array = array;
        this.start = start;
        this.end = end;
        this.number = number;
        this.manager = manager;
    }
    
    @Override
    protected Integer compute() {
        System.out.println("Task: "+start+":"+end);
        int ret;
        if(end-start>10){
            ret = launchTasks();
        }else{
            ret = lookForNumber();
        }
        return ret;
    }
    
    private int launchTasks(){
        int mid = (start+end)/2;
        SearchNumberTask task1 = new SearchNumberTask(array, start, mid, number, manager);
        SearchNumberTask task2 = new SearchNumberTask(array, mid, end, number, manager);
        manager.addTask(task1);
        manager.addTask(task2);
        //采用異步方式執行兩個任務
        task1.fork();
        task2.fork();
        int ret;
        ret = task1.join();
        if(ret!=-1)
            return ret;
        ret = task2.join();
        return ret;
    }
    
    private int lookForNumber(){
        try {
            for(int i=start;i<end;i++){
                if(array[i]==number){
                    System.out.printf("SearchNumberTask: Number %d found in position %d\n", number, i);
                    manager.cancelTasks(this);
                    return i;
                }
                TimeUnit.SECONDS.sleep(1);
            }
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return NOT_FOUND;
    }

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

5. 程序運行結果如下

Task: 0:1000
Task: 0:500
Task: 500:1000
Task: 500:750
Task: 0:250
Task: 750:1000
Task: 0:125
Task: 750:875
Task: 750:812
Task: 875:1000
Task: 125:250
Task: 500:625
Task: 812:875
Task: 812:843
Task: 0:62
Task: 125:187
Task: 250:500
Task: 843:875
Task: 250:375
Task: 375:500
Task: 62:125
Task: 125:156
Task: 843:859
Task: 875:937
Task: 625:750
Task: 0:31
Task: 937:1000
Task: 31:62
Task: 0:15
Task: 937:968
Task: 62:93
Task: 156:187
Task: 93:125
Task: 375:437
Task: 187:250
Task: 859:875
Task: 437:500
Task: 62:77
Task: 77:93
Task: 625:687
Task: 250:312
Task: 687:750
Task: 968:1000
Task: 843:851
SearchNumberTask: Number 5 found in position 849
Task: Cancelled task from 0 to 500
Task: Cancelled task from 500 to 1000
Task: Cancelled task from 0 to 250
Task: Cancelled task from 250 to 500
Task: Cancelled task from 500 to 750
Task: Cancelled task from 750 to 1000
Task: Cancelled task from 500 to 625
Task: Cancelled task from 625 to 750
Task: Cancelled task from 0 to 125
Task: 851:859
Task: Cancelled task from 125 to 250
Task: Cancelled task from 750 to 875
Task: Cancelled task from 875 to 1000
Task: Cancelled task from 0 to 62
Task: Cancelled task from 62 to 125
Task: Cancelled task from 750 to 812
Task: Cancelled task from 812 to 875
Task: Cancelled task from 750 to 781
Task: Cancelled task from 781 to 812
Task: Cancelled task from 875 to 937
Task: Cancelled task from 937 to 1000
Task: Cancelled task from 125 to 187
Task: Cancelled task from 187 to 250
Task: Cancelled task from 500 to 562
Task: Cancelled task from 562 to 625
Task: Cancelled task from 812 to 843
Task: Cancelled task from 843 to 875
Task: Cancelled task from 812 to 827
Task: Cancelled task from 827 to 843
Task: Cancelled task from 0 to 31
Task: Cancelled task from 31 to 62
Task: Cancelled task from 125 to 156
Task: Cancelled task from 156 to 187
Task: Cancelled task from 250 to 375
Task: Cancelled task from 375 to 500
Task: Cancelled task from 843 to 859
Task: Cancelled task from 859 to 875
Task: Cancelled task from 250 to 312
Task: Cancelled task from 312 to 375
Task: Cancelled task from 375 to 437
Task: Cancelled task from 437 to 500
Task: Cancelled task from 62 to 93
Task: Cancelled task from 93 to 125
Task: Cancelled task from 125 to 140
Task: Cancelled task from 140 to 156
Task: Cancelled task from 851 to 859
Task: Cancelled task from 875 to 906
Task: Cancelled task from 906 to 937
Task: Cancelled task from 625 to 687
Task: Cancelled task from 687 to 750
Task: Cancelled task from 0 to 15
Task: Cancelled task from 15 to 31
Task: Cancelled task from 937 to 968
Task: Cancelled task from 968 to 1000
Task: Cancelled task from 31 to 46
Task: Cancelled task from 46 to 62
Task: Cancelled task from 0 to 7
Task: Cancelled task from 7 to 15
Task: Cancelled task from 937 to 952
Task: Cancelled task from 952 to 968
Task: Cancelled task from 62 to 77
Task: Cancelled task from 77 to 93
Task: Cancelled task from 156 to 171
Task: Cancelled task from 171 to 187
Task: Cancelled task from 93 to 109
Task: Cancelled task from 109 to 125
Task: Cancelled task from 375 to 406
Task: 406:437
Task: Cancelled task from 406 to 437
Task: 687:718
Task: 687:702
Task: 62:69
SearchNumberTask: Number 5 found in position 856
Task: Cancelled task from 0 to 500
Task: Cancelled task from 500 to 1000
Task: Cancelled task from 0 to 250
Task: Cancelled task from 250 to 500
Task: Cancelled task from 500 to 750
Task: Cancelled task from 750 to 1000
Task: Cancelled task from 500 to 625
Task: Cancelled task from 625 to 750
Task: Cancelled task from 0 to 125
Task: Cancelled task from 125 to 250
Task: Cancelled task from 750 to 875
Task: Cancelled task from 875 to 1000
Task: Cancelled task from 0 to 62
Task: Cancelled task from 62 to 125
Task: Cancelled task from 750 to 812
Task: Cancelled task from 812 to 875
Task: Cancelled task from 750 to 781
Task: Cancelled task from 781 to 812
Task: Cancelled task from 875 to 937
Task: Cancelled task from 937 to 1000
Task: Cancelled task from 125 to 187
Task: Cancelled task from 187 to 250
Task: Cancelled task from 500 to 562
Task: Cancelled task from 562 to 625
Task: Cancelled task from 812 to 843
Task: Cancelled task from 843 to 875
Task: Cancelled task from 812 to 827
Task: Cancelled task from 827 to 843
Task: Cancelled task from 0 to 31
Task: Cancelled task from 31 to 62
Task: Cancelled task from 125 to 156
Task: Cancelled task from 156 to 187
Task: Cancelled task from 250 to 375
Task: Cancelled task from 375 to 500
Task: Cancelled task from 843 to 859
Task: Cancelled task from 859 to 875
Task: Cancelled task from 250 to 312
Task: Cancelled task from 312 to 375
Task: Cancelled task from 375 to 437
Task: Cancelled task from 437 to 500
Task: Cancelled task from 62 to 93
Task: Cancelled task from 93 to 125
Task: Cancelled task from 125 to 140
Task: Cancelled task from 140 to 156
Task: Cancelled task from 843 to 851
Task: Cancelled task from 875 to 906
Task: Cancelled task from 906 to 937
Task: Cancelled task from 625 to 687
Task: Cancelled task from 687 to 750
Task: Cancelled task from 0 to 15
Task: Cancelled task from 15 to 31
Task: Cancelled task from 937 to 968
Task: Cancelled task from 968 to 1000
Task: Cancelled task from 31 to 46
Task: Cancelled task from 46 to 62
Task: Cancelled task from 0 to 7
Task: Cancelled task from 7 to 15
Task: Cancelled task from 937 to 952
Task: Cancelled task from 952 to 968
Task: Cancelled task from 62 to 77
Task: Cancelled task from 77 to 93
Task: Cancelled task from 156 to 171
Task: Cancelled task from 171 to 187
Task: Cancelled task from 93 to 109
Task: Cancelled task from 109 to 125
Task: Cancelled task from 375 to 406
Task: Cancelled task from 406 to 437
Task: Cancelled task from 187 to 218
Task: Cancelled task from 218 to 250
Task: Cancelled task from 859 to 867
Task: 867:875
Task: Cancelled task from 867 to 875
Task: Cancelled task from 437 to 468
Task: Cancelled task from 468 to 500
Task: Cancelled task from 62 to 69
Task: 69:77
Task: Cancelled task from 69 to 77
Task: Cancelled task from 77 to 85
Task: Cancelled task from 85 to 93
Task: 656:687
Task: Cancelled task from 625 to 656
Task: 968:984
Task: 984:1000
Task: 702:718
Task: 718:750
Task: 702:710
Task: 710:718
SearchNumberTask: Number 5 found in position 706
Task: Cancelled task from 0 to 500
Task: Cancelled task from 500 to 1000
Task: Cancelled task from 0 to 250
Task: Cancelled task from 250 to 500
Task: Cancelled task from 500 to 750
Task: Cancelled task from 750 to 1000
Task: Cancelled task from 500 to 625
Task: Cancelled task from 625 to 750
Task: Cancelled task from 0 to 125
Task: Cancelled task from 125 to 250
Task: Cancelled task from 750 to 875
Task: Cancelled task from 875 to 1000
Task: Cancelled task from 0 to 62
Task: Cancelled task from 62 to 125
Task: Cancelled task from 750 to 812
Task: Cancelled task from 812 to 875
Task: Cancelled task from 750 to 781
Task: Cancelled task from 781 to 812
Task: Cancelled task from 875 to 937
Task: Cancelled task from 937 to 1000
Task: Cancelled task from 125 to 187
Task: Cancelled task from 187 to 250
Task: Cancelled task from 500 to 562
Task: Cancelled task from 562 to 625
Task: Cancelled task from 812 to 843
Task: Cancelled task from 843 to 875
Task: Cancelled task from 812 to 827
Task: Cancelled task from 827 to 843
Task: Cancelled task from 0 to 31
Task: Cancelled task from 31 to 62
Task: Cancelled task from 125 to 156
Task: Cancelled task from 156 to 187
Task: Cancelled task from 250 to 375
Task: Cancelled task from 375 to 500
Task: Cancelled task from 843 to 859
Task: Cancelled task from 859 to 875
Task: Cancelled task from 250 to 312
Task: Cancelled task from 312 to 375
Task: Cancelled task from 375 to 437
Task: Cancelled task from 437 to 500
Task: Cancelled task from 62 to 93
Task: Cancelled task from 93 to 125
Task: Cancelled task from 125 to 140
Task: Cancelled task from 140 to 156
Task: Cancelled task from 843 to 851
Task: Cancelled task from 851 to 859
Task: Cancelled task from 875 to 906
Task: Cancelled task from 906 to 937
Task: Cancelled task from 625 to 687
Task: Cancelled task from 687 to 750
Task: Cancelled task from 0 to 15
Task: Cancelled task from 15 to 31
Task: Cancelled task from 937 to 968
Task: Cancelled task from 968 to 1000
Task: Cancelled task from 31 to 46
Task: Cancelled task from 46 to 62
Task: Cancelled task from 0 to 7
Task: Cancelled task from 7 to 15
Task: Cancelled task from 937 to 952
Task: Cancelled task from 952 to 968
Task: Cancelled task from 62 to 77
Task: Cancelled task from 77 to 93
Task: Cancelled task from 156 to 171
Task: Cancelled task from 171 to 187
Task: Cancelled task from 93 to 109
Task: Cancelled task from 109 to 125
Task: Cancelled task from 375 to 406
Task: Cancelled task from 406 to 437
Task: Cancelled task from 187 to 218
Task: Cancelled task from 218 to 250
Task: Cancelled task from 859 to 867
Task: Cancelled task from 867 to 875
Task: Cancelled task from 437 to 468
Task: Cancelled task from 468 to 500
Task: Cancelled task from 62 to 69
Task: Cancelled task from 69 to 77
Task: Cancelled task from 77 to 85
Task: Cancelled task from 85 to 93
Task: Cancelled task from 625 to 656
Task: Cancelled task from 656 to 687
Task: 281:312
Task: Cancelled task from 250 to 281
Task: 718:734
Task: 687:694
Task: 281:296
Task: 656:671
Task: 656:663
Task: 694:702
Task: 663:671
Task: 671:687
SearchNumberTask: Number 5 found in position 698
Task: Cancelled task from 0 to 500
Task: Cancelled task from 500 to 1000
Task: Cancelled task from 0 to 250
Task: Cancelled task from 250 to 500
Task: Cancelled task from 500 to 750
Task: Cancelled task from 750 to 1000
Task: Cancelled task from 500 to 625
Task: Cancelled task from 625 to 750
Task: Cancelled task from 0 to 125
Task: Cancelled task from 125 to 250
Task: Cancelled task from 750 to 875
Task: Cancelled task from 875 to 1000
Task: Cancelled task from 0 to 62
Task: Cancelled task from 62 to 125
Task: Cancelled task from 750 to 812
Task: Cancelled task from 812 to 875
Task: Cancelled task from 750 to 781
Task: Cancelled task from 781 to 812
Task: Cancelled task from 875 to 937
Task: Cancelled task from 937 to 1000
Task: Cancelled task from 125 to 187
Task: Cancelled task from 187 to 250
Task: Cancelled task from 500 to 562
Task: Cancelled task from 562 to 625
Task: Cancelled task from 812 to 843
Task: Cancelled task from 843 to 875
Task: Cancelled task from 812 to 827
Task: Cancelled task from 827 to 843
Task: Cancelled task from 0 to 31
Task: Cancelled task from 31 to 62
Task: Cancelled task from 125 to 156
Task: Cancelled task from 156 to 187
Task: Cancelled task from 250 to 375
Task: Cancelled task from 375 to 500
Task: Cancelled task from 843 to 859
Task: Cancelled task from 859 to 875
Task: Cancelled task from 250 to 312
Task: Cancelled task from 312 to 375
Task: Cancelled task from 375 to 437
Task: Cancelled task from 437 to 500
Task: Cancelled task from 62 to 93
Task: Cancelled task from 93 to 125
Task: Cancelled task from 125 to 140
Task: Cancelled task from 140 to 156
Task: Cancelled task from 843 to 851
Task: Cancelled task from 851 to 859
Task: Cancelled task from 875 to 906
Task: Cancelled task from 906 to 937
Task: Cancelled task from 625 to 687
Task: Cancelled task from 687 to 750
Task: Cancelled task from 0 to 15
Task: Cancelled task from 15 to 31
Task: Cancelled task from 937 to 968
Task: Cancelled task from 968 to 1000
Task: Cancelled task from 31 to 46
Task: Cancelled task from 46 to 62
Task: Cancelled task from 0 to 7
Task: Cancelled task from 7 to 15
Task: Cancelled task from 937 to 952
Task: Cancelled task from 952 to 968
Task: Cancelled task from 62 to 77
Task: Cancelled task from 77 to 93
Task: Cancelled task from 156 to 171
Task: Cancelled task from 171 to 187
Task: Cancelled task from 93 to 109
Task: Cancelled task from 109 to 125
Task: Cancelled task from 375 to 406
Task: Cancelled task from 406 to 437
Task: Cancelled task from 187 to 218
Task: Cancelled task from 218 to 250
Task: Cancelled task from 859 to 867
Task: Cancelled task from 867 to 875
Task: Cancelled task from 437 to 468
Task: Cancelled task from 468 to 500
Task: Cancelled task from 62 to 69
Task: Cancelled task from 69 to 77
Task: Cancelled task from 77 to 85
Task: Cancelled task from 85 to 93
Task: Cancelled task from 625 to 656
Task: Cancelled task from 656 to 687
Task: Cancelled task from 250 to 281
Task: Cancelled task from 281 to 312
Task: Cancelled task from 687 to 718
Task: Cancelled task from 718 to 750
Task: Cancelled task from 968 to 984
Task: Cancelled task from 984 to 1000
Task: 421:437
Task: Cancelled task from 406 to 421
Task: 734:750
Task: 718:726
SearchNumberTask: Number 5 found in position 718
Task: Cancelled task from 0 to 500
Task: Cancelled task from 500 to 1000
Task: Cancelled task from 0 to 250
Task: Cancelled task from 250 to 500
Task: Cancelled task from 500 to 750
Task: Cancelled task from 750 to 1000
Task: Cancelled task from 500 to 625
Task: Cancelled task from 625 to 750
Task: Cancelled task from 0 to 125
Task: Cancelled task from 125 to 250
Task: Cancelled task from 750 to 875
Task: Cancelled task from 875 to 1000
Task: Cancelled task from 0 to 62
Task: Cancelled task from 62 to 125
Task: Cancelled task from 750 to 812
Task: Cancelled task from 812 to 875
Task: Cancelled task from 750 to 781
Task: Cancelled task from 781 to 812
Task: Cancelled task from 875 to 937
Task: Cancelled task from 937 to 1000
Task: Cancelled task from 125 to 187
Task: Cancelled task from 187 to 250
Task: Cancelled task from 500 to 562
Task: Cancelled task from 562 to 625
Task: Cancelled task from 812 to 843
Task: Cancelled task from 843 to 875
Task: Cancelled task from 812 to 827
Task: Cancelled task from 827 to 843
Task: Cancelled task from 0 to 31
Task: Cancelled task from 31 to 62
Task: Cancelled task from 125 to 156
Task: Cancelled task from 156 to 187
Task: Cancelled task from 250 to 375
Task: Cancelled task from 375 to 500
Task: Cancelled task from 843 to 859
Task: Cancelled task from 859 to 875
Task: Cancelled task from 250 to 312
Task: Cancelled task from 312 to 375
Task: Cancelled task from 375 to 437
Task: Cancelled task from 437 to 500
Task: Cancelled task from 62 to 93
Task: Cancelled task from 93 to 125
Task: Cancelled task from 125 to 140
Task: Cancelled task from 140 to 156
Task: Cancelled task from 843 to 851
Task: Cancelled task from 851 to 859
Task: Cancelled task from 875 to 906
Task: Cancelled task from 906 to 937
Task: Cancelled task from 625 to 687
Task: Cancelled task from 687 to 750
Task: Cancelled task from 0 to 15
Task: Cancelled task from 15 to 31
Task: Cancelled task from 937 to 968
Task: Cancelled task from 968 to 1000
Task: Cancelled task from 31 to 46
Task: Cancelled task from 46 to 62
Task: Cancelled task from 0 to 7
Task: Cancelled task from 7 to 15
Task: Cancelled task from 937 to 952
Task: Cancelled task from 952 to 968
Task: Cancelled task from 62 to 77
Task: Cancelled task from 77 to 93
Task: Cancelled task from 156 to 171
Task: Cancelled task from 171 to 187
Task: Cancelled task from 93 to 109
Task: Cancelled task from 109 to 125
Task: Cancelled task from 375 to 406
Task: Cancelled task from 406 to 437
Task: Cancelled task from 187 to 218
Task: Cancelled task from 218 to 250
Task: Cancelled task from 859 to 867
Task: Cancelled task from 867 to 875
Task: Cancelled task from 437 to 468
Task: Cancelled task from 468 to 500
Task: Cancelled task from 62 to 69
Task: Cancelled task from 69 to 77
Task: Cancelled task from 77 to 85
Task: Cancelled task from 85 to 93
Task: Cancelled task from 625 to 656
Task: Cancelled task from 656 to 687
Task: Cancelled task from 250 to 281
Task: Cancelled task from 281 to 312
Task: Cancelled task from 687 to 718
Task: Cancelled task from 718 to 750
Task: Cancelled task from 968 to 984
Task: Cancelled task from 984 to 1000
Task: Cancelled task from 406 to 421
Task: Cancelled task from 421 to 437
Task: Cancelled task from 687 to 702
Task: Cancelled task from 702 to 718
Task: Cancelled task from 687 to 694
Task: Cancelled task from 694 to 702
Task: Cancelled task from 656 to 671
Task: Cancelled task from 671 to 687
Task: 976:984
Task: Cancelled task from 968 to 976
Task: Cancelled task from 976 to 984
Task: Cancelled task from 984 to 992
Task: 992:1000
Task: Cancelled task from 992 to 1000
Task: Cancelled task from 702 to 710
Task: Cancelled task from 710 to 718
Task: Cancelled task from 718 to 734
Task: Cancelled task from 734 to 750
Task: Cancelled task from 281 to 296
Task: Cancelled task from 296 to 312
Task: Cancelled task from 726 to 734
Task: 288:296
SearchNumberTask: Number 5 found in position 288
Task: Cancelled task from 0 to 500
Task: Cancelled task from 500 to 1000
Task: Cancelled task from 0 to 250
Task: Cancelled task from 250 to 500
Task: Cancelled task from 500 to 750
Task: Cancelled task from 750 to 1000
Task: Cancelled task from 500 to 625
Task: Cancelled task from 625 to 750
Task: 296:312
Task: Cancelled task from 0 to 125
Task: Cancelled task from 281 to 288
SearchNumberTask: Number 5 found in position 996
Task: Cancelled task from 0 to 500
Task: Cancelled task from 500 to 1000
Task: Cancelled task from 0 to 250
Task: Cancelled task from 250 to 500
Task: Cancelled task from 500 to 750
Task: Cancelled task from 750 to 1000
Task: Cancelled task from 500 to 625
Task: Cancelled task from 625 to 750
Task: Cancelled task from 0 to 125
Task: Cancelled task from 125 to 250
Task: Cancelled task from 750 to 875
Task: Cancelled task from 875 to 1000
Task: Cancelled task from 0 to 62
Task: Cancelled task from 62 to 125
Task: Cancelled task from 750 to 812
Task: Cancelled task from 812 to 875
Task: Cancelled task from 750 to 781
Task: Cancelled task from 781 to 812
Task: Cancelled task from 875 to 937
Task: Cancelled task from 937 to 1000
Task: Cancelled task from 125 to 187
Task: Cancelled task from 187 to 250
Task: Cancelled task from 500 to 562
Task: Cancelled task from 562 to 625
Task: Cancelled task from 812 to 843
Task: Cancelled task from 843 to 875
Task: Cancelled task from 812 to 827
Task: Cancelled task from 827 to 843
Task: Cancelled task from 0 to 31
Task: Cancelled task from 31 to 62
Task: Cancelled task from 125 to 156
Task: Cancelled task from 156 to 187
Task: Cancelled task from 250 to 375
Task: Cancelled task from 375 to 500
Task: Cancelled task from 843 to 859
Task: Cancelled task from 859 to 875
Task: Cancelled task from 250 to 312
Task: Cancelled task from 312 to 375
Task: Cancelled task from 375 to 437
Task: Cancelled task from 437 to 500
Task: Cancelled task from 62 to 93
Task: Cancelled task from 93 to 125
Task: Cancelled task from 125 to 140
Task: Cancelled task from 140 to 156
Task: Cancelled task from 843 to 851
Task: Cancelled task from 851 to 859
Task: Cancelled task from 875 to 906
Task: Cancelled task from 906 to 937
Task: Cancelled task from 625 to 687
Task: Cancelled task from 687 to 750
Task: Cancelled task from 0 to 15
Task: Cancelled task from 15 to 31
Task: Cancelled task from 937 to 968
Task: Cancelled task from 968 to 1000
Task: Cancelled task from 31 to 46
Task: Cancelled task from 46 to 62
Task: Cancelled task from 0 to 7
Task: Cancelled task from 7 to 15
Task: Cancelled task from 937 to 952
Task: Cancelled task from 952 to 968
Task: Cancelled task from 62 to 77
Task: Cancelled task from 77 to 93
Task: Cancelled task from 156 to 171
Task: Cancelled task from 171 to 187
Task: Cancelled task from 93 to 109
Task: Cancelled task from 109 to 125
Task: Cancelled task from 375 to 406
Task: Cancelled task from 406 to 437
Task: Cancelled task from 187 to 218
Task: Cancelled task from 218 to 250
Task: Cancelled task from 859 to 867
Task: Cancelled task from 867 to 875
Task: Cancelled task from 437 to 468
Task: Cancelled task from 468 to 500
Task: Cancelled task from 62 to 69
Task: Cancelled task from 69 to 77
Task: Cancelled task from 77 to 85
Task: Cancelled task from 85 to 93
Task: Cancelled task from 625 to 656
Task: Cancelled task from 656 to 687
Task: Cancelled task from 250 to 281
Task: Cancelled task from 281 to 312
Task: Cancelled task from 687 to 718
Task: Cancelled task from 718 to 750
Task: Cancelled task from 968 to 984
Task: Cancelled task from 984 to 1000
Task: Cancelled task from 406 to 421
Task: Cancelled task from 421 to 437
Task: Cancelled task from 687 to 702
Task: Cancelled task from 702 to 718
Task: Cancelled task from 687 to 694
Task: Cancelled task from 694 to 702
Task: Cancelled task from 656 to 671
Task: Cancelled task from 671 to 687
Task: Cancelled task from 968 to 976
Task: Cancelled task from 976 to 984
Task: Cancelled task from 984 to 992
Task: Cancelled task from 702 to 710
Task: Cancelled task from 710 to 718
Task: Cancelled task from 718 to 734
Task: Cancelled task from 734 to 750
Task: Cancelled task from 281 to 296
Task: Cancelled task from 296 to 312
Task: Cancelled task from 718 to 726
Task: Cancelled task from 726 to 734
Task: Cancelled task from 281 to 288
Task: Cancelled task from 288 to 296
Task: Cancelled task from 656 to 663
Task: Cancelled task from 663 to 671
Task: Cancelled task from 671 to 679
Task: Cancelled task from 679 to 687
Task: Cancelled task from 421 to 429
Task: Cancelled task from 429 to 437
Task: Cancelled task from 734 to 742
Task: Cancelled task from 742 to 750
Task: Cancelled task from 296 to 304
Task: Cancelled task from 304 to 312
SearchNumberTask: Number 5 found in position 668
Task: Cancelled task from 0 to 500
Task: Cancelled task from 500 to 1000
Task: Cancelled task from 0 to 250
Task: Cancelled task from 250 to 500
Task: Cancelled task from 500 to 750
Task: Cancelled task from 750 to 1000
Task: Cancelled task from 500 to 625
Task: Cancelled task from 625 to 750
Task: Cancelled task from 0 to 125
Task: Cancelled task from 125 to 250
Task: Cancelled task from 750 to 875
Task: Cancelled task from 875 to 1000
Task: Cancelled task from 0 to 62
Task: Cancelled task from 62 to 125
Task: Cancelled task from 750 to 812
Task: Cancelled task from 812 to 875
Task: Cancelled task from 750 to 781
Task: Cancelled task from 781 to 812
Task: Cancelled task from 875 to 937
Task: Cancelled task from 937 to 1000
Task: Cancelled task from 125 to 187
Task: Cancelled task from 187 to 250
Task: Cancelled task from 500 to 562
Task: Cancelled task from 562 to 625
Task: Cancelled task from 812 to 843
Task: Cancelled task from 843 to 875
Task: Cancelled task from 812 to 827
Task: Cancelled task from 827 to 843
Task: Cancelled task from 0 to 31
Task: Cancelled task from 31 to 62
Task: Cancelled task from 125 to 156
Task: Cancelled task from 156 to 187
Task: Cancelled task from 250 to 375
Task: Cancelled task from 375 to 500
Task: Cancelled task from 843 to 859
Task: Cancelled task from 859 to 875
Task: Cancelled task from 250 to 312
Task: Cancelled task from 312 to 375
Task: Cancelled task from 375 to 437
Task: Cancelled task from 437 to 500
Task: Cancelled task from 62 to 93
Task: Cancelled task from 93 to 125
Task: Cancelled task from 125 to 140
Task: Cancelled task from 140 to 156
Task: Cancelled task from 843 to 851
Task: Cancelled task from 851 to 859
Task: Cancelled task from 875 to 906
Task: Cancelled task from 906 to 937
Task: Cancelled task from 625 to 687
Task: Cancelled task from 687 to 750
Task: Cancelled task from 0 to 15
Task: Cancelled task from 15 to 31
Task: Cancelled task from 937 to 968
Task: Cancelled task from 968 to 1000
Task: Cancelled task from 31 to 46
Task: Cancelled task from 46 to 62
Task: Cancelled task from 0 to 7
Task: Cancelled task from 7 to 15
Task: Cancelled task from 937 to 952
Task: Cancelled task from 952 to 968
Task: Cancelled task from 62 to 77
Task: Cancelled task from 77 to 93
Task: Cancelled task from 156 to 171
Task: Cancelled task from 171 to 187
Task: Cancelled task from 93 to 109
Task: Cancelled task from 109 to 125
Task: Cancelled task from 375 to 406
Task: Cancelled task from 406 to 437
Task: Cancelled task from 187 to 218
Task: Cancelled task from 218 to 250
Task: Cancelled task from 859 to 867
Task: Cancelled task from 867 to 875
Task: Cancelled task from 437 to 468
Task: Cancelled task from 468 to 500
Task: Cancelled task from 62 to 69
Task: Cancelled task from 69 to 77
Task: Cancelled task from 77 to 85
Task: Cancelled task from 85 to 93
Task: Cancelled task from 625 to 656
Task: Cancelled task from 656 to 687
Task: Cancelled task from 250 to 281
Task: Cancelled task from 281 to 312
Task: Cancelled task from 687 to 718
Task: Cancelled task from 718 to 750
Task: Cancelled task from 968 to 984
Task: Cancelled task from 984 to 1000
Task: Cancelled task from 406 to 421
Task: Cancelled task from 421 to 437
Task: Cancelled task from 687 to 702
Task: Cancelled task from 702 to 718
Task: Cancelled task from 687 to 694
Task: Cancelled task from 694 to 702
Task: Cancelled task from 656 to 671
Task: Cancelled task from 671 to 687
Task: Cancelled task from 968 to 976
Task: Cancelled task from 976 to 984
Task: Cancelled task from 984 to 992
Task: Cancelled task from 992 to 1000
Task: Cancelled task from 702 to 710
Task: Cancelled task from 710 to 718
Task: Cancelled task from 718 to 734
Task: Cancelled task from 734 to 750
Task: Cancelled task from 281 to 296
Task: Cancelled task from 296 to 312
Task: Cancelled task from 718 to 726
Task: Cancelled task from 726 to 734
Task: Cancelled task from 281 to 288
Task: Cancelled task from 288 to 296
Task: Cancelled task from 656 to 663
Task: Cancelled task from 671 to 679
Task: Cancelled task from 679 to 687
Task: Cancelled task from 421 to 429
Task: Cancelled task from 429 to 437
Task: Cancelled task from 734 to 742
Task: Cancelled task from 742 to 750
Task: Cancelled task from 296 to 304
Task: Cancelled task from 304 to 312
Main: The program has finished
View Code


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM