如果我们正在同步读取,我们是否需要同步写入?
我对同步块有一些怀疑。 在我的问题之前,我想分享来自其他相关职位Link for Answer to related question的答案。我从同一个答案引用Peter Lawrey。如果我们正在同步读取,我们是否需要同步写入?
-
同步,确保您拥有的数据的一致视图。这意味着您将读取最新值,而其他缓存将获得最新值 。高速缓存足够聪明,可以通过 特殊总线(不是JLS所要求的但允许)相互通信。总线意味着它不必触碰主存以获得一致的视图。
-
如果您只使用同步,您将不需要易失性。如果你有一个非常简单的操作,同步的 会过度挥发,挥发性是有用的。
在参照上述我有以下三个问题:
Q1。假设在一个多线程应用程序中,只有一个对象或一个原始实例字段只能在一个同步块中读取(写入操作可能会发生在没有同步的其他方法中)。同步块也在其他对象上定义。 是否声明它是不稳定的(即使它只在同步块内读取)有意义? Q2302。 我了解同步已完成的对象的状态值是一致的。我不确定其他对象和原始字段在Synchronized块的读取状态。 假设在没有获得锁的情况下进行更改,但通过获取锁来完成读取。 Alwaysized块中的所有对象和所有原始字段的值的状态都始终具有一致的视图。?
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;
}
}
您需要了解的第一件事情是,在链接答案中讨论的场景与您正在谈论的场景之间存在细微的差异。你谈到修改一个没有同步的值,而所有的值都是在链接的答案的同步上下文中修改的。有了这个理解,让我们来解答你的问题:
Q1。假设在一个多线程应用程序中,只有一个对象或一个原始实例字段只能在一个同步块中读取(写入操作可能会发生在没有同步的其他方法中)。同步块也在其他对象上定义。是否声明它是不稳定的(即使它只在同步块内读取)是否有意义?
是的,它宣布字段为volatile
是有意义的。由于写入不在上下文中,因此不能保证写入线程将新刷新的值刷新到主内存。阅读线程可能仍会因此而看到不一致的值。
假设在没有获得锁的情况下进行更改,但通过获取锁来完成读取。 Alwaysized块中的所有对象和所有原始字段的值的状态都始终具有一致的视图。 ?
答案仍然没有。推理与上述相同。
底线:修改同步上下文之外的值不会确保将这些值刷新到主内存。 (因为读写器线程可能在写入器线程之前进入同步块)在上下文中读取这些值的线程仍可能最终读取较旧的值,即使它们从主内存中获取这些值。
注意,关于原语这个问题的谈判,因此同样重要的是要明白,Java提供外的薄空中安全 32位原语(除了长和双所有原始数据),这意味着您可以放心,您至少会看到有效的价值(如果不一致)。
好吧,但链接的答案呢,它说:1.同步确保你有一个一致的数据视图。这意味着您将读取最新值,其他缓存将获得最新值。和2.如果你只使用synchronized,你不需要volatile。如果你有一个非常简单的操作,同步会过度,挥发性是有用的。他们是不是不正确或完整? –
关联答案中讨论的场景与您正在谈论的场景之间存在细微的差异。你谈到修改一个没有同步的值,而所有的值都是在链接的答案的同步上下文中修改的。在同步上下文之外修改值不会确保它们被刷新到主内存。 – CKing
okk ..有帮助 –
全部确实是捕获它的同步对象的锁。如果锁已被捕获,它将等待其释放。它并不以任何方式断言该对象的内部字段不会改变。为此,有volatile
感谢您的回复,我错误地使用主内存,我已编辑的问题.. –
当你的对象监视器A
上同步,可以保证在同一个显示器A
在另一个线程同步之后会看到第一线作出任何对象任何变化。这就是所提供的可视性保证,仅此而已。
A volatile
不管任何同步块,变量保证可见性(仅用于变量,易失性HashMap
并不意味着映射的内容将可见)。
感谢您的答案。如果假设同步已经在'ObjectA'的监视器上完成,并且我们读取同步块内部的'ObjectB'状态(由某个线程修改其他方法),它是否一致? –
除非在'synchronized(ObjectA)'块中对'ObjectB'进行了修改。相同的显示器 - >更改可见。不同的显示器 - >不能保证。 – Kayaman
很好..其实这是非常接近我想知道的东西。只是为了让我自己清楚一个问题:如果在同一台显示器上进行更改,则所有字段(而不仅仅是同步完成的对象)的更改都是可见的? –
我想对此很好,但那是其中一个最诚实的工作方式。如果你在谈论JMM时想到的是“从内存中获取”的东西,那么你还没有明白它,应该远离并发。但是没有给出的代码是不正确的。 – Voo
使'isSomeFlag'挥发性将解决此问题 – ControlAltDel
@Voo我编辑了我的问题,抱歉使用单词记忆,我的意思是一致的.. –