【多线程】synchronized关键字详解

发布时间 2024-01-07 13:11:45作者: 此木|西贝

synchronized是什么?

java中使用synchronized关键字实现加锁/解锁,来保证多线程对共享资源的访问,防止多个线程同时访问共享资源导致数据问题。

synchronized是重量级锁还是轻量级锁?

java早期版本中synchronized是重量级锁,无论是否发生了锁竞争,都会进行加锁的动作。但是java6之后官方对synchronized进行优化,在没有发生锁竞争时,不会进行加锁的动作,只有发生锁竞争时,才会升级为重量级锁。这就是锁升级。

synchronized锁升级原理

  • 锁升级的步骤
    • 无锁状态
    • 偏向锁
    • 轻量级锁
    • 重量级锁
    • 锁释放

JAVA中64位虚拟机对象头信息分布

无锁状态

锁标志位是01,代表还未执行过

偏向锁

偏向锁:代表锁会偏向于第一个获得他的线程,如果接下来的执行过程中,该锁没有被其他线程获取,则持有偏向锁的线程永远不需要再进行同步

加锁流程:

  • 当同步对象第一次被一个线程获取后,虚拟机会将锁标志位设置为 01,偏向模式设置为 1,代表进入偏向锁。同时使用CAS将获取到这个锁的线程ID记录在Mark word中,如果cas操作成功,持有偏向锁的线程每次进入这个相关同步块时,虚拟机都可以不在进行任何同步操作(例如加锁、解锁等)
  • 一旦有另一个线程尝试获取这个锁,偏向锁模式宣告结束。根据锁对象目前是否处于被锁状态决定是否撤销偏向,撤销后锁标志位恢复到未锁定或轻量级锁状态。

轻量级锁

轻量级锁:如果一个对象虽然有多线程需要加锁,但是多个线程之间加锁是错开的,并无竞争,那么可以使用轻量级锁来优化。如果没有锁膨胀,轻量级锁就不会和操作系统有交互。

加锁流程:

  • 代码进入同步块时,如果此时同步对象没有被锁定 (锁标志位 01),则虚拟机在当前线程创建名为(Lock Record)的锁记录空间,用于存储对象Mark Word的拷贝。
  • 虚拟机使用CAS将对象的Mark Word更新为执行Lock Record的指针,更新成功后,所标志为变更为00,表示处于轻量级锁。
  • 如果更新失败,则意味着该资源存在其他线程访问,出现了锁竞争。虚拟机首先会检查对象Mark Word是否指向当前线程,如果是,则代表以及拥有了锁,直接进行操作。否则代表多个线程竞争同一个锁,锁膨胀为重量级锁,所标志位变为 10,此时Mark Word中存储的是重量级锁的指针,未获取到锁的线程进入阻塞状态。

锁释放

释放锁的流程:

  • 轻量级锁/偏向锁解锁过程也同样通过CAS来操作,如果对象Mark Word仍然指向线程的锁记录,就利用CAS将线程中的Mark Word信息替换回来。
  • 替换成功,解锁成功
  • 替换失败,说明发生了锁竞争,就要在释放锁的同时,唤醒阻塞的线程。

加锁解锁流程

image