【问题标题】:Does synchronized marks variable volatile automatically? [duplicate]synchronized 会自动标记变量 volatile 吗? [复制]
【发布时间】:2018-09-23 11:53:28
【问题描述】:

我正在阅读有关 java 中的同步和易失性的信息。每一篇新文章都让我感到困惑。一篇文章说“Java 的 synchronized 关键字保证了互斥和可见性”。我不确定可见性部分。 java中的volatile是否解决了可见性问题。让我们考虑这个小程序。

class SharedObj
  {
    volatile int sharedVar = 6;

   public int synchronized getVar(){
          return sharedVar; 
         }

   public synchronized setVar(int i){
          return sharedVar=i; 
        }

}

假设这是由 10 个线程运行的,5 个用于读取,5 个用于写入同一 SharedObj 对象。 这里我们既需要同步也需要 volatile?

volatile :因为每个线程都会将 sharedVar 缓存到本地缓存中。

同步:一次一个线程。

【问题讨论】:

  • 如果方法是synchronized,并且该方法包含20000个变量,您是否希望它们都被标记为volatile
  • @Thomas .. 我的困惑是关于实例变量(例如 sharedVar)而不是局部变量。
  • 据我在 cmets 中发布的线程了解,volative 可以省略 sharedVar
  • @Maxim 是的,通过同步gettersetter 并使sharedVar 私有,您可以使SharedObj 类线程安全,并且可以安全地省略volatile

标签: java synchronized volatile


【解决方案1】:

锁定可以同时保证可见性和原子性; volatile变量只能保证可见性

可见性有什么问题? CPU 内核有缓存,当内核要向内存写入数据时,它首先写入缓存,这意味着,即使一个内核认为它向变量写入了新值,其他线程仍然可以观察到旧值(所谓的“陈旧数据”) )。

进入同步块有以下副作用:缓存无效 - 从主内存中获取变量的新值。

离开同步块有以下副作用:所有缓存的数据都被刷新到主内存。

在您的小例子中:图像线程 1 设置值 sharedVar 使用 setVar。因为这个方法是synchronized,所以sharedVar的值在方法结束时被刷新到主内存。当线程 2 想要使用 getVar 读取值时,它首先从主内存中获取 sharedVar 值 - 我们知道,这个值是最新的。所以,这里volatile关键字是多余的。


顺便说一句,从volatile 变量读取具有与离开同步块相同的副作用:不仅volatile 变量值被刷新,而且其他变量也被刷新;并且写入volatile 变量与进入同步块具有相同的副作用:不仅获取volatile 变量值,还获取其他变量;

Brian Goetz 所著的伟大著作 Java concurrency in practice 的第一章完美地解释了一切。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-04-01
    • 2013-10-02
    • 2014-10-22
    • 2011-03-31
    • 1970-01-01
    • 2015-05-20
    • 1970-01-01
    相关资源
    最近更新 更多