在 Hotspot 虚拟机中,Java 对象头包含_mark 和_klass(继承自 OopDesc),其中synchronized 用的锁就是保存在_mark 中的。
synchronized 中锁的状态分为无锁/偏向锁/轻量级锁/重量级锁 四种状态。同时这几个状态随着竞争情况逐渐升级。并且锁可以升级但是无法降级。
同时编译器会清除一些使用了同步,但是代码块内却没有涉及同步数据的锁。
Java对象头Mark Word
- 无锁
- 不锁定资源,所有线程都可以访问并且修改资源,但是只有一个线程可以修改成功。特点是修改操作在循环体内,如 CAS 操作。
- 偏向锁 Biased Lock
- 大部分情况下,锁不存在多线程竞争,并且总是由同一个线程多次获得。于是便引入了偏向锁。
- 当锁对象第一次被线程获得时,会将对象头的标志位设置为01,即偏向模式。同时 CAS操作尝试将获取锁的线程 ID 记录在 Mark Word。若 CAS 成功,则表示获取锁成功。当当前线程再次去获得锁或者退出同步的时候,无需进行 CAS,只要简单的检测下Mark Wrod 记录的线程 ID 是否是当前 ID 即可。
-
当其他线程尝试去获得偏向锁时,发现锁的线程 ID 不是当前线程,即发生了竞争。此时已经获得偏向锁的线程会释放锁(达到一个全局安全点 safe point)。撤销偏向锁后,会根据拥有偏向锁的线程状态将_mark 设置为无锁状态或者变成轻量级锁(标志设置为 00)。
锁的状态转换以及 Mark Word
实验来看看偏向锁下的 Mark Word 是什么样子的,JDB+HDSB
jsd 附带参数 -XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0表示开启偏向锁
public class Main {
public static void main(String[] args) {
Main main = new Main();
main.addString("sss");
}
private List<String> list = new ArrayList<>();
public void addString(String s) {
synchronized (this) {
list.add(s);
}
}
}
运行 jdb,在 list.add(s);加上断点
轻量级锁 锁
网友评论