我正在查看我发现的最简单的示例之一,并开始推理 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在这两个 Action 之间,因此没有happens-before,根据JLS
,这是一个数据竞赛:
When a program contains two conflicting accesses that are not ordered by a happens-before relationship, it is said to contain a data race.
因此读取 a
和 b
是两个有趣的读取,所以看到 b=1
和 a=0
是允许和可能的。
现在这又允许 JVM 在 writer 中进行锁粗化,所以它变成:
void threadX() {
synchronized(this) {
a = 1;
b = 1;
}
}
我的问题是,如果读者最初是这样写的:
void threadY() {
synchronized(this) {
int r1 = b;
}
synchronized(this) {
int r2 = a;
}
}
还会允许锁粗化吗?我认为我知道答案,但我也想听到有根据的解释。
最佳答案
是的,这是允许的。
这里有一个简单的解释。
记住 synchronized
block :
synchronized
block synchronized
block 时,它会立即看到在先前执行的synchronized
block 中所做的一切换句话说,synchronized
block 总是以全局顺序以原子方式执行。
不同的执行在 synchronized
block 如何交错方面可能不同,但情况总是如此:
threadX()
中的第一个 synchronized
block 总是在第二个 block 之前执行threadY()
的 synchronized
block 也是如此有 6 种可能的交错:
threadX threadY threadX threadY threadX threadY
------------------------------- ------------------------------- -------------------------------
synchronized { | synchronized { | synchronized { |
a = 1; | a = 1; | a = 1; |
} | } | } |
synchronized { | | synchronized { | synchronized {
b = 1; | | int r1 = b; | int r1 = b;
} | | } | }
| synchronized { synchronized { | | synchronized {
| int r1 = b; b = 1; | | int r2 = a;
| } } | | }
| synchronized { | synchronized { synchronized { |
| int r2 = a; | int r2 = a; b = 1 |
| } | } } | }
(Case A) (Case B) (Case C)
threadX threadY threadX threadY threadX threadY
------------------------------- ------------------------------- -------------------------------
| synchronized { | synchronized { | synchronized {
| int r1 = b; | int r1 = b; | int r1 = b;
| } | } | }
| synchronized { synchronized { | synchronized { |
| int r2 = a; a = 1; | a = 1; |
| } } | } |
synchronized { | | synchronized { synchronized { |
a = 1; | | int r2 = a; b = 1; |
} | | } } |
synchronized { | synchronized { | | synchronized {
b = 1; | b = 1; | | int r2 = a;
} | } | | }
(Case D) (Case E) (Case F)
当您在 threadY()
中合并 synchronized
block 时:
void threadY() { void threadY() {
synchronized(this) { synchronized(this) {
int r1 = b; int r1 = b;
} => int r2 = a;
synchronized(this) { }
int r2 = a; }
}
}
然后,您实际上只保留来自 threadY()
的 synchronized
block 彼此相邻的情况:即情况 A、C 和 D。
由于这次优化后没有出现新的可能执行,那么这次优化是合法的。
对于更严格和详细的解释,我建议:
https://stackoverflow.com/questions/69293751/
相关文章:
indexing - 为什么索引 HashMap 不返回引用?
python - Linux Mint Cinnamon 错误打开设置(没有名为 'PIL' 的模块
python - python解释器是否隐含地使用了中国余数定理?
ruby-on-rails - Rails 参数方法 : Why can it be accesse
javascript - MongooseServerSelectionError:连接 ECONN
assembly - 如果 x86 jmp 跳转到其他两个连续有效地址之间的地址会发生什么?
reactjs - 如何更改Chakra UI Toast组件的背景颜色?