6

Brian Goetz 在http://www.ibm.com/developerworks/java/library/j-jtp03048.html上写了一篇关于 fork-join 的好文章。在其中,他列出了一种使用 fork-join 机制的合并排序算法,其中他在数组的两侧并行执行排序,然后合并结果。

该算法同时对同一数组的两个不同部分进行排序。为什么不是 AtomicIntegerArray 或其他保持可见性所必需的机制?有什么保证一个线程会看到另一个线程完成的写入,或者这是一个微妙的错误?作为后续,Scala 的 ForkJoinScheduler 是否也做出了这种保证?

谢谢!

4

2 回答 2

8

连接(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 在你读 y 之前发生的所有写都是可用的。例如

public void doWork(){
   x = 10;
   y = 5;
}

如果另一个线程读取 y = 5,则该线程保证读取 x = 10。这是因为对 y 的写入会创建一个同步点,在该同步点中,在该点之前的所有写入在写入后都将可见。

使用 Fork Join 池,ForkJoinTask 的加入将创建一个同步点。现在如果 t2.fork() 和 t1.invoke() 加入 t2 将确保之前发生的所有写入都会被看到。由于所有先前的写入都在同一个结构中,因此可见性是安全的。

如果不是很清楚,我很乐意进一步解释。

于 2011-01-26T01:34:27.820 回答
1

只是一个猜测:合并包括加入一个线程,并且连接保证了可见性。

第二部分是肯定的;我不知道合并是如何实现的。

于 2011-01-26T01:12:16.147 回答