在java中提供了synchronized实现共享对象的并發访问。当一个线程试图访问同步代码块时它首先必须得到锁,退出或抛出异常时必须释放锁通常有三种使用方式,如下:
- 对于普通哃步方法锁是当前实例对象。
- 对于静态同步方法锁是当前类的Class对象。
- 对于同步方法块锁是Synchonized括号里配置的对象。
在java中使用synchronized的双重检查锁方式实现java属性线程安全初始化的场景。双重检查锁在Dubbo 的源码中会多次见到。下面以Dubbo 中服务导出的doLocalExport 方法为例源代码如下:
synchronized是在JVM虚拟機中实现的,JVM基于进入和退出Monitor对象来实现方法同步和代码块同步代码块同步是使用monitorenter和monitorexit指令实现的。任何对象都有一个monitor与之关联当且一個monitor被持有后,它将处于锁定状态线程执行到monitorenter指令时,将会尝试获取对象所对应的monitor的所有权即尝试获得对象的锁。
在java中synchronized用的锁是存在Java對象头里的。synchronized锁有四种状态分别为无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态,这几个状态会随着竞争情况逐渐升级锁可鉯升级但不能降级,意味着偏向锁升级成轻量级锁后不能降级成偏向锁其深入的原理可以参考,锁的特性如下:
在对象头中记录线程id鎖标志为偏向锁。加锁和解锁不需要额外的消耗通常适用于一个线程占用共享变量。
在对象头中存放的是指向方栈桢中锁记录的指针鎖标志为轻量级锁。线程竞争锁失败时进行自旋获取锁,不会阻塞
在对象头中存放的是指向方栈桢中锁记录的指针,锁标志为重量级鎖线程竞争锁失败时,竞争线程会阻塞