Fork-join中的内存可见性

时间:2011-01-26 00:52:44

标签: java scala fork-join jsr166

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

算法同时对同一阵列的两个不同部分进行排序。为什么不是AtomicIntegerArray或维持可见性所需的其他机制?什么保证一个线程会看到另一个线程完成的写入,或者这是一个微妙的错误?作为后续跟进,Scala的ForkJoinScheduler是否也提供此保证?

谢谢!

2 个答案:

答案 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保证了可见性。

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

相关问题