Fork/Join框架
2020年12月27日
20:22
目录 |
- - 引言 - fork分割任务 - 工作窃取算法 - 源码剖析
|
引言
它是一个同样实现了ExecutorService的线程池,专门用于将大任务分解成小任务,最大化利用多线程/多处理器的处理性能。线程池的主要作用是线程缓冲池,而它主要是提供一个“单机版MapReduce”。
说起来它和MapReduce的理念很像——分割任务,分开执行。
思想
fork分割任务
这个没什么好说的,它本身并不带分割,需要使用者结合递归使用。来看一个个使用案例就懂了。
求斐波那契数列,注意这个例子是强行使用,Fork/Join并不是在所有分而治之的算法都有效的,它需要每个子任务有一定的计算量,多核多线程可以加快的前提下。
1 public class FibonacciTest { 2 class Fibonacci extends RecursiveTask<Integer> { 3 int n; 4 public Fibonacci(int n) { 5 this.n = n; 6 } 7 // 主要的实现逻辑都在compute()里 8 @Override 9 protected Integer compute() { 10 // 这里先假设 n >= 0 11 if (n <= 1) { 12 return n; 13 } else { 14 // f(n-1) 15 Fibonacci f1 = new Fibonacci(n - 1); 16 f1.fork(); 17 // f(n-2) 18 Fibonacci f2 = new Fibonacci(n - 2); 19 f2.fork(); 20 // f(n) = f(n-1) + f(n-2) 21 return f1.join() + f2.join(); 22 } 23 } 24 } 25 @Test 26 public void testFib() throws ExecutionException, InterruptedException { 27 ForkJoinPool forkJoinPool = new ForkJoinPool(); 28 System.out.println("CPU核数:" + Runtime.getRuntime().availableProcessors()); 29 long start = System.currentTimeMillis(); 30 Fibonacci fibonacci = new Fibonacci(40); 31 Future<Integer> future = forkJoinPool.submit(fibonacci); 32 System.out.println(future.get()); 33 long end = System.currentTimeMillis(); 34 System.out.println(String.format("耗时:%d millis", end - start)); 35 } 38 } |
工作窃取算法
在Fork/Join的框架下,线程池里的线程每一个都维护一个任务队列,一旦自己的任务做完,随机选择其他线程,从中窃取任务执行。就这么点事。
但这整个框架看来,显然是一件非常难实现的事,所以源代码还没读懂。
源码剖析
todo,没读懂
REF