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后面文章会讲到,内存屏障怎么实现刷主内存的后面 更详细的实现原理后面硬件原理的时候会讲到