ReentrantLock

ReentrantLock 即可重入锁,有 3 个内部类:Sync、FairSync 和 NonfairSync。

  • Sync 是一个继承 AQS 的抽象类,并发控制就是通过 Sync 实现的。
  • 有两个子类 FiarSync 和 NonfairSync,即公平锁和非公平锁。

ReentrantLock构造器,默认是非公平锁

  1. private final Sync sync;
  2. public ReentrantLock() { //默认是非公平锁
  3. sync = new NonfairSync();
  4. }
  5. public ReentrantLock(boolean fair) { //可设置为公平锁
  6. sync = fair ? new FairSync() : new NonfairSync();
  7. }

ReentrantLock 加锁

ReentrantLock加锁会根据是公平锁还是非公平锁调用不同方法
lock方法的过程(分为公平和非公平)

  1. 非公平锁会先进行一次CAS操作,去抢占自由状态的锁,若此时锁为非自由状态,则会进行同公平锁一致取锁操作

    1. // 非公平锁 NonfairSync
    2. final void lock() {
    3. if (compareAndSetState(0, 1))
    4. setExclusiveOwnerThread(Thread.currentThread());
    5. else
    6. acquire(1);
    7. }
    8. // 公平锁
    9. final void lock() {
    10. acquire(1);
    11. }
  2. 进入acquire方法

    1. public final void acquire(int arg) {
    2. if (!tryAcquire(arg) &&
    3. acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
    4. selfInterrupt();
    5. }
  3. 进入tryAcquire方法,该方法内对于自由状态下的公平锁和非公平锁有区别,对于重入锁一致

    1. //公平锁
    2. protected final boolean tryAcquire(int acquires) {
    3. final Thread current = Thread.currentThread();
    4. int c = getState();
    5. if (c == 0) {
    6. if (!hasQueuedPredecessors() &&
    7. compareAndSetState(0, acquires)) {
    8. setExclusiveOwnerThread(current);
    9. return true;
    10. }
    11. }
    12. else if (current == getExclusiveOwnerThread()) {
    13. int nextc = c + acquires;
    14. if (nextc < 0)
    15. throw new Error("Maximum lock count exceeded");
    16. setState(nextc);
    17. return true;
    18. }
    19. return false;
    20. }
    21. //非公平锁
    22. protected final boolean tryAcquire(int acquires) {
    23. return nonfairTryAcquire(acquires);
    24. }
    25. final boolean nonfairTryAcquire(int acquires) {
    26. final Thread current = Thread.currentThread();
    27. int c = getState();
    28. if (c == 0) {
    29. if (compareAndSetState(0, acquires)) {
    30. setExclusiveOwnerThread(current);
    31. return true;
    32. }
    33. }
    34. else if (current == getExclusiveOwnerThread()) {
    35. int nextc = c + acquires;
    36. if (nextc < 0) // overflow
    37. throw new Error("Maximum lock count exceeded");
    38. setState(nextc);
    39. return true;
    40. }
    41. return false;
    42. }
    1. 获取锁状态,若state=0自由状态
      1. 非公平锁进行一次CAS操作取锁,成功返回true
      2. 公平锁会进行判断等待队列是否为空,不为空则判断当前线程是否是队头,若是,进行一次CAS操作取锁,成功返回true
    2. state!=0,锁为非自由状态
      1. 判断当前线程是否为持有锁线程,若是则计入重入数,且取锁true,否则false
  4. 取锁失败后,入队addWaiter

    1. private Node addWaiter(Node mode) {
    2. Node node = new Node(Thread.currentThread(), mode);
    3. // Try the fast path of enq; backup to full enq on failure
    4. Node pred = tail;
    5. if (pred != null) {
    6. node.prev = pred;
    7. if (compareAndSetTail(pred, node)) {
    8. pred.next = node;
    9. return node;
    10. }
    11. }
    12. enq(node);
    13. return node;
    14. }
    15. private Node enq(final Node node) {
    16. for (;;) {
    17. Node t = tail;
    18. if (t == null) { // Must initialize
    19. if (compareAndSetHead(new Node()))
    20. tail = head;
    21. } else {
    22. node.prev = t;
    23. if (compareAndSetTail(t, node)) {
    24. t.next = node;
    25. return t;
    26. }
    27. }
    28. }
    29. }
    1. 队尾不为空,即队列不为空,将线程装node存在队尾,入队结束
    2. 队尾为空,即队列为空,为队列进行初始化,将线程装node存在队尾,入队结束
  5. 入队后,acquireQueued

    1. final boolean acquireQueued(final Node node, int arg) {
    2. boolean failed = true;
    3. try {
    4. boolean interrupted = false;
    5. for (;;) {
    6. final Node p = node.predecessor();
    7. if (p == head && tryAcquire(arg)) {
    8. setHead(node);
    9. p.next = null; // help GC
    10. failed = false;
    11. return interrupted;
    12. }
    13. if (shouldParkAfterFailedAcquire(p, node) &&
    14. parkAndCheckInterrupt())
    15. interrupted = true;
    16. }
    17. } finally {
    18. if (failed)
    19. cancelAcquire(node);
    20. }
    21. }
    22. private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
    23. int ws = pred.waitStatus;
    24. if (ws == Node.SIGNAL)
    25. /*
    26. * This node has already set status asking a release
    27. * to signal it, so it can safely park.
    28. */
    29. return true;
    30. if (ws > 0) {
    31. /*
    32. * Predecessor was cancelled. Skip over predecessors and
    33. * indicate retry.
    34. */
    35. do {
    36. node.prev = pred = pred.prev;
    37. } while (pred.waitStatus > 0);
    38. pred.next = node;
    39. } else {
    40. /*
    41. * waitStatus must be 0 or PROPAGATE. Indicate that we
    42. * need a signal, but don't park yet. Caller will need to
    43. * retry to make sure it cannot acquire before parking.
    44. */
    45. compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
    46. }
    47. return false;
    48. }
    1. 判断当前node前一个节点是否队头节点,队头节点是线程为空的节点
    2. 若是,则将其设为头节点,进行取锁,且未被中断
    3. 若不是,则进入shouldParkAfterFailedAcquire
      1. 如果当前节点的前置节点的waitstatus为SIGNAL,说明前置节点也在等待拿锁,所以当前节点是可以挂起的,睡眠当前线程,返回中断状态,若当前线程被中断了,则将当前节点设置为取消节点,并清除多余的取消节点
      2. 如果waitStatus状态是CANCEL,往前搜索,直至搜索到waitStatus<=0,填在其后面,中间部分直接删除
      3. waitStatus是其他状态,既然当前节点已经加入,那么前置节点就应该做好等待锁的准备,所以将前置节点waitStatus置为SIGNAL,若会再循环一次,将当前节点挂起

ReentrantLock 解锁

非公平锁和公平锁解锁的操作是一致的
当调用unlock解锁的时候

  1. sync.release(1); 进入release方法

    1. public void unlock() {
    2. sync.release(1);
    3. }
    4. public final boolean release(int arg) {
    5. if (tryRelease(arg)) {
    6. Node h = head;
    7. if (h != null && h.waitStatus != 0)
    8. unparkSuccessor(h);
    9. return true;
    10. }
    11. return false;
    12. }
  2. tryRelease

    1. 把锁的状态改为自由状态
    2. 解锁的线程和持有的线程不一样,会抛出异常。这种情况一般不会出现,除非你没有加锁直接解锁则会异常
    3. boolean free = false; 标识一下目前还没有释放锁成功,因为你仅仅把锁改成了自由状态,线程没有释放(而且还有可能是重入),所以这个变量是一个过渡变量
    4. c == 0释放锁,返回true
      1. protected final boolean tryRelease(int releases) {
      2. int c = getState() - releases;
      3. if (Thread.currentThread() != getExclusiveOwnerThread())
      4. throw new IllegalMonitorStateException();
      5. boolean free = false;
      6. if (c == 0) {
      7. free = true;
      8. setExclusiveOwnerThread(null);
      9. }
      10. setState(c);
      11. return free;
      12. }
  3. 锁被成功释放后,Node h = head;//拿到对头,if (h != null && h.waitStatus != 0);//判断是否有对头(是否有人在排队),若有节点在排队唤醒头节点

Sync

  1. abstract static class Sync extends AbstractQueuedSynchronizer {
  2. abstract void lock();
  3. final boolean nonfairTryAcquire(int acquires){
  4. final Thread current = Thread.currentThread();
  5. int c = getState();
  6. if (c == 0) {
  7. if (compareAndSetState(0, acquires)) {
  8. setExclusiveOwnerThread(current);
  9. return true;
  10. }
  11. }
  12. else if (current == getExclusiveOwnerThread()) {
  13. int nextc = c + acquires;
  14. if (nextc < 0) // overflow
  15. throw new Error("Maximum lock count exceeded");
  16. setState(nextc);
  17. return true;
  18. }
  19. return false;
  20. }
  21. protected final boolean tryRelease(int releases) {
  22. int c = getState() - releases;
  23. if (Thread.currentThread() != getExclusiveOwnerThread())
  24. throw new IllegalMonitorStateException();
  25. boolean free = false;
  26. if (c == 0) {
  27. free = true;
  28. setExclusiveOwnerThread(null);
  29. }
  30. setState(c);
  31. return free;
  32. }
  33. }
  • Sync 重写了 tryRelease() 释放锁
  • Sync 重写 tryRealese() 方法,并且 FairSync 和 NonfairSync没有再次重写该方法,所以 公平锁和非公平锁释放锁的操作是一样的,即唤醒等待队列中第一个被挂起的线程
  • 公平锁和非公平锁获取锁的方式是不同的。
    • 公平锁获取锁时,如果一个线程已经获取了锁,其他线程都会被挂起进入先进先出等待队列,(即后面来的线程等待的时间没有等待队列中线程等待的时间长的话,那么就会放弃获取锁,直接进入等待队列)
    • 非公平锁获取锁的方式是一种抢占式的,不考虑线程等待时间,无论是哪个线程获取了锁,则其他线程就进入等待队列。
  • 非公平锁取锁nonfairTryAcquire的方法出现在了父类Sync里,是因为 ReentrantLock 继承了Lock接口,Lock接口里面的tryLock方法同样需要这个非公平锁取锁的步骤

nonfairTryAcquire(int acquires)

非公平取锁

  • getState获得锁状态,若state=0为自由状态,进行一次CAS操作获得锁
  • 若state!=0,即为非自由状态,且当前线程为持有锁线程,即重入,state+acquires
  • 以上取锁成功,返回true,失败则false

tryRelease(int releases)

公平锁,非公平锁释放锁

  • getState获得锁状态-releases需要释放的次数,若当前线程为非持有锁线程,抛出异常
  • 若释放锁后的state=0,表示自由状态,将持有锁对象设置=null,且返回true,否则false

FairSync

公平锁

  1. static final class FairSync extends Sync {
  2. final void lock() {
  3. acquire(1);
  4. }
  5. protected final boolean tryAcquire(int acquires) {
  6. final Thread current = Thread.currentThread();
  7. int c = getState();
  8. if (c == 0) {
  9. if (!hasQueuedPredecessors() &&
  10. compareAndSetState(0, acquires)) {
  11. setExclusiveOwnerThread(current);
  12. return true;
  13. }
  14. }
  15. else if (current == getExclusiveOwnerThread()) {
  16. int nextc = c + acquires;
  17. if (nextc < 0)
  18. throw new Error("Maximum lock count exceeded");
  19. setState(nextc);
  20. return true;
  21. }
  22. return false;
  23. }
  24. }

NonfairSync

非公平锁

  1. static final class NonfairSync extends Sync {
  2. final void lock() {
  3. if (compareAndSetState(0, 1))
  4. setExclusiveOwnerThread(Thread.currentThread());
  5. else
  6. acquire(1);
  7. }
  8. protected final boolean tryAcquire(int acquires) {
  9. return nonfairTryAcquire(acquires);
  10. }
  11. }