背景

java中每个对象都是一个monitor,monitor的构成有独占标记、等待队列、入口队列。
针对一块被同步的锁住的代码块,对于任何线程,都要获取独占锁之后才能进入,否则只能再入口队列进行等待。

wait和notify

如果线程获取到锁之后,调用wait方法(释放锁),会进入等待队列。在什么场景会有这种情况,比如线程在等待外部状态改变的时候才能继续执行,典型的如生产者-消费者模式,对于生产线程来说,如果队列满了就要wait,等待消费者线程消费后notify唤醒,对于消费者线程来说,如果队列空了就要wait等待生产者线程生产后notify唤醒,他们都是基于一个锁来实现的,所以也解释了wait和notify必须要在synchronized块中执行,因为notify要释放锁,notify线程要给与锁。
被notify的线程不是立即执行,而是从等待队列放到入口队列,重新竞争锁。

锁升级

  1. 无锁:加了锁,但是处于多线程环境,那么JIT会优化为无锁执行。
  2. 偏向锁:大部分都是同一个线程竞争锁,可以偏向该锁减少cas自旋。
  3. 轻量级锁:解决低锁冲突场景下的加锁时的内核态和用户态的切换成本问题,通过自旋解决。
  4. 重量级锁:通过多次自旋无法获取,升级为普通锁。