Java 同步标记是否自动可变?
我在读java中的同步和易失性。每一篇新文章都让我感到困惑。一篇文章说“Java的synchronized关键字保证了互斥性和可见性”。我不确定可见性部分。在java中,volatile不能解决可见性问题。让我们考虑一下这个小程序。< /P>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;
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
。