gpt4 book ai didi

Java,仅对同步块(synchronized block)中的变量或所有实例变量发生与主内存的同步?

转载 作者:行者123 更新时间:2023-11-29 08:54:29 25 4
gpt4 key购买 nike

考虑以下玩具示例:

public class Test {

private int nr;
private A a;


public synchronized A getA() {
return a;
}

public synchronized void setA(A a) {
this.a = a;
}


public static class A{
B b;
}

public static class B{
// may contain other references
}
}

由于 get/set 中的同步关键字,我们可以安全地从多个线程读取/写入 'a'。我们不需要将其声明为 volatile,因为在同步块(synchronized block)的开始/结束时,本地缓存线程与主内存的同步已经完成。

但是,基本上我们是在“this”上进行同步,并且 Test 对象还包含变量“nr”。 Java 是否与主内存同步,关于 set/get 'a',只发生在 'a' 上,因为它是在那些同步块(synchronized block)中访问的唯一变量,或者对于 Test 类的所有成员,因为我们已经同步了 'this '?

此外,当与主内存同步时,这是递归的,即“a”可能包含的所有引用链(在本例中为“b”)是从主内存读/写还是只是“a”的引用?

谢谢

最佳答案

来自 concurrent package 处的 Javadoc

The results of a write by one thread are guaranteed to be visible to a read by another thread only if the write operation happens-before the read operation.

...

An unlock (synchronized block or method exit) of a monitor happens-before every subsequent lock (synchronized block or method entry) of that same monitor. And because the happens-before relation is transitive, all actions of a thread prior to unlocking happen-before all actions subsequent to any thread locking that monitor.

所以你可以说所有变量都是同步的。更准确地说,所有写入(对任何变量)都被读取(从相同变量)看到如果两个线程在同一对象上同步

如果您有多个线程 A、B 和 C。例如,线程 A 和 B 在 test1 上同步,线程 B 和 C 在 test2 上同步。然后 B 将看到 A 的写入。线程 C 将看到 B 的写入,并且可能看到也可能看不到 A 的写入。

有两个线程 T1 和 T2 的例子,语句从上到下执行

T1             T2
test.nr = 5;
test.setA(a1);
test.getA(); //gives a1
print(test.nr); //gives 5

对于不同的对象:

T1             T2
test2.nr = 5;
test.setA(a1);
test.getA(); //gives a1
print(test2.nr); //gives 5

之前的例子没有正确同步:

T1             T2
test.nr = 6;
test.nr = 5;
test.setA(a1);
test.getA(); //gives a1
print(test.nr); //gives 5 or 6

再举一个例子

T1             T2             T3
test.nr = 5;
test.setA(a1);
test.nr = 6;
test.setA(a2);
test.nr = 7;
test.getA(); //gives a2
print(test.nr); //gives 5,6 or 7

“主内存”中有什么? 5,6 还是 7?嗯,规范中没有主内存。所以没有正确答案。当然,JVM 将使用主内存、寄存器和高速缓存。但是它如何使用它们取决于 JVM 的实现。

最后一个可怕的例子

T1             T2

test.nr = 6;
print(test.nr); //gives 5 or 6
test.nr = 5;

您可以读取值 5,即使它尚未写入!

有一个简单的解决方案,如果两个线程读取和/或写入同一个变量,将它们放在同一个对象的同步块(synchronized block)中。

关于Java,仅对同步块(synchronized block)中的变量或所有实例变量发生与主内存的同步?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20980379/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com