JUC-ReentrantLock源码分析

1. ReentrantLock定义

PS:要想理解ReentrantLock原理,需要先了解AQS,不了解AQS的可以看先之前的文章->aqs源码解析

ReentrantLock是jdk提供的可中断, 可重入获取, 支持超时, 支持尝试获取锁。它与synchronized锁主要有以下几点不同之处:

  1. 可重入, 一个线程获取独占锁后, 可多次获取, 多次释放(synchronized也一样, 只是synchronized内的代码执行异常后会自动释放到monitor上的锁)
  2. 支持中断(synchronized不支持)
  3. 支持超时机制, 支持尝试获取lock, 支持公不公平获取lock(主要区别在 判断 AQS 中的 Sync Queue 里面是否有其他线程等待获取 lock)
  4. 支持调用 Condition 提供的 await(释放lock, 并等待), signal(将线程节点从 Condition Queue 转移到 Sync Queue 里面)
  5. 在运行 synchronized 里面的代码若抛出异常, 则会自动释放监视器上的lock, 而 ReentrantLock 是需要显示的调用 unlock方法

下面我们先来看看reentrantLock如何使用的:

public class ReentrantLockDemo extends Thread {

    public static Lock lock = new ReentrantLock();
    public static int i = 0;

    public ReentrantLockDemo(String name) {
        super(name);
    }

    public static void main(String[] args) {
        new ReentrantLockDemo("thread1").start();
        new ReentrantLockDemo("thread2").start();
        new ReentrantLockDemo("thread3").start();
    }

    @Override
    public void run(){
        try {
            lock.lock();
            System.out.println(Thread.currentThread().getName() + "获取lock锁");
            TimeUnit.SECONDS.sleep(1);

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            // 因为程序发生异常,lock锁不会自动释放,所以放在finally中释放锁
            lock.unlock();
        }
    }
}

同synchronized一样,对于同一把锁,在同一时刻只会有一个线程获取到锁

2. ReentrantLock特性

2.1 公平锁和非公平锁

 	public ReentrantLock() {
        sync = new NonfairSync();
    }

    /**
     * Creates an instance of {@code ReentrantLock} with the
     * given fairness policy.
     *
     * @param fair {@code true} if this lock should use a fair ordering policy
     */
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

ReentrantLock内部提供两种锁实现,分别是FairSync(公平锁)和NonfairSync(非公平锁)。通过上面的构造方法可以看出,默认是非公平锁,这样的好处是吞吐量高。可以通过有参构造传值,决定使用公平锁或者非公平锁。

2.2 重入锁

和Synchronized一样,ReentrantLock也支持重入锁。因为ReentrantLock是基于AQS实现的(了解aqs可以看我之前的文章,aqs源码解析),当获取锁的线程再次尝试获取锁的时候,通过state++标记锁的获取次数。

3. 源码分析

公平锁和非公平锁的父类:

abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;

        /**
         * Performs {@link Lock#lock}. The main reason for subclassing
         * is to allow fast path for nonfair version.
         */
        abstract void lock();

        /**
         * Performs non-fair tryLock.  tryAcquire is implemented in
         * subclasses, but both need nonfair try for trylock method.
         */
        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;
        }

        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

        protected final boolean isHeldExclusively() {
            // While we must in general read state before owner,
            // we don't need to do so to check if current thread is owner
            return getExclusiveOwnerThread() == Thread.currentThread();
        }

        final ConditionObject newCondition() {
            return new ConditionObject();
        }

        // Methods relayed from outer class

        final Thread getOwner() {
            return getState() == 0 ? null : getExclusiveOwnerThread();
        }

        final int getHoldCount() {
            return isHeldExclusively() ? getState() : 0;
        }

        final boolean isLocked() {
            return getState() != 0;
        }

        /**
         * Reconstitutes the instance from a stream (that is, deserializes it).
         */
        private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
            s.defaultReadObject();
            setState(0); // reset to unlocked state
        }
    }

公平锁:

static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;

        final void lock() {
            acquire(1);
        }

        /**
         * 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();
            int c = getState();
            if (c == 0) {
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
    }

非公平锁:

static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;

        /**
         * Performs lock.  Try immediate barge, backing up to normal
         * acquire on failure.
         */
        final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

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

3.1 lock()分析

我们可以看到FairSync和NoFairSync都继承自Sync,而Sync继承自AbstractQueuedSynchronizer,下面我们来分析获取锁的过程:

	final void lock() {
        acquire(1);
    }

当调用lock方法时,实际调用的是AQS中的acquire方法

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

AQS中的tryAcquire方法是抽象方法,具体的实现是在FairSync和NoFairSync中的,下面是Sync中tryAcquire的具体实现:

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

当tryAcquire方法调用后,会继续走aqs的逻辑去尝试获取锁,如果没有获取到锁,会加入到aqs队列中。

3.2 unlock()分析

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

当调用unlock方法时,调用的也是aqs的release方法:

	public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

tryRelease方法同上,在aqs中也是抽象方法,具体实现也是在Sync中:

	   protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

后续会继续走aqs逻辑进行释放锁操作。

3.3 公平锁和非公平锁分析

3.3.1 非公平锁FairSync

非公平锁中的lock逻辑:

		final void lock() {
			// 会直接尝试获取锁
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

当线程调用lock方法时,不管aqs中等待队列中是否有线程等待,会直接调用compareAndSetState方法尝试获取锁,所以获取锁操作时非公平的。

3.3.2 公平锁NoFairSync

公平锁中的lock逻辑:

	final void lock() {
            acquire(1);
        }

当线程调用lock方法时,直接走aqs的acquire逻辑,判断队列中是否有线程等待,如果有线程等待,不会尝试获取锁,而是加入到等待队列的尾部,服从先到先得的逻辑。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值