锁一共有4种状态:无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态。
一、偏向锁
大多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得,为了让线程获得锁的代价更低而引入了偏向锁。
偏向锁使用了一种等到竞争出现才释放锁的机制,所以当其他线程尝试竞争偏向锁时,持有偏向锁的线程才会释放锁。
那么什么时候使用偏向锁呢?在这样的场景:如果始终只有一个线程在执行同步块,在它没有执行完释放锁之前,没有其它线程去执行同步块,在锁无竞争的情况下使用,一旦有了竞争就升级为轻量级锁,升级为轻量级锁的时候需要撤销偏向锁,撤销偏向锁的时候会导致线程暂停操作。
二、轻量级锁
如果偏向锁失败,那么系统会进行轻量级锁的操作,使用CAS操作来尝试加锁。如果轻量级锁失败,才调用系统级别的重量级锁来加锁。
轻量级锁加锁:
线程在执行同步块之前,JVM会创建存储锁记录的空间。然后线程尝试使用CAS将对象头中的Mark Word替换为指向锁记录的指针,成功,当前线程获得锁。如果失败,表示其他线程竞争锁,当前线程便尝试使用自旋来获取锁。
轻量级锁解锁:
会使用原子的CAS操作将Displaced Mark Word替换回到对象头,如果成功,则表示没有竞争发生。如果失败,表示当前锁存在竞争,锁就会膨胀成重量级锁。
三、自旋锁
自旋:当线程申请锁时,锁被占用,就让线程执行循环,看看持有锁的线程是否会释放。如还没获得锁,进入同步阻塞状态。
自适应自旋: 自适应意味着时间不固定,而是由前一次的自旋时间和锁拥有者状态决定。如果在同一个锁对象上,自旋等待刚刚成功,并持锁线程在运行,jvm就认为自旋是再次成功的。如果自旋很少成功过,尝试获取这个锁将阻塞线程。