文章目录

  • AQS(面试)
  • 基于AQS的ReentrantLock
  • 公平锁获取锁的过程总结
  • 非公平锁过程总结
  • 条件锁
  • await大致流程


AQS(面试)

AQS的全称是AbstractQueuedSynchronizer

AQS内部维护一个状态state,通过原子更新(CAS)这个状态变量可实现加锁解锁操作。

如果要实现自己的锁,可以基于AQS,重写tryAcquire,tryRelease,lock(会调用tryAcquire),unlock(tryRelease)方法。

基于AQS的ReentrantLock

ReentrantLock中主要定义了三个内部类:Sync、NonfairSync、FairSync。
ReentrantLock实现了Lock接口,Lock接口里面定义了java中锁应该实现的几个方法:

// 获取锁
void lock();
// 获取锁(可中断)
void lockInterruptibly() throws InterruptedException;
// 尝试获取锁,如果没获取到锁,就返回false
boolean tryLock();
// 尝试获取锁,如果没获取到锁,就等待一段时间,这段时间内还没获取到锁就返回false
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
// 释放锁
void unlock();
// 条件锁
Condition newCondition();
公平锁获取锁的过程总结

获取锁的主要过程大致如下:

  • 1、先判断有没有锁(state==0)。
  • 2、如果没有锁且没有线程在排队,则尝试获取锁(CAS),如果获取到了就直接返回了;
  • 3、尝试获取锁失败,会判断占有锁的线程是不是当前现场,如果是则state+1,获取锁成功
  • 4、如果获取锁失败且占有锁的线程不是当前线程,则会新建一个节点,CAS插入尾部,入队。
  • 5、如果入队没成功,调用enq方法,不断尝试入队。
  • 6、循环执行,判断当前节点的前面一个节点是不是head,如果是则尝试获取锁,获取成功则返回。
  • 7、如果前面一个节点不是head或者没获取到锁,在循环过程中可能会park/
非公平锁过程总结
  • 1、非公平锁一上来就会尝试获取锁,不管队列中有没有其他线程。
  • 2、如果没有获取到,则会继续tryAcquire方法继续尝试获取锁。

条件锁

条件锁,是指在获取锁之后发现当前业务场景自己无法处理,而需要等待某个条件的出现才可以继续处理时使用的一种锁。

await、signal

条件锁维护一个条件队列。

await大致流程
  • 1、新建一个节点加入到条件队列中去;
  • 2、完全释放当前线程占有的锁;
  • 3、阻塞当前线程,并等待条件的出现;
  • 4、条件已出现(此时节点已经移到AQS的队列中),尝试获取锁;