ReentrantLock源码解析

目录

前言

源码解析

lock

tryLock

unlock

小结


前言

        ReentrantLock是可重入的互斥锁,虽然具有与synchronized相同功能,但是比synchronized更加灵活。

源码解析

ReentrantLock核心应用的是AQS(AbstractQueuedSynchronizer)。通过类图可以看出,ReentrantLock 实现了Lock接口,从而控制锁的获取和释放等操作。

                其中比较重要的方法有 lock,tryLock 和tryrelease.

lock

        @ReservedStackAccess
        final void lock() {
            if (!initialTryLock())
                acquire(1);
        }

        /**
         * Acquires only if reentrant or queue is empty.
         */
        final boolean initialTryLock() {
            Thread current = Thread.currentThread();
            int c = getState();
            //先尝试去获取锁,获取锁则返回成功
            if (c == 0) {
                if (!hasQueuedThreads() && compareAndSetState(0, 1)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            //查看锁是不是被当前线程所占有,占有则state+1,返回true
            } else if (getExclusiveOwnerThread() == current) {
                if (++c < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(c);
                return true;
            }
            return false;
        }

这里acquire是调用父类的acquire方法,这其实是一个钩子方法,FairSync中重写了tryAcquire方法

    public final void acquire(int arg) {
        if (!tryAcquire(arg))
            acquire(null, arg, false, false, false, 0L);
    }

        /**
         * Acquires only if thread is first waiter or empty
         */
        protected final boolean tryAcquire(int acquires) {
            if (getState() == 0 && !hasQueuedPredecessors() &&
                compareAndSetState(0, acquires)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        其中hasQueuedPredecessors()方法判断当前线程是否是队列第一个等待线程或者不存在等待队列

   public final boolean hasQueuedPredecessors() {
        Thread first = null; Node h, s;
        if ((h = head) != null && ((s = h.next) == null ||
                                   (first = s.waiter) == null ||
                                   s.prev == null))
            first = getFirstQueuedThread(); // retry via getFirstQueuedThread
        return first != null && first != Thread.currentThread();
    }

    /**
     * Returns the first (longest-waiting) thread in the queue, or
     * {@code null} if no threads are currently queued.
     *
     * <p>In this implementation, this operation normally returns in
     * constant time, but may iterate upon contention if other threads are
     * concurrently modifying the queue.
     *
     * @return the first (longest-waiting) thread in the queue, or
     *         {@code null} if no threads are currently queued
     */
    public final Thread getFirstQueuedThread() {
        Thread first = null, w; Node h, s;
        if ((h = head) != null && ((s = h.next) == null ||
                                   (first = s.waiter) == null ||
                                   s.prev == null)) {
            // traverse from tail on stale reads
            for (Node p = tail, q; p != null && (q = p.prev) != null; p = q)
                if ((w = p.waiter) != null)
                    first = w;
        }
        return first;
    }

ReentrantLock 有两个内部类NonfairSync和FairSync分别代表了公平锁和非公平锁,NonfairSync和fairSync的区别在于

NofairSync并不关心当前队列在等待队列中的位置


        /**
         * Acquire for non-reentrant cases after initialTryLock prescreen
         */
        protected final boolean tryAcquire(int acquires) {
            if (getState() == 0 && compareAndSetState(0, acquires)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }
    }

tryLock


        /**
         * Performs non-fair tryLock.
         */
        @ReservedStackAccess
        final boolean tryLock() {
            Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (compareAndSetState(0, 1)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            } else if (getExclusiveOwnerThread() == current) {
                if (++c < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(c);
                return true;
            }
            return false;
        }

ReentrantLock 采取非公平锁的方式去实现tryLock,获取到锁就返回True,否则返回false,同一个线程没执行一次tryLock或者Lock 获取锁成功,state+1.

unlock

public void unlock() {
    sync.release(1);
}


    /**
     * Releases in exclusive mode.  Implemented by unblocking one or
     * more threads if {@link #tryRelease} returns true.
     * This method can be used to implement method {@link Lock#unlock}.
     *
     * @param arg the release argument.  This value is conveyed to
     *        {@link #tryRelease} but is otherwise uninterpreted and
     *        can represent anything you like.
     * @return the value returned from {@link #tryRelease}
     */
    public final boolean release(int arg) {
        if (tryRelease(arg)) {
            signalNext(head);
            return true;
        }
        return false;
    }
        @ReservedStackAccess
        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (getExclusiveOwnerThread() != Thread.currentThread())
                throw new IllegalMonitorStateException();
            boolean free = (c == 0);
            if (free)
                setExclusiveOwnerThread(null);
            setState(c);
            return free;
        }

当前线程占有锁时,每次release 都会使state-1,直到state=0,才释放锁。因此,每次,lock,或者tryLock以后都需要调用unlock来释放锁。

小结

reentrantLock实现了Lock接口,内部应用了AbstractQueuedSyncronizer的子类NonfairSync和FairSync来实现对锁的占用和释放。NonfairSync和FairSync的区别在于:FairSync在trylock时候会判断当前线程是否处于等待队列的队首位置,只有队首位置时才会去获取锁。此外,Lock方法并不区分公平锁还是非公平锁,同时使用非公平锁的方法去去获取锁。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值