synchronized实现原理

synchronized ,jdk1.6之前是重量级锁,多线程通过获取monitor获取对象进行同步。只有获取到monitor对象的线程才能执行临界代码.获取monitor对象的过程是

调用操作系统本身的互斥 Mutex Lock指令进行的,对线程做切换,会有用户态切换到内核态,比较损耗性能。

jdk1.6之后对锁进行了优化,锁升级过程如下:无锁--偏向锁--轻量级锁--重量级锁。

锁升级过程是通过对当前锁对象的对象头mark-word进行修改锁标识位,线程id等字段进行控制的。

获取偏向锁的过程如下:

当线程进入同步代码时,判断当前对象头中mark-word相应字段是否是可偏向状态,如果是则进行cas(原子操作)修改mark-word相应字段,

写入线程id,锁标识等此时锁变为偏向锁,如果判断当前对象mark-word线程id不为空且线程id不等于自身线程id(说明被其他线程占有了(已偏向)),则进行竞争,

导致已经得到偏向的线程释放偏向锁,清空标识,把线程改变为无锁状态或者轻量级锁状态。

获取轻量级锁的过程如下:

(1)判断当前对象是否处于无锁状态(hashcode、0、01),若是,则JVM首先将在当前线程的栈帧中建立一个名为锁记录(Lock Record)的空间,用于存储锁对象目前的Mark Word的拷贝(官方把这份拷贝加了一个Displaced前缀,即Displaced Mark Word);否则执行步骤(3);

(2)JVM利用CAS操作尝试将对象的Mark Word更新为指向Lock Record的指正,如果成功表示竞争到锁,则将锁标志位变成00(表示此对象处于轻量级锁状态),执行同步操作;如果失败则执行步骤(3);

(3)判断当前对象的Mark Word是否指向当前线程的栈帧,如果是则表示当前线程已经持有当前对象的锁,则直接执行同步代码块;否则只能说明该锁对象已经被其他线程抢占了,这时轻量级锁需要膨胀为重量级锁,锁标志位变成10,后面等待的线程将会进入阻塞状态;

总结:不论是获取偏向锁,还是轻量级锁都是通过cas(原子操作)修改对象头中的某些标识字段的值,来确认是否获取到锁资源。获取到偏向锁--(如果有其他线程竞争失败则升级为)轻量级锁--(如果线程自旋后获取锁资源失败则升级为)重量级锁。

升级为重量级锁后则会产生线程阻塞,会有线程的切换系统资源的消耗。

每一个对象都会和一个monitor相关联,对象头中mark-word中LockWord中会存储monitor的引用地址,monitor对象中会存储拥有当前锁的线程的唯一标识。

posted on 2019-11-03 23:02  xiangoffice  阅读(122)  评论(0编辑  收藏  举报

导航