Brian Goetz在http://www.ibm.com/developerworks/java/library/j-jtp03048.html撰写了一篇关于fork-join的精彩文章。在其中,他列出了使用fork-join机制的合并排序算法,在该机制中,他并行执行数组两侧的排序,然后合并结果。
算法同时对同一阵列的两个不同部分进行排序。为什么不是AtomicIntegerArray或维持可见性所需的其他机制?什么保证一个线程会看到另一个线程完成的写入,或者这是一个微妙的错误?作为后续跟进,Scala的ForkJoinScheduler是否也提供此保证?
谢谢!
答案 0 :(得分:6)
ForkJoin的连接本身需要一个同步点,这是最重要的信息。同步点将确保在所述点之后发生的所有写入都是可见的。
如果查看代码,可以看到同步点出现的位置。这只是调用invokeAll的一个方法
public static void invokeAll(ForkJoinTask<?> t1, ForkJoinTask<?> t2) {
t2.fork();
t1.invoke();
t2.join();
}
这里t2分叉到另一个进程,t1执行它的任务,并且调用线程将在t2.join()上等待。通过t2时。然后,对t1和t2的所有写入都将可见。
编辑:此编辑只是为了解释我对同步点的意义。
让我们说你有两个变量
int x;
volatile int y;
任何时候你写y你读之前发生的所有写作都将可用。例如
public void doWork(){
x = 10;
y = 5;
}
如果另一个线程读取y = 5该线程 保证 读取x = 10.这是因为写入y会创建一个同步点,其中所有写入之前写完之后会说明这一点。
使用Fork Join池,ForkJoinTask的连接将创建一个同步点。现在,如果t2.fork()和t1.invoke(),t2的加入将确保将看到之前发生的所有写入。由于所有先前的写入都在相同的结构内,因此可见是安全的。
如果不清楚,我会很乐意进一步解释。
答案 1 :(得分:1)
只是一个猜测:merge包括加入一个Thread,并且join保证了可见性。
第二部分是肯定的;我不知道如何实现合并。