(个人学习)记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(不能保证原子性)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~