【发布时间】:2021-11-16 11:35:38
【问题描述】:
我正在查看我找到的最简单的示例之一,并开始推理 SO(同步顺序)或更准确地说,缺少它。考虑下面的例子:
int a, b; // two shared variables
Thread-X:
void threadX() {
synchronized(this) {
a = 1;
}
synchronized(this) {
b = 1;
}
}
还有一个读者线程,Thread-Y:
void threadY() {
int r1 = b;
int r2 = a;
}
为简单起见,我们假设Thread-Y 完全按照以下顺序进行读取:它肯定会先读取b,然后再读取a(与写入相反)。
允许阅读线程查看[1, 0](就像b=1 发生在之前 a=1)。我想我也明白为什么:因为在两个动作之间有no synchronization order,因此没有happens-before,根据JLS,这是一场数据竞赛:
当一个程序包含两个冲突的访问,这些访问没有按照发生前的关系排序时,就被称为包含数据竞争。
因此阅读a 和b 是两个活泼的阅读,所以看到b=1 和a=0 是允许和可能的。
现在这反过来又允许 JVM 在写入器中进行锁粗化,所以它变成:
void threadX() {
synchronized(this) {
a = 1;
b = 1;
}
}
我的问题是,如果读者最初是这样写的:
void threadY() {
synchronized(this) {
int r1 = b;
}
synchronized(this) {
int r2 = a;
}
}
是否仍允许锁粗化?我认为我知道答案,但我也想听听有根据的解释。
【问题讨论】:
-
锁粗化不考虑其他方法的动作,因为它不能详尽地识别所有的动作。类可以是动态子类化、反射等。简单的答案是锁粗化可能无论如何都会发生。我没有将此评论归类为答案,因为我认为自己在这个领域没有受到足够的“教育”。
标签: java multithreading jvm locking jit