Java中同步的内存效应
说: 但同步还有很多问题 而不是相互排斥。同步 确保内存由线程写入 在同步块之前或期间 以可预测的方式显示 以其他线程的方式 在同一监视器上同步。之后 我们退出一个同步块,我们 释放监视器,它具有 将缓存刷新到主缓存的效果 内存,所以由这个 线程可以对其他线程可见 线程。在我们进入一个 同步块,我们获得 监视器,具有以下效果: 使本地处理器缓存无效 以便重新加载变量 从主存储器。然后我们就可以 要查看使所有写入可见,请执行以下操作: 在上一版本中 我还记得读到过,在现代Sun虚拟机上,无竞争的同步是便宜的。我对这种说法有点困惑。考虑代码:Java中同步的内存效应,java,concurrency,jvm,java-memory-model,Java,Concurrency,Jvm,Java Memory Model,说: 但同步还有很多问题 而不是相互排斥。同步 确保内存由线程写入 在同步块之前或期间 以可预测的方式显示 以其他线程的方式 在同一监视器上同步。之后 我们退出一个同步块,我们 释放监视器,它具有 将缓存刷新到主缓存的效果 内存,所以由这个 线程可以对其他线程可见 线程。在我们进入一个 同步块,我们获得 监视器,具有以下效果: 使本地处理器缓存无效 以便重新加载变量 从主存储器。然后我们就可以 要查看使所有写入可见,请执行以下操作: 在上一版本中 我还记得读到过,在现代Sun虚拟机上,无竞争的同
class Foo {
int x = 1;
int y = 1;
..
synchronized (aLock) {
x = x + 1;
}
}
对x的更新需要同步,但锁的获取是否也会从缓存中清除y的值?我无法想象会是这样,因为如果这是真的,像锁条化这样的技术可能不会有帮助。或者,JVM是否可以可靠地分析代码,以确保y在另一个使用相同锁的同步块中没有被修改,因此在进入同步块时不会在缓存中转储y的值?由于y超出了同步方法的范围,因此不能保证对它的更改在其他线程中可见。如果要保证在所有线程中看到对y的更改是相同的,那么所有线程在读/写y时都必须使用同步 如果某些线程以同步方式更改y,而其他线程则不更改y,那么您将获得意外的行为。线程之间共享的所有可变状态必须同步,才能保证看到线程之间的更改。必须同步所有线程对共享可变状态(变量)的所有访问 是的,JVM保证当锁被持有时,没有其他线程可以进入受同一锁保护的代码区域 对x的更新需要同步, 但是锁的获得 同时从中清除y的值 隐藏物我无法想象这是最重要的 因为如果这是真的, 锁条化等技术可能会 没有帮助 我不确定,但我想答案可能是“是的”。考虑这一点:
class Foo {
int x = 1;
int y = 1;
..
void bar() {
synchronized (aLock) {
x = x + 1;
}
y = y + 1;
}
}
现在,这段代码是不安全的,这取决于程序的其余部分发生了什么。但是,我认为内存模型意味着bar
看到的y
值不应早于获取锁时的“真实”值。这意味着缓存必须对y
和x
无效
JVM还可以可靠地分析
确保y未被修改的代码
在另一个同步块中,使用
同一把锁
如果锁是this
,那么在所有类都预加载后,作为全局优化,该分析看起来是可行的。(我不是说这很容易,也不是说值得……)
在更一般的情况下,证明一个给定的锁只用于一个给定的“拥有”实例的问题可能很难解决。我们是java开发人员,我们只知道虚拟机,不知道真正的机器 让我从理论上解释一下发生了什么——但我必须说我不知道我在说什么 假设线程A在带缓存A的CPU A上运行,线程B在带缓存B的CPU B上运行
第(5)步的补充:线程A可能有自己的缓存,甚至比缓存A更快——例如,它可以使用变量“y”的寄存器。这不会在步骤(4)中失效,因此在步骤(5)中,线程A必须在同步输入时擦除自己的缓存。不过这并不是一个巨大的惩罚。简单的回答是JSR-133在解释上走得太远了。这不是一个严重的问题,因为JSR-133是一个非规范性文档,它不是语言或JVM标准的一部分。相反,它只是一个文档,解释了一种可能的策略,这种策略足以实现内存模型,但一般来说并不必要。除此之外,关于“缓存刷新”的评论基本上是完全不恰当的,因为基本上零体系结构将通过执行任何类型的“缓存刷新”来实现Java内存模型(许多体系结构甚至没有这样的指令) Java内存模型是正式定义的