【并发编程】synchronized如何保证原子性、一致性和可见性

介绍

synchronized是解决线程安全的问题,常用在同步普通方法、静态方法、代码块中,每个对象有一个锁和等待队列,锁只能被一个线程持有,其他需要锁的线程需要阻塞等待,锁被释放后,对象会从队列中取出一个并唤醒,唤醒哪个线程是不确定的,不保证公平性,
因此,synchronized是非公平、可重入的悲观锁

同步方法

生成的字节码文件中会多一个ACC_SYNCHRONIZED标志位,当一个线程访问方法时,会去检查是否存在ACC_SYNCHRONIZED标志位,如果存在,执行线程将先获取monitor,获取成功之后才能执行方法体,方法执行完后再释放monitor,在方法执行期间,其他任何线程都无法在获取同一个monitor对象,也叫隐式同步

同步代码块

加了synchronized关键字的代码段,生成的字节码会多出monitorenter和monitorexit两条指令,每个monitor维护着一个记录拥有次数的计数器,未被拥有的monitor的该计数器0,没当一个线程执行monitorenter后,该计数器自增1,当issue执行monitorexit指令的时候,计数器自减1,当计数器为0的时候,monitor将被释放,也叫显式同步


两种没有本质区别,都是通过monitor来实现同步。

synchronized是如何保证原子性、有序性,可见性

  • 原子性

注意:原子性在并发编程中通常是指不可再分割的,例如int i =0; i++ 就是很好的例子,而在数据库ACID中,原子性指的是要么全部成功,要么全部失败。

synchronized保证原子性是通过monitorenter和monitorexit来实现的,当线程执行monitorenter的时候需要先获得锁才能执行后面的方法,当执行monitorexit的时候就需要释放锁。
在没有被释放之前,其他线程是无法再次获取锁的,所以通过monitorenter和monitorexit可以保证synchronized修饰的代码在同一时间只有一个线程访问。因此在java中可以使用synchronized来保证原子性。

  • 有序性
    因为处理器的优化和执行重排序等,CPU可能对输入代码进行乱序执行,比如1,2,3可能被优化成1,3,2。这就是可能存在有序性问题,那么synchronized是如何保证有序性的呢?

在java程序中天然的有序性可以总结为:**如果在本线程内观察,所有的操作都是天然有序的。如果在一个线程中观察另一个线程,所有操作都是无需的。这句话也是《深入理解Java虚拟机》中的原话,周志明并没有详细的解释,这里我简单扩展一下,这其实和as-if-serial语义相关。
as-if-serial:不管怎么重排序,单线程程序的执行结果都不能被改变。编译器和处理器无论如何优化,都必须遵守as-if-serial。
那么我们就可以简单的认为,单线程程序是按照顺序执行的 **。
所以,由于synchronized修饰的代码,在保证原子性的同时,也保证了在同一时间只能被一个线程访问。那么也就是单线程执行的,所以,可以保证其有序性。

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

Java内存模型中规定了所有的变量都存储在主内存中,每条线程还有自己的工作内存,线程的工作内存保存了该线程中使用到的变量的主内存副本拷贝,线程对变量的所有操作都必须在工作内存中,而不能直接读写主内存,不同的线程直接也无法访问对方工作内存中的变量,线程间的变量传递均需要自己的工作内存和主内存直接进行数据同步,因此,就会出现某个线程改了变量的值,其他线程不可见的情况。

synchronized修饰的代码,在开始的会加锁,执行完成会释放锁,而为了保证可见性,有这样一个规则:对一个变量解释之前,必须先把此变量同步回主内存中。这样解锁后,后续线程就可以放到被修改后的值。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈橙橙丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值