java - 如果要同步读,是否还需要同步写?

标签 java multithreading heap-memory synchronized-block

我对同步块(synchronized block)没有什么疑问。 在我提问之前,我想分享另一篇相关帖子 Link for Answer to related question 的答案。 。我引用Peter Lawrey来自同一个答案。

  1. synchronized ensures you have a consistent view of the data. This means you will read the latest value and other caches will get the latest value. Caches are smart enough to talk to each other via a special bus (not something required by the JLS, but allowed) This bus means that it doesn't have to touch main memory to get a consistent view.

  2. If you only use synchronized, you wouldn't need volatile. Volatile is useful if you have a very simple operation for which synchronized would be overkill.

引用上述内容,我有以下三个问题:

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

第二季度。 我了解已完成同步的对象的状态值是一致的。我不确定在 Synchronized block 中读取的其他对象和原始字段的状态。 假设在没有获取锁的情况下进行更改,但通过获取锁来完成读取。 Synchronized block 内所有对象的状态和所有原始字段的值是否始终具有一致的 View 。 ?

第三季度。 [更新]:无论我们锁定什么,同步块(synchronized block)中读取的所有字段都会从主内存中读取吗?[由 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. Suppose in a multi threaded application there is an object or a primitive instance field being only read in a synchronized block (write may be happening in some other method without synchronization). Also Synchronized block is defined upon some other Object. Does declaring it volatile (even if it is read inside Synchronized block only) makes any sense ?

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

Suppose changes are made without obtaining a lock but reading is done by obtaining a lock. Does state of all the objects and value of all primitive fields inside a Synchronized block will have consistent view always. ?

答案仍然是否定的。道理和上面是一样的。

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


请注意,这个问题讨论的是原语,因此了解 Java 为 32 位原语(除了 long 和 double 之外的所有原语)提供凭空而来的安全性也很重要,这意味着您可以放心,您至少会看到一个有效值(如果不一致)。

关于java - 如果要同步读,是否还需要同步写?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42163468/

相关文章:

android - Android 中的栈内存

java - 有没有办法让命令文本跟随输入?

java - 在 XML 和 Java 中创建 View 然后在以后引用和加载它们?

C程序只在调试时写入文件

multithreading - 如何将函数发送到另一个线程?

c++ - 堆内存分析

c++ - 为什么静态类变量不能分配到栈中?

java - 无法将 JMenuItem 添加到 JPopupMenu 中的 JMenu

java - ReentrantLock 显示 "unlocked"但第一个线程停止

java - 生产者线程和消费者线程之间的线程间通信?