代码人生

Java中Volatile和Synchronized关键字的区别

代码人生 http://www.she9.com 2018-08-23 11:16 出处:网络 编辑:@技术狂热粉
本文介绍了Java中的一些基本概念,但非常重要。 volatile是一个字段修饰符,而synchronized修饰了代码块和方法。

本文介绍了Java中的一些基本概念,但非常重要。


volatile是一个字段修饰符,而synchronized修饰了代码块和方法。


因此,我们可以使用这两个关键字指定一个简单访问器的三个变量:

        int i1;                      
        int geti1() {return i1;}
        
        volatile int i2;              
        int geti2() {return i2;}        
        
        int i3;
        synchronized int geti3() {return i3;}

在上面,我们定义了三个整数变量:i1、i2和i3。我们定义了三个相应的getter方法:geti1()、geti2()和geti3()。


geti1()访问当前线程中存储在i1中的值。


线程可以拥有变量的本地副本,并且数据不必与其他线程中的数据相同。特别是,另一个线程可能在其线程中更新了i1,但是当前线程中的值可能与更新后的值不同。实际上,Java演示了“主”内存的概念,这是存储变量当前“正确”值的内存。线程可以有自己的变量数据副本,线程副本可以不同于“主”内存。


因此,如果thread1和thread2都更新了i1,那么“主”内存的值可能为1,thread1的值为2,thread3的值为3。但是,更新的值还没有传播到“主”内存或其他线程。


另一方面,geti2()有效地从“主”内存访问i2的值。不允许volatile变量具有与当前保存在“主”内存中的值不同的变量的本地副本。实际上,声明为volatile的变量必须在所有线程之间同步它的数据,以便在任何线程中访问或更新变量时,所有其他线程都能立即看到相同的值。通常,volatile变量比普通变量有更高的访问和更新开销。通常,线程被允许拥有自己的数据副本,这是为了提高效率。


volatile和synchronized有两个区别:


首先,synchronized在monitors(监视器)上获得并释放锁,它一次只能强制一个线程执行代码块。这是同步的一个非常著名的方面。但是synchronized也同步了内存。实际上,synchronized使整个线程内存与“主”内存同步。


因此,执行geti3()会执行以下操作:

        1、线程为这个对象获取监视器上的锁。

        

        2、线程内存刷新所有的变量,也就是说,它的所有变量都有效地从“主”内存读取。

        

        3、执行代码块。在本例中,这意味着将返回值设置为i3的当前值,i3可能刚刚从“主”内存中重置。

        

        4、对变量的任何更改通常会被写到“主”内存中,但是对于geti3(),我们没有更改。

        

        5、线程释放这个对象在监视器上的锁。


因此,当volatile只在线程内存和“主”内存之间同步一个变量的值时,同步将同步线程内存和“主”内存之间的所有变量的值并锁定,并释放一个监视器来控制多线程之间的所有权。

从这些信息可以得出结论,synchronized比volatile的开销更大。


请关注公众号:程序你好
0

精彩评论

暂无评论...
验证码 换一张
取 消