Synchronized的表现形式
普通同步方法
- 普通同步方法使用
synchronized
关键字修饰,锁对象是当前实例对象(即方法所属对象的实例)。
public synchronized void method() {
// 锁对象是当前实例对象
}
静态同步方法
- 静态同步方法使用
synchronized
关键字修饰,锁对象是当前类的Class
对象。
public static synchronized void staticMethod() {
// 锁对象是当前类的 Class 对象
}
同步方法块
- 同步方法块可以指定任意对象作为锁对象。
public void method() {
synchronized (lockObject) {
// 锁对象是 synchronized 括号里配置的对象 lockObject
}
}
Java对象头
锁的原理
JVM 基于 进 入和退出 Monitor 对象来实现 方法同步和代 码块 同步,但两者的 实现细节 不一 样 。代 码块 同步是使用 monitorenter和monitorexit 指令 实现 的,而方法同步是使用另外一种方式 实现 的, 细节 在 JVM 规 范里并没有详细说明。但是,方法的同步同 样 可以使用 这 两个指令来 实现 。 monitorenter指令是在 编译 后插入到同步代 码块 的开始位置,而 monitorexit 是插入到方法 结 束 处 和异常 处 , JVM 要保 证 每个 monitorenter 必 须 有 对应 的 monitorexit 与之配 对 。任何 对 象都有 一个 monitor 与之关 联 ,当且一个 monitor 被持有后,它将 处 于 锁 定状 态 。 线 程 执 行到 monitorenter 指令 时 ,将会 尝试获 取 对 象所 对应 的 monitor 的所有 权 ,即 尝试获 得 对 象的 锁 。 总结来讲就是两点- 标记锁的开始和结束
- 在对象头中做标记
锁的升级
偏向锁
当前线程加锁,先不释放锁,等到有线程来请求锁,并且当前线程已经执行完毕,才会释放锁。轻量级锁
当锁被其他线程持有,该线程会一直通过自旋的方式来竞争锁。
重量级锁
当轻量级锁解锁时,存在锁的竞争,则会升级成为重量级锁,竞争失败的线程会进入堵塞队列。