Fork/join主要用于问题分解处理,分而治之。html
Fork/join算法将问题划分红多个小的子问题,对每一个子问题运用一样的算法,当子问题足够小时,问题就能够直接获得解决。全部子问题都解决了,结合起来父问题也就获得了解决。node
JSR-166y类库对Fork/join支持至关不错,但有些问题若是不注意,还会遇到麻烦。并且还得本身处理threads、pools及synchronization barriers(同步障)。GPars隐藏了这些东西,让你用起Fork/join来更加方便。下例是统计一指定目录及其子目录下文件个数的算法:算法
import groovyx.gpars.AbstractForkJoinWorker import static groovyx.gpars.Parallelizer.* public final class FileCounter extends AbstractForkJoinWorker{ private final File file; def FileCounter(final File file) { this.file = file } protected void compute() { long count = 0; file.eachFile { if (it.isDirectory()) { println "Forking a thread for $it" //fork一个子任务 forkOffChild(new FileCounter(it)) } else { count++ } } //用子任务结果计算并保存本任务结果 setResult(count + ((childrenResults)?.sum() ?: 0)) } } doParallel(1) { pool -> //1个线程也能搞定 println """Number of files: ${orchestrate( new FileCounter( new File("...目录名...") ) )}""" }
上例中Parallelizer.orchestrate()方法根据传递进的AbstractForkJoinWorker类型的参数(根任务)建立一个ForkJoinOrchestrator并运行该AbstractForkJoinWorker,等待结果返回。childrenResults是AbstractForkJoinWorker的属性,等待子任务结果返回,返回值为List类型。安全
Fork/Join操做之因此能安全地由成若干小线程运行,要归功于内部TaskBarrier类对线程的同步。当算法中一个线程被阻塞等待其子问题得以完成时,该线程会被归还到池内,以用于任务队列中其余可运行子问题。尽管算法建立了许多任务(因为子目录不少),并且都要等其子目录任务完成,但最少只需一个线程就足以保持运算进行。并发
GPars指南中还给出了一个比较复杂的Mergesort的例子,有兴趣的读者能够参考。ide
本系列的其余文章:ui