java中volatile和synchronized的区别与联系

 更新时间:2017年10月18日 11:12:12   投稿:lqh  
这篇文章主要介绍了java中volatile和synchronized的区别与联系的相关资料,希望通过本文能帮助到大家,让大家理解这部分内容,需要的朋友可以参考下

java中volatile和synchronized的区别与联系

这个可能是最好的对比volatile和synchronized作用的文章了。volatile是一个变量修饰符,而synchronized是一个方法或块的修饰符。所以我们使用这两种关键字来指定三种简单的存取变量的方式

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

geti1()在当前线程中立即获取在i1变量中的值。线程可以获得变量的本地拷贝,而所获得的变量的值并不一定与其他线程所获得的值相同。特别是,如果其他的线程修改了i1的值,那么当前线程获得的i1的值可能与修改后的值有所差别。实际上,Java有一种主内存的机制,使用一个主内存来保存变量当前的正确的值。线程将变量的值拷贝到自己独立的内存中,而这些线程的内存拷贝可能与主内存中的值不同。所以实际当中可能发生这样的情况,在主内存中i1的值为1,线程1和线程2都更改了i1,但是却没把更新的值传回给主内存或其他线程中,那么可能在线程1中i1的值为2,线程2中i1的值却为3。

另一方面,geti2()可以有效的从主内存中获取i2的值。一个volatile类型的变量不允许线程从主内存中将变量的值拷贝到自己的存储空间。因此,一个声明为volatile类型的变量将在所有的线程中同步的获得数据,不论你在任何线程中更改了变量,其他的线程将立即得到同样的结果。由于线程存取或更改自己的数据拷贝有更高的效率,所以volatile类型变量在性能上有所消耗。
那么如果volatile变量已经可以使数据在线程间同步,那么synchronizes用来干什么呢?两者有两方面的不同。首先,synchronized获取和释放由监听器控制的锁,如果两个线程都使用一个监听器(即相同对象锁),那么监听器可以强制在一个时刻只有一个线程能处理代码块,这是最一般的同步。另外,synchronized还能使内存同步。在实际当中,synchronized使得所有的线程内存与主内存相同步。所以geti3()的执行过程如下:

1.   线程从监听器获取对象的锁。(这里假设监听器非锁,否则线程只有等到监听器解锁才能获取对象锁)

2.   线程内存更新所有的变量,也就是说他将读取主内存中的变量使自己的变量保证有效。(JVM会使用一个“脏”标志来最优化过程,使得仅仅具有“脏”标志变量被更新。详细的情况查询JAVA规范的17.9)

3.   代码块被执行(在这个例子中,设置返回值为刚刚从主内存重置的i3当前的值。)

4.   任何变量的变更将被写回到主内存中。但是这个例子中geti3()没有什么变化。

5.   线程释放对象的锁给监听器。

所以volatile只能在线程内存和主内存之间同步一个变量的值,而synchronized则同步在线程内存和主内存之间的所有变量的值,并且通过锁住和释放监听器来实现。显然,synchronized在性能上将比volatile更加有所消耗。 

关于两者的区别

1.volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取;synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。

2.volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的

3.volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性

4.volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。

5.volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化 

红字体部分的原因如下:

线程A修改了变量还没结束时,另外的线程B可以看到已修改的值,而且可以修改这个变量,而不用等待A释放锁,因为Volatile 变量没上锁

如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

相关文章

  • springboot+dynamicDataSource动态添加切换数据源方式

    springboot+dynamicDataSource动态添加切换数据源方式

    这篇文章主要介绍了springboot+dynamicDataSource动态添加切换数据源方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01
  • java保留小数的四种实现方法

    java保留小数的四种实现方法

    这篇文章主要为大家详细介绍了java保留小数的四种实现方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-11-11
  • 浅谈Java编程之if-else的优化技巧总结

    浅谈Java编程之if-else的优化技巧总结

    说实话,其实我很讨厌在代码里大量使用if-else,一是因为该类代码执行方式属于面向过程的,二嘛,则是会显得代码过于冗余.这篇笔记,主要记录一些自己在工作实践当中针对if-else的优化心得,将会不定期地长期更新,需要的朋友可以参考下
    2021-06-06
  • Mybatis源码解析之初始化分析

    Mybatis源码解析之初始化分析

    这篇文章主要介绍了Mybatis源码解析之初始化分析,Mybatis的初始化过程就是mybatis配置文件的解析过程并将解析结果保存到Configuration类。,需要的朋友可以参考下
    2024-01-01
  • springboot整合jquery和bootstrap框架过程图解

    springboot整合jquery和bootstrap框架过程图解

    这篇文章主要介绍了springboot整合jquery和bootstrap框架过程图解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12
  • Java class文件格式之属性详解_动力节点java学院整理

    Java class文件格式之属性详解_动力节点java学院整理

    这篇文章主要介绍了Java class文件格式之属性详解,需要的朋友可以参考下
    2017-06-06
  • java分割文本字符串的方法

    java分割文本字符串的方法

    这篇文章主要为大家详细介绍了java分割文本字符串的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-06-06
  • 详解SpringMVC HandlerInterceptor拦截器的使用与参数

    详解SpringMVC HandlerInterceptor拦截器的使用与参数

    本文主要介绍了详解SpringMVC HandlerInterceptor拦截器的使用与参数,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • Java SpringBoot自动装配原理详解

    Java SpringBoot自动装配原理详解

    这篇文章主要介绍了详解Spring Boot自动装配的原理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-09-09
  • java全角与半角标点符号相互转换详解

    java全角与半角标点符号相互转换详解

    这篇文章主要为大家介绍了java全角与半角标点符号相互转换详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03

最新评论