Skip to main content

Synchronized

对象锁,悲观锁

作用

使用和原理

  • 对于非静态成员函数,锁加在对象上面的(方法上的访问标志)
  • 对于静态成员函数,锁是加在class对象上(方法上的访问标志)
  • 对于代码块加锁,加到特定对象(monitorenter,monitorexit)
  • 综上,synchronized是在对象头的Mark Word区,存2个重要字段:锁标志位和占用该锁的thread ID

Q&A

优化

主要思想
  • optimistic 乐观编程
    • 表示对于共享资源的访问持乐观态度,认为在大多数情况下不会发生竞争,因此不需要加锁。先用最低成本去执行
  • adaptive 自适应编程
    • 表示根据运行时的情况动态调整程序的行为和策略,以适应不同的环境和需求。
  • double check 双重校验
    • 第一次校验:加锁之前,无锁状态下过滤掉大多数情况
    • 第二次校验:加锁之后,防止第一次和加锁中间,共享数据被其他线程修改过

前置知识:对象头

锁状态偏向模式标志位
未锁定001
轻量级锁定00
重量级锁定10
GC标记11
可偏向110

偏向锁

会有一个标志位,记录获取锁的线程,为了在无竞争状态下,让同一线程更快获取到锁

获取流程
  • 首先获取对象的 MarkWord,判断是否处于可偏向状态
    • 如果是可偏向状态,则通过 CAS 操作,把当前线程的 ID 写入到 MarkWord
      • 如果 cas 成功, 表示已经获得了锁对象的偏向锁,接着执行同步代码块
      • 如果 cas 失败,说明有其他线程已经获得了偏向锁,当前锁存在竞争,需要撤销已获得偏向锁的线程,并升级为轻量级锁
    • 如果是已偏向状态,需要检查当前线程是不是记录线程( MarkWord 中存储的ThreadID 是否等于当前线程的 ThreadID非cas)
      • 如果相等,不需要再次获得锁(加锁,解锁,更新MarkWord),可直接执行同步代码块
      • 如果不相等,偏向模式立刻结束,说明当前锁偏向于其他线程,需要撤销偏向锁并升级到轻量级锁

轻量级锁

存在竞争的情况下,短期内不会阻塞吗,会先通过自旋尝试获取锁

  • 先判断对象的锁状态是不是无锁状态(标志位01,偏向模式0)
  • 然后在栈帧中复制一份对象头的MarkWord,cas尝试更新对象头MarkWord的指针
    • 如果cas更新成功,标志位改成00
    • 如果失败,double check一下MarkWord的指针,如果是当前线程的指针,更新成功
    • 如果double check失败,意味着有多线程竞争,当前线程会自旋多尝试几次,当自旋超过一定次数,或者有第三个线程来竞争的时候,升级到重量级锁

重量级锁