我对同步块几乎没有疑问。 在我提出问题之前,我想与其他相关帖子Link for Answer to related question分享答案。我从同一个答案中引用Peter Lawrey。
synchronized确保您拥有一致的数据视图。这意味着您将阅读最新的值,其他缓存将获得 最新价值。缓存足够聪明,可以通过一个相互交谈 特殊巴士(不是JLS要求的东西,但允许)这个 总线意味着它不必触摸主内存即可获得 一致的观点。
如果您只使用synchronized,则不需要volatile。如果您有一个非常简单的同步操作,则Volatile非常有用 会有点矫枉过正。
参考上文,我有以下三个问题:
Q1。假设在多线程应用程序中,只有一个对象或一个原始实例字段只在同步块中读取(写入可能在某些其他方法中没有同步发生)。同步块也是在某个其他对象上定义的。 声明它是不稳定的(即使它只在同步块中读取)是否有意义?
Q2。 我理解已经完成同步的对象状态的值是一致的。我不确定在Synchronized块的一侧读取其他对象和原始字段的状态。 假设在没有获得锁定的情况下进行了更改,但是通过获取锁定来完成读取。 Synchronized块中所有原始字段的所有对象和值的状态是否始终具有一致的视图。?
Q3。 [更新] :无论我们锁定什么,是否会在主内存中读取同步块中读取的所有字段? [CKing回答]
我已为上述问题准备了参考代码。
public class Test {
private SomeClass someObj;
private boolean isSomeFlag;
private Object lock = new Object();
public SomeClass getObject() {
return someObj;
}
public void setObject(SomeClass someObj) {
this.someObj = someObj;
}
public void executeSomeProcess(){
//some process...
}
// synchronized block is on a private someObj lock.
// inside the lock method does the value of isSomeFlag and state of someObj remain consistent?
public void someMethod(){
synchronized (lock) {
while(isSomeFlag){
executeSomeProcess();
}
if(someObj.isLogicToBePerformed()){
someObj.performSomeLogic();
}
}
}
// this is method without synchronization.
public void setSomeFlag(boolean isSomeFlag) {
this.isSomeFlag = isSomeFlag;
}
}
答案 0 :(得分:2)
您需要了解的第一件事是,链接答案中讨论的场景与您正在谈论的场景之间存在细微差别。您谈到在没有同步的情况下修改值,而在链接的答案中的同步上下文中修改所有值。考虑到这种理解,让我们解决您的问题:
Q1。假设在多线程应用程序中,只有一个对象或一个原始实例字段只在同步块中读取(写入可能在某些其他方法中没有同步发生)。同步块也是在某个其他对象上定义的。声明它是不稳定的(即使它只在同步块中读取)是否有意义?
是的,将字段声明为volatile
是有意义的。由于写入不在synchronized
上下文中发生,因此无法保证写入线程将新更新的值刷新到主存储器。由于这个原因,阅读线程可能仍会看到不一致的值。
假设在没有获得锁定的情况下进行了更改,但是通过获取锁定来完成读取。 Synchronized块中所有原始字段的所有对象和值的状态是否始终具有一致的视图。 ?
答案仍然是否定的。推理与上述相同。
底线:修改同步上下文之外的值不会确保将这些值刷新到主内存。 (因为读者线程可能在写入线程之前进入同步块)在synchronized
上下文中读取这些值的线程仍然可能最终读取较旧的值,即使它们从主存储器中获取这些值。
请注意,这个问题涉及原语,因此理解Java为32位基元(除了long和double之外的所有基元)提供超薄空中安全也很重要,这意味着您可以放心,您至少会看到有效值(如果不一致)。
答案 1 :(得分:1)
所有synchronized
都会捕获与其同步的对象的锁定。如果已经捕获了锁,它将等待其释放。它绝不断言该对象的内部字段不会发生变化。为此,有volatile
答案 2 :(得分:1)
在对象监视器A
上进行同步时,可以保证在同一监视器A
上同步的另一个线程将看到第一个线程所做的任何更改任何对象。这是synchronized
提供的可见性保证,仅此而已。
volatile
变量保证线程之间的可见性(仅适用于变量,易失性HashMap
并不意味着地图的内容可见),而不管任何同步的块。