JUC之ReentrantLock

JUC之ReentrantLock

引言

承接上篇JUC之AbstractQueuedSynchronizer 我们分析一下最常用的锁 ReentrantLock,即可重入锁。
上篇我们分析了aqs的acquire方法和release方法。接下来我们分析ReentrantLock是如何通过aqs实现锁的。

Lock

先看一下锁的定义。

public interface Lock {

    /**
     * 加锁,如果获取不到锁会阻塞当前线程
     */
    void lock();

    /**
     * 加锁,如果获取不到锁会阻塞当前线程和lock方法不同的是,锁阻塞期间会被中断
     */
    void lockInterruptibly() throws InterruptedException;

    /**
     * 尝试加锁,没有抢到锁时会返回false,反之,返回true
     */
    boolean tryLock();

    /**
     * 尝试加锁,成功返回true;失败,阻塞并尝试加锁,超时返回false,否则加锁成功返回true
     */
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;

    /**
     * 解锁
     */
    void unlock();

    /**
     * 返回和锁绑定的Condition对象
     */
    Condition newCondition();
}

ReentrantLock核心方法及实现

这里ReentrantLock的用法不再细说,我们看ReentrantLock是如何实现的。
ReentrantLock仅持有了一个Sync类型的变量 sync,所有锁的方法的实现都是通过sync提供的方法来实现的。
在这里插入图片描述
ReentrantLock核心方法:

    
    public void lock() {
        sync.lock();
    }

    
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

    
    public boolean tryLock() {
        return sync.nonfairTryAcquire(1);
    }

    
    public boolean tryLock(long timeout, TimeUnit unit)
            throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }

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

    
    public Condition newCondition() {
        return sync.newCondition();
    }

    
    public int getHoldCount() {
        return sync.getHoldCount();
    }

    
    public boolean isHeldByCurrentThread() {
        return sync.isHeldExclusively();
    }

   
    public boolean isLocked() {
        return sync.isLocked();
    }

    public final boolean isFair() {
        return sync instanceof FairSync;
    }

    protected Thread getOwner() {
        return sync.getOwner();
    }

    public final boolean hasQueuedThreads() {
        return sync.hasQueuedThreads();
    }

    public final boolean hasQueuedThread(Thread thread) {
        return sync.isQueued(thread);
    }

    public final int getQueueLength() {
        return sync.getQueueLength();
    }

    protected Collection<Thread> getQueuedThreads() {
        return sync.getQueuedThreads();
    }

    public boolean hasWaiters(Condition condition) {
        if (condition == null)
            throw new NullPointerException();
        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
            throw new IllegalArgumentException("not owner");
        return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
    }

而Sync是ReentrantLock的内部类,继承与aqs,同样是抽象类。
Sync的实现类同样是内部类,有两个NonfairSync和FairSync,不公平和公平的同步器。
JUC之ReentrantLock_第1张图片
具体使用哪个同步器,是通过ReentrantLock的构造函数传入的boolean类型的入参fair来决定的。默认使用的是非公平的同步器。

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

    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

为什么默认使用非公平的同步器?是因为非公平的同步器效率更高,具体下面分析。
我们来看一下Sync的实现

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

        /**
         * 提供了一个抽象方法,交由子类实现
         */
        abstract void lock();

        /**
         * 非公平的尝试获取锁,这里涉及到了设置获得锁的线程,以及state,都是aqs提供的方法。
         */
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            //获取当前的state
            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;
                //把获得锁的线程置为null
                setExclusiveOwnerThread(null);
            }
            //设置锁的状态,因为同时只会有一个线程执行到这里,所以不需要利用cas操作保证线程安全。
            setState(c);
            return free;
        }

		/**
		* 是不是当前线程独占
		*/
        protected final boolean isHeldExclusively() {
            return getExclusiveOwnerThread() == Thread.currentThread();
        }
		
		/**
		* 生成Condtion对象
		*/
        final ConditionObject newCondition() {
            return new ConditionObject();
        }

        /**
        * 当前线程是不是当前锁的持有线程
        */
        final Thread getOwner() {
            return getState() == 0 ? null : getExclusiveOwnerThread();
        }
		
		/**
		* 持有的状态值
		*/
        final int getHoldCount() {
            return isHeldExclusively() ? getState() : 0;
        }
		
		/**
		* 是否有线程获得锁
		*/
        final boolean isLocked() {
            return getState() != 0;
        }

        /**
         * 反序列化锁,将锁的转态置为0
         */
        private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
            s.defaultReadObject();
            setState(0); // reset to unlocked state
        }
    }

Sync代码比较简单,接下来我们来看NonfairSync和FairSync,主要关注是如何实现非公平和公平的。

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

        
        final void lock() {
        	// 立刻尝试设置状态,这里是为了效率
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

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

    
    static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;
		
        final void lock() {
        	//和NonfairSync对比,没有尝试设置状态
            acquire(1);
        }

        
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
            	// 如果队列中没有等待的线程,才会尝试设置状态。假如队列中有别的线程在等待,将会返回false,之后的方法会把当前线程加入到等待的队列。这是和NonfairSync的区别。
                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;
        }
    }

结语

ReentranLock的实现比较简单,主要是通过Sync来实现锁的方法,其中最核心的方法是tryAcquire()和tryRelease()方法,有了这两个方法结合aqs提供的方法,我们就可以实现一个完整的锁。
下一篇我们将会分析ReentrantLock的lockInterruptibly(),tryLock(long timeout, TimeUnit unit)和newCondition()方法。

你可能感兴趣的:(jdk源码阅读)