连接(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 将确保之前发生的所有写入都会被看到。由于所有先前的写入都在同一个结构中,因此可见性是安全的。
如果不是很清楚,我很乐意进一步解释。