假设我有两个变量的X类。
class X {
Integer a;
Y b;
Integer c;
}
Y级class Y {
Integer y1;
String y2;
}
说,我们有4个线程,T1,T2,T3和T4。T1在
a
上运行,T2在b.y1
上运行(类似于x.getB().setY1()
),T3在b.y2
上运行,T4在c
上运行。在执行完所有线程之前,我不会读取任何“最深”值(
a, y1, y2, c
)(T2和T3将执行x.getB()
)。我是否会遇到与多线程相关的任何典型问题?
我的问题
x.getB()
怎么样? 当处理器在处理完成后将其缓存与主内存进行调和时,它们是否仅更新更改的内存块,还是用其缓存的整个内存块覆盖了主内存?
例如,最初,a和c都具有
a = 1
和c = 1
值。 P1和P4缓存这些值(a=1
和c=1
)。 T1更改为a = 2
,T4更改为c = 2
。现在,缓存C1中的值为
a=2, c=1
;在C2中,为a=1, c=2
。因此,写回主存储器时,首先说P1完成,然后再更新主存储器。因此,现在的值为
a=2, c=1
。现在,当P4完成时,是否仅更新了
c
的值,因为它仅修改了c
?还是用缓存中的值简单地覆盖主内存,即为a=1, c=2
?或者它们只是缓存将要读取或写入的值,这意味着T1永远不会缓存
c
的值,而T4永远不会缓存a
的值。
最佳答案
您质疑许多有趣的话题。我将尝试重新整理您的问题,并按顺序回答。
关于第一个问题:如果不同的线程仅修改不同的对象,这会带来一致性问题吗?
您需要在修改对象(或“写入”)与使此类更改对其他线程可见之间做出区分。在您出现的情况下,您的各种线程彼此独立地处理各种对象,而无需“读取”其他对象。是的,这很好。
但是,如果一个线程需要读取可能已被另一个线程修改的变量的值,则需要引入一些同步,以便在第一个线程读取之前对该变量进行修改(同步块(synchronized block)/访问 volatile 变量/信号量等)。我对这篇文章Fixing the Java Memory Model不够推荐。
关于第二个问题:
对第一个问题的回答相同:只要没有线程修改b
实例的成员X
,就无需担心;线程T2
和T3
将获得相同的对象。
关于第三个和第四个问题,缓存一致性如何?
从程序员的角度来看,Java虚拟机如何处理内存分配是有点晦涩的。您所关注的被称为虚假共享。 Java虚拟机将确保存储在内存中的内容与您的程序一致。您无需担心不良的高速缓存会覆盖另一个线程所做的更改。
但是,如果成员之间有足够的争用,您可能会面临性能下降的问题。幸运的是,您可以通过在存在问题的成员上使用 @Contended
注释来减少这种影响,这些成员会向Java虚拟机指示应在不同的缓存行上分配它们。
关于java - 多线程:操纵同一对象的不同字段的线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66380065/