(个人学习)记volatile和synchronized的区别

  提到synchronized和volatile首先需要想到的是并发编程,在并发的情况下,为了保证代码能正常运行,需要使代码满足三个要求:1.原子性、2.可见性、3有序性

  1.原子性:即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。

  2.可见性:指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。

  3.有序性:即程序执行的顺序按照代码的先后顺序执行。在Java内存模型中,允许编译器和处理器对指令进行重排序,但是重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。

  • volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取(可见性); synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。(加锁保证线程唯一)
  • volatile仅能使用在变量级别(适用范围);synchronized则可以使用在变量、方法、和类级别的
  • volatile仅能实现变量的修改可见性,不能保证原子性(没有加锁);而synchronized则可以保证变量的修改可见性和原子性
  • volatile不会造成线程的阻塞(并不会加锁,只是使得线程在修改变量之前必须从主存中获取最新值,修改值后会第一时间写会主存);synchronized可能会造成线程的阻塞(加锁)。
  • volatile标记的变量不会被编译器优化(一定程度上的有序性,因为volatile标记的变量前后的代码还是会优化);synchronized标记的变量可以被编译器优化(但是因为加锁,线程唯一,重排序并不会影响到结果,即实现了有序性)

例子:一个家有A,B个人(多线程),家里(主存)存款100元(数据),A,B各有一张家里的副卡(工作内存),知道家里存款100元(工作内存中的缓存)

  ①普通情况下,A,B同时出去消费;A知道家里有100元,消费了50,把余额50告诉家里(将数据写回主存);B知道家里有100元,消费了50,把余额50告诉家里(将数据写回主存),最后家里将钱改成50,因为家里只会保存传回来的余额数据,但实际消费了100,最后结果却是余额还剩50

  ②加volatile情况下,A,B同时出去消费;A知道家里有100元,想消费之前,必须让家里告诉自己有多少钱(获取最新值),然后消费50,然后立马把余额50告诉家里(将数据写回主存),家里将余额改成50;B知道家里有100元,也是在想消费之前,获取家里最新余额50,消费50后,把余额0告诉家里(将数据写回主存),最后家里将钱改成0,最后结果余额还剩0

  ③加synchronized情况下,A,B只能同时有一个人出去消费(一个人消费的时候,另一个人只能在家等着(线程阻塞))

  第二种情况下会出现一种问题,假如A出去消费50的时候,消费完了,被打了,昏迷了(线程中断),没有及时把余额告诉家里,而此时B也消费了50,但是因为A昏迷了,没有把余额告诉家里,所以B获取最新值还是100,也会导致最终结果是50(不能保证原子性)

  

posted @   棱角0033  阅读(46)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示