synchronized

synchronized

2020-10-13
java

轻量级锁 #

  • 使用场景:如果一个对象虽然有多线程访问,但多线程的访问时间是错开的(也就是没有竞争),那么可以使用轻量级锁来优化。
  • 使用线程的栈中的锁记录充当锁。
  • 轻量级锁对使用者是透明的,即语法仍然是synchronized。
  • 轻量级锁在没有竞争时,每次重入仍需要执行CAS操作。

锁膨胀 #

  • 如果在尝试加轻量级锁的过程中,CAS操作无法成功,这时一种情况就是有其他线程为此对象加上了轻量级锁(有竞争),这时需要进行锁膨胀,将轻量级锁变为重量级锁。

自旋优化 #

  • 重量级锁竞争的时候,还可以使用自旋来优化,如果当前线程自旋成功(即这时候持锁线程已经退出了同步块,释放了锁),这时当前线程就可以避免阻塞。

偏向锁 #

  • 只有在第一次使用CAS将线程ID设置到对象头的Mark Word中,之后发现这个线程ID是自己的就表示没有竞争,不用重新CAS。以后只要不发生竞争,这个对象就归该线程所有。
  • 调用对象的hashCode()会禁用该对象的偏向锁;当有其他线程使用偏向锁对象时,会将偏向锁升级为轻量级锁;调用wait/notify会转化为重量级锁。
  • 批量重偏向:如果对象虽然被多个线程访问,但是没有竞争,这时候偏向了t1的线程的对象仍有机会重新偏向t2,重偏向会重置对象的ThreadID。当撤销偏向锁阈值超过20次后,jvm会觉得:我是不是偏向错了呢,于是会在给这些对象加锁时重新偏向至加锁线程。
  • 批量撤销:当撤销偏向锁阈值超过40次后,jvm会觉得:自己确实错了,根本就不应该偏向。于是整个类的所有对象都会变成不可偏向的,新建的对象也是不可偏向的,针对类的优化。