二.synchronized关键字

synchronized的作用,synchronized可以保证并发安全问题,比如i++操作,实际是两步,先读取i的值,再把i+1,这样的话多个线程并发执行i++的时候就可能出现并发问题了,这里使用synchronized就能解决并发安全问题,synchronized需要一个锁对象,可以是一个对象实例,也可以是一个Class,直接加在方法上就是当前实例对象 也就是this,多个线程同时执行synchronized代码块的时候,如果synchronized加锁的对象是同一个对象,那么一个加锁成功,另外一个就需要等待第一个线程执行完释放锁才能加锁成功,synchronized是可重入锁,也就是一个线程可以多次加锁

 

synchronized实现原理:synchronized会有一个锁对象,锁对象里面会有一个monitor指针,monitor指针指向一个ObjectMonitor对象,ObjectMonitor里面有一个entryList存放等待加锁的线程,维护了一个count为0,加锁的时候先判断count是不是为0,如果不为0就等待,如果为0就把0变成1,其他线程就要等待了,释放锁的时候把count-1,count为0以后其他线程就能获取锁了

条件队列wait/notify实现线程通信

在synchronized里面调用wait方法会让当前获取锁对象的线程睡眠释放锁,调用notify会唤醒睡眠的线wait/notify实现原理:在对象里面还一个waitset,调用wait方法的时候就当前线程放到waitset里面,然后释放锁了,调用notify方法会唤醒waitset里面的线程,waitset线程重新获取锁

一张图来表示synchronized和wait/notify原理

 

 

synchronized能保证原子性、可见性、有序性

保证原子性就是通过上面说的,接下来看看如何保证可见性和有序性的

synchronized(this) { // monitorenter

Load内存屏障

Acquire内存屏障

…………

Release内存屏障

} // monitorexit

Store内存屏障

进入synchronized的时候会执行一个monitorentey指令,这个指令会执行两个操作,一个Load内存屏障,表示指令重排synchronized代码块之前的不能再synchronized方面之后,Acquire内存屏障,会强制把数据刷到主内存读取最新数据。

synchronized代码块执行完毕以后会做一个monitorexit操作,执行Release内存屏障,会把synchronized做的修改刷到主内存,Store内存屏障让指令重排序的时候synchronized代码块后面的指令不会排到synchronized结束之前。

所以通过Load内存屏障+Store内存屏障实现有序性问题,synchronized代码块不会和synchronized代码指令重排,但是synchronized代码块里面的指令是可以重排序的

通过Acquire内存屏障+release内存屏障实现可见性

 

count从0变成1用cas实现的,cas后面文章会讲到,内存屏障怎么实现刷主内存的后面 更详细的实现原理后面硬件原理的时候会讲到

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值