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 ", 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 ", pool.getActiveThreadCount()); System.out.printf("Main: Thread Steal: %d ", pool.getStealCount()); System.out.printf("Main: Parallelism: %d ", 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 ", 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.
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 ", pool.getParallelism()); System.out.printf("Main: Active Threads: %d ", pool.getActiveThreadCount()); System.out.printf("Main: Task Count: %d ", pool.getQueuedTaskCount()); System.out.printf("Main: Steal Count: %d ", 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
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. ", 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 ", pool.getParallelism()); System.out.printf("Main: Active Threads: %d ", pool.getActiveThreadCount()); System.out.printf("Main: Task Count: %d ", pool.getQueuedTaskCount()); System.out.printf("Main: Steal Count: %d ", 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. ", results.size()); results = apps.join(); System.out.printf("Apps: %d files found. ", results.size()); results = documents.join(); System.out.printf("Documents: %d files found. ", 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 SettingsDELLApplication DataTencentQQMiscMsgBubble: 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.
本范例使用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 ", 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 ", 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)
虽然运行这个程序时将抛出异常,但是程序不会停止。在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 ", 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 ", 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 ", 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 ", 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