ReentrantLock
公平锁
- 尝试加锁 tryAcquire(arg)
- 查看state是否是0 也就是是否是自由状态
- 如果是0 先看是否有队列的存在 hasQueuedPredecessors或队列中是否有线程排队 如果队列是空(无队列的情况)那么就继续compareAndSetState(CAS)如果是此时是state还是0那么就setExclusiveOwnerThread(current); 加锁成功直接 return true
- 如果不是自由状态查看当前拿到锁的线程是否和当前线程相同 相同则返回true
- state 不为0且当前持有锁的线程不是自己 或state=0 但是队列中有人 返回 false
- Note:如果tryAcquire(arg) 成功则直接返回了不需要任何其他的操作与队列无关,此时的队列仍然是空的,head 和tail都是null
- 查看state是否是0 也就是是否是自由状态
- 如果尝试加锁失败 tryAcquire(arg) 失败则需要执行acquireQueued(addWaiter(Node.EXCLUSIVE), arg)
- addWaiter(Node.EXCLUSIVE) 返回的是包含有当前Thread的新node
- 如果这个AQS队列是空的那么需要进行对队列的初始化enq(node);也就是先将头节点和尾节点,指向一个new node里面的成员变量都是null,然后再将当前的node(里面包含有Thread)的prev指向空node,然后让tail指向自己,然后空node的next指向自己。
- 如果这个队列不为空,那么就是直接把自己加入到尾节点中,排队排在队尾
- 此时会真正的进入acquireQueued函数
- 首先判断是否自己的前一个节点是刚才说的空node如果是就说明自己排在第二个,下一个就是自己,因此他可以自旋一次,再次尝试加锁tryAcquire(arg) 大部分都是失败的
- 失败则直接park 阻塞这个线程(调用的是操作系统的函数)
- addWaiter(Node.EXCLUSIVE) 返回的是包含有当前Thread的新node
非公平锁
- 首先与公平锁不同的一点是他直接去进行compareAndSetState(CAS)在公平锁中他需要先判断state是否是0(判断锁是否是自由状态)且会判断队列是否为空,队列中是否有其他线程在排队。
- 而非公平锁在第一步就直接去判断是否锁是空闲的,如果空闲就插队,然后占有锁然后返回
- 如果此时无法占有锁,那么执行acquire(1);
- 执行nonfair的 tryAcquire(arg)
- 这是fair和nonfair的tryAcquire(arg)
- 在我看来这里唯一的区别就是:是否有查看队列存在或这队列是否有线程在等待
- 在非公平锁中会先查看state的状态(锁是否是自由的)
- 如果不自由那么park
- 如果是自由状态那就尝试插队获取锁(不会去查看队列)。如果获取失败那就park