当前位置: 首页 > 知识库问答 >
问题:

如果同步读取,是否需要同步写入?

伊铭
2023-03-14

我对同步块有一些疑问。在提问之前,我想分享另一个相关帖子链接的答案,以回答相关问题。我引用彼得·劳里的同一个答案。

>

  • <块引号>

    同步确保您对数据有一致的视图。这意味着您将读取最新值,其他缓存将获得最新值。缓存足够智能,可以通过特殊总线相互通信(JLS不需要,但允许)该总线意味着它不必触摸主存储器即可获得一致的视图。

    如果您只使用同步,则不需要Volatile。如果您有一个非常简单的操作,而同步将是多余的,那么Volatile很有用。

    关于以上问题,我有三个问题:

    Q1.假设在多线程应用程序中,有一个对象或原语实例字段仅在同步块中读取(写入可能在没有同步的其他方法中发生)。同步块也定义在其他对象上。将其声明为volatile(即使它仅在同步块内读取)有意义吗?

    Q2。我知道已完成同步的对象的状态值是一致的。我不确定在Synchronized块中读取的其他对象和原始字段的状态。假设在没有获得锁的情况下进行了更改,但是通过获得锁进行了读取。同步块中所有对象的状态和所有原语字段的值是否总是具有一致的视图。?

    问题 3.[更新] :无论我们锁定什么,同步块中读取的所有字段都将从主内存中读取吗?[由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;
      }
    }
    
  • 共有3个答案

    狄珂
    2023-03-14

    当您在对象监视器A上同步时,可以保证随后在同一监视器A上同步的另一个线程将看到第一个线程对任何对象所做的任何更改。这就是同步提供的可见性保证,仅此而已。

    可变变量保证线程之间的可见性(仅对于变量,可变性 HashMap 并不意味着映射的内容是可见的),而不管任何同步块。

    蒲功
    2023-03-14

    所有同步所做的就是捕获它同步的对象的锁。如果锁已经被捕获,它将等待释放。它不会以任何方式断言该对象的内部字段不会更改。为此,有易失性

    韩佐
    2023-03-14

    首先你需要明白的是,链接答案中正在讨论的场景和你正在谈论的场景之间存在微妙的区别。您谈到在没有同步的情况下修改值,而在链接答案中,所有值都在同步的上下文中修改。了解这一点后,让我们来回答您的问题:

    Q1.假设在多线程应用程序中,有一个对象或原语实例字段仅在同步块中读取(写入可能在没有同步的其他方法中发生)。同步块也定义在其他对象上。将其声明为volatile(即使它仅在同步块内读取)有意义吗?

    是的,将字段声明为volatile是有意义的。由于写入不是在同步的上下文中进行的,因此无法保证写入线程会将新更新的值刷新到主内存中。因此,读取线程仍可能看到不一致的值。

    假设在没有获取锁的情况下进行更改,但读取是通过获取锁来完成的。同步块内所有对象的状态和所有基元字段的值是否始终具有一致的视图。?

    答案仍然是否定的。推理与上述相同。

    底线:在同步上下文之外修改值不会确保这些值被刷新到主存储器。(因为读取器线程可能会在写入线程之前进入同步块)在同步上下文中读取这些值的线程最终可能仍然会读取旧值,即使它们从主存储器中获取这些值。

    请注意,这个问题涉及基元,因此了解Java为32位基元(除长基元和双基元之外的所有基元)提供了超薄的空中安全性也很重要,这意味着您可以放心,您至少会看到一个有效的值(如果不一致)。

     类似资料:
    • 问题内容: 我对同步块几乎没有疑问。 1. > 同步可确保您拥有一致的数据视图。这意味着您将读取最新值,而其他缓存将获得最新值。高速缓存足够智能,可以通过特殊总线相互通信(这不是JLS所必需的,但允许)。该总线意味着不必触摸主内存即可获得一致的视图。 如果仅使用同步,则不需要volatile。如果您有一个非常简单的操作(对于同步操作可能会过分杀伤),则波动性很有用。 参考上面,我有以下三个问题:

    • 问题内容: 我有两个线程,我想确保我在LinkedBlockingQueue上正确进行了同步。这正确吗?还是不需要在(messageToCommsQueue)上进行显式同步? 宣言: 方法一: 方法二: 问题答案: 是的,没有必要。JavaDoc说: BlockingQueue实现是线程安全的。

    • 如何写这个问题?老实说,我不明白这个问题的意思。A) 编写读者和作者优先于读者的解决方案,并评论每个信号量的功能。(记住变量和信号量的定义和初始化)B)读卡器的优先级意味着什么?当一个作家在写作时,到达的读者会发生什么?当编写器结束其操作时会发生什么?

    • 问题内容: 这样做,即ConcurrentHashMap(所有非retreival操作,等)需要在被包裹块?我知道所有这些操作都是线程安全的,因此这样做有真正的好处/需要吗?使用的唯一操作是和。 问题答案: 不,这样做会失去您的利益。您也可以使用with 或锁定整个表(这是在中包装操作时要执行的操作,因为隐含的监视器是整个对象实例。) 目的是通过允许在表上进行并发读/写而不锁定整个表来提高并发代码

    • 问题内容: 说我有一个全局对象: 有一个线程定期运行以从远程获取新编号并更新(仅写入): 并且有一个或多个线程随机使用此全局变量(仅读取): 您可以看到我不使用任何锁或对其进行保护,对吗?是否有可能引起问题的潜在问题? 更新: 就我而言,读取线程必须实时获取最新的值并不是很重要。我的意思是,如果有任何问题(由于缺少锁定/同步而导致)使一个读取线程错过了该值,那就没关系了,因为它将有机会尽快运行相同

    • 问题内容: 这似乎是一个非常基本的问题,但我找不到明确的确认。 假设我有一个本身已正确同步的类: 如果我需要 引用 在线程之间共享的该类的实例, 我仍然需要将该实例声明为volatile或final ,对吗?如: 或者,如果不能是最终的,则因为其实例化取决于其他一些事先未知的条件(与GUI的交互,来自套接字的信息等): final或volatile是强制性的 ,将访问权限同步到其自身成员的事实并不