JAVA中的synchronized和volatile的个人理解

本文探讨了synchronized和volatile在多线程环境下的作用及局限性。解释了synchronized如何实现资源的同步访问,以及为何它不能确保多CPU环境下数据的一致性。同时介绍了volatile如何帮助解决这一问题,并指出了其非原子性的限制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

个人理解仅供参考。

 

synchronized对于同一颗cpu或者说同一个核来说,是原子性的。诸多线程只能同步访问被同步的域。这些线程之间必须形成竞争关系,竞争被同步的资源。

实例:

 

static int a;

synchronized(a){

//do something here

...

}

 

a就是被抢占的资源,也正是因为这个破a,诸多线程之间才形成了竞争关系。

 

听起来好像a一定不会出错了,因为所有的线程都是对a顺序操作了。

 

但很不幸忽略了一个问题,对a上的锁是不牢靠的,不在于synchronized本身,而是a本身。

 

假如你有两个cpu,每一个cpu都有独立的工作内存(寄存器或者缓存之类的什么玩意),每个cpu都跑着5个线程,总共十个,他们都抢占a,问题来了:

 

A CPU和B CPU都想操作 a, 但他们两个CPU上的线程不具备竞争条件,他们有各自的时钟,和各自的工作内存。

 

假设此时a == 0;

 

A CPU操作a从主存读到A CPU内存,此时B也要多a操作,他也把a读到自己的CPU内存中。

 

a此时在俩个CPU内存中都是0。

 

A CPU上的线程A1抢占到了时间片,A2,A3,A4,A5都等待,A1把a加1,然后写入主存。

 

现在内存里a的值是1了。

 

在我们描述商议过程的时候B CPU里也发生了同样的事情,线程B1抢占了B CPU里的a(此时a还是0呢),然后把a加1,写会主存。

 

干了a的值被加了两次,可惜他还是1。

 

 

此时volatile关键字就解决了这个问题,他的出现告诉cpu别从你得存储里拿a,从主存里拿! 这样就避免了CPU各自处理各自的a的副本的情况。

 

但很遗憾,volitle基本上不是原子的。他没办法解决多个线程并发访问带来的脏数据问题。

 

所以我们可以synchronized和volatile同时使用,把锁加在主存上。

 

 

总结:

synchronized同步CPU内存上的变量,但无法维护各CPU内存上的变量的值保持同步。

volatile可以保证所有线程访问的是同一个变量(在主存中,而没有副本),但他没办法保持线程同步。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值