Java 同步标记是否自动可变?

Java 同步标记是否自动可变?,java,synchronized,volatile,Java,Synchronized,Volatile,我在读java中的同步和易失性。每一篇新文章都让我感到困惑。一篇文章说“Java的synchronized关键字保证了互斥性和可见性”。我不确定可见性部分。在java中,volatile不能解决可见性问题。让我们考虑一下这个小程序。< /P> class SharedObj { volatile int sharedVar = 6; public int synchronized getVar(){ return sharedVar;

我在读java中的同步和易失性。每一篇新文章都让我感到困惑。一篇文章说“Java的synchronized关键字保证了互斥性和可见性”。我不确定可见性部分。在java中,volatile不能解决可见性问题。让我们考虑一下这个小程序。< /P>
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:因为每个线程都会将sharedVar缓存到本地缓存中

同步:一次一个线程

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

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

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

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

对于您的小示例:image thread-1使用
setVar
设置值
sharedVar
。由于此方法是同步的,
sharedVar
的值在方法结束时刷新到主存。当线程2想要使用
getVar
读取值时,它首先从主存获取
sharedVar
值,我们知道,这个值是最新的。因此,这里的
volatile
关键字是多余的


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


Brian Goetz的名著《Java并发实践》(Java concurrency in practice)的第一章完美地解释了一切。

如果该方法是同步的,并且该方法包含20000个变量,您会期望所有变量也被标记为volatile吗?@Thomas。。我的困惑在于实例变量(示例中的sharedVar)不是局部变量。正如我从评论中发布的线程中了解到的,
volative
可以省略
sharedVar
@Maxim Yes,通过同步
getter
setter
并使
sharedVar
私有化,可以使
SharedObj
类线程安全,并且可以安全地省略
volatile