ReentrantLock源码解析(整理中)

39 篇文章 1 订阅
8 篇文章 0 订阅

可以很轻易的看到其内部有个基于AQS的sync抽象类,并且基于这个抽象类创建了公平锁FairSync非公平锁NonFairSync两个静态内部类。

通过构造方法可以看出如果不特别指定是否公平,则默认创建非公平锁

 

上锁流程

成功上锁

  1. 创建非公平锁。
  2. 若当前状态state为0,则将0置1,并设当前线程获取独占锁。
  3. 结束
  final void lock() {
            1. 创建非公平锁。
            if (compareAndSetState(0, 1))
                2. 若当前状态state为0,则将0置1,并设当前线程获取独占锁。
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

上锁失败

  1. 创建非公平锁。
  2. 由于当前已有线程获得独占锁,所以state=1,无法将state从0置1,所以走else分支中的acquire(1)。
  3. 调用非公平锁中重写的tryAcquire(1),尝试获取独占锁。
  4. 若期间之前获取锁的线程释放了锁,使得state归0,则当前线程获取锁。
  5. 若当前线程已经获取了锁,结果又请求锁,那就是重入锁,state往上累加
  6. 若一直是其他线程持有锁,就返回false,表示上锁失败。
  7. 失败后调用addWaiter,将当前线程封装为节点,尾插到AQS的等待队列waitQueue中。
  8. 走acquireQueued流程。
    1. 进入自旋,调用shouldParkAfterFailAcquired,将当前节点的前驱设置为signal,表示当前节点即将陷入沉睡(挂起park),后续需要它是需要被unpark。
    2. 然后调用parkAndCheckInterrupt,将自己挂起park,等待唤醒。
    3. 被唤醒时判断自己是被unpark正常唤醒,还是被中断唤醒,若为中断环境,设置interrupted标记为true。
    4. 如果是中断唤醒使得当前线程获取了锁,对不起,继续中断吧。
  final void lock() {
            1. 创建非公平锁。
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                2. 由于当前已有线程获得独占锁,所以state=1,无法将state从0置1,所以走else分支中的acquire(1)。
                acquire(1);
        }

 public final void acquire(int arg) {
        3. 调用非公平锁中重写的tryAcquire(1),尝试获取独占锁
        if (!tryAcquire(arg) &&   7. 失败后调用addWaiter,将当前线程封装为节点,尾插到AQS的等待队列waitQueue中。
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) 8. 走acquireQueued流程。
            selfInterrupt(); 8.4 如果是中断唤醒使得当前线程获取了锁,对不起,继续中断吧。
    }


protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }


final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            4. 若期间之前获取锁的线程释放了锁,使得state归0,则当前线程获取锁。
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            5. 若当前线程已经获取了锁,结果又请求锁,那就是重入锁,state往上累加。
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            6. 若一直是其他线程持有锁,就返回false,表示上锁失败。
            return false;
        }


final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                8.1 进入自旋,调用shouldParkAfterFailAcquired,将当前节点的前驱设置为signal,表示当前节点即将陷入沉睡(挂起park),后续需要它是需要被unpark。
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt()) 8.2 然后调用parkAndCheckInterrupt,将自己挂起park,等待唤醒
                    interrupted = true; 8.3 被唤醒时判断自己是被unpark正常唤醒,还是被中断唤醒,若为中断环境,设置interrupted标记为true
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

 private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int ws = pred.waitStatus;
        if (ws == Node.SIGNAL)
            /*
             * This node has already set status asking a release
             * to signal it, so it can safely park.
             */
            return true;
        if (ws > 0) {
            /*
             * Predecessor was cancelled. Skip over predecessors and
             * indicate retry.
             */
            do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {
            /*
             * waitStatus must be 0 or PROPAGATE.  Indicate that we
             * need a signal, but don't park yet.  Caller will need to
             * retry to make sure it cannot acquire before parking.
             */
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }



 private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);
        return Thread.interrupted();
    }

 

  final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

4. 在acquire(1)中调用NonFairSync重写的tryAcquire方法,判断能否获得锁。

由于在2中,已经将state置1,且标记当前线程为独占线程,

 public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }


final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

5. 不能获得则加入waitQueue(addWaiter)。

6. 然后调用acquired流程。

7. 最后将当前线程中断。

 public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

 

FairSync中对AQS的tryAquire()方法的实现

  1. 判断当前有没有线程获取锁
  2. 若没有线程获取锁(state=0),则state增加,且将当前线程标记为独占线程
  3. 如果当前线程已经是独占线程,则表示同一个线程重复获取锁(可重入锁),则继续累加state
/**
         * Fair version of tryAcquire.  Don't grant access unless
         * recursive call or no waiters or is first.
         */
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            1. 判断当前有没有线程获取锁
            int c = getState();
            2. 若没有线程获取锁(state=0),则state增加,且将当前线程标记为独占线程
            if (c == 0) {
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            3. 如果当前线程已经是独占线程,则表示同一个线程重复获取锁(可重入锁),则继续累加state
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

关联博客

java线程池ThreadPoolExecutor类详解 https://blog.csdn.net/qq_26950567/article/details/117435378

ReentrantLock源码解析 https://blog.csdn.net/qq_26950567/article/details/117442244

AbstractQueueSynchronizer详解 https://blog.csdn.net/qq_26950567/article/details/117440770

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值