并发包中锁原理剖析

LockSupport

主要作用是挂起和唤醒线程

主要方法

  • park:挂起线程
  • unpark:如果因park挂起的,调用unpark后,线程被唤醒
  • parkNanos:如果没有拿到许可证,超时后会自动返回
  • parkUntil:与parkNanos区别是parkUntil的时间是从1970年开始算的

AQS

抽象队列同步器,是一个双向队列,通过Node类型的head和tail记录队首和队尾元素。Node的thread变量记录进行AQS的线程

Node元素

  • SHARED:标记该线程是获取共享资源时被阻塞挂起后放入AQS队列的
  • EXCLUSIVE:标记获取独占资源时阻塞被挂起后放入AQS队列的
  • waitStatus:线程等待状态:
    • CANCELLED
    • SIGNAL
    • CONDITION
    • PROPAGATE
  • head:记录队首
  • tail:记录队尾元素
  • thread:记录进入AQS的线程

ConditionObject

用来结合锁实现线程同步,可以直接访问AQS内部变量。ConditionObject作为条件变量,每个条件变量对应一个条件队列。

AQS操作state的方式

  • 独占方式:一个线程获取到了锁,其他线程获取失败进入阻塞。获取到锁的线程,,AQS会利用CAS将state状态值有0设置为1,如果锁是可重入的,已经获取到锁的线程再次获取时会将state值递增加一。
  • 共享方式:类似于信号量的获取,如果一个信号被线程获取了,其他线程尝试获取时如果信号量满足条件则可以获取到锁。

AQS的条件变量的支持

条件变量为signal和await,AQS一个锁可以对应多个条件变量,每个条件变量内部维护一个条件队列,存放调用条件变量await方法是被阻塞的线程。

条件变量作用示例:线程A获取到锁后调用了锁创建的条件变量1,那么线程A会释放锁,当前线程被转换为Node节点插入条件变量1的条件队列。

await方法:调用该方法前需要获取到锁,调用方法后会将该线程放到条件变量的阻塞队列(不是AQS队列)。然后释放锁。

signal方法:将条件队列中队头的线程节点移除,并放入AQS阻塞队列,激活这个线程