一、Lock与Synchronized的区别

    Lock是个接口,有如下方法:

Java Lock 实现 java lock trylock_java

  • lock():获取锁
  • lockInterruptibly():可中断的获取锁,与lock()不同的点是该方法会响应中断(锁获取中,可中断当前县城)
  • tryLock(): 非阻塞获取锁,立即返回结果
  • tryLock(long time,TimeUnit unit) :超时获取锁,(1)获得锁(2)超时被中断 (3)超时结束,返回false
  • unlock() :释放锁
  • newCondition(): 获取等待通知组件,线程获得锁,才能调用该组件的wait,调用完,释放锁

重量级锁。

Lock接口与synchronized 关键字都可实现同步,Lock接口具备Synchronized没有的主要特征如下:

(1) 尝试非阻塞获取锁: tryLock()

(2) 能被中断的获取锁: lockInterruptibly() ,获取锁的线程能够相应中断,当获取到锁的线程被中断时,中断议程会抛出,并释放锁。

(3) 超时获取锁:tryLock(long time,TimeUnit unit)在指定的截止时间之前获取锁,如果截止时间到了无法获取,则返回。

 

二、Java锁的实现基石---AbstractQueuedSynchronizer

    Java中有各种不同的锁及同步组件(ReentrantLock,ReentrantReadWriteLock),而这些锁是面向使用者的,隐藏了实现细节。而其中实现最为关键的基石即是队列同步器 AbstractQueuedSynchronizer,其实现了同步状态管理、线程排队、等待与唤醒等底层实现。

    对于AbstractQueuedSynchronizer(AQS)来说, 

    实现同步状态的管理有三个方法:

    getState(),setState(int newState),compareAndSetState(int expect,int update)--使用CAS设置当前状态,用来保证状态设置的原子性。

    AQS使用了模板方法模式,重写相关方法,在相关方法内部实现对同步状态的管理,可重写相关的方法如下:

Java Lock 实现 java lock trylock_java_02

    

  • tryAcquire(int): 独占式获取同步状态,实现该方法需要使用CAS设置同步状态,compareAndSetState
  • tryRelease(int):独占式释放同步状态
  • tryAcquireShared(int): 共享式获取同步状态,返回大于等于0的值,则成功
  • tryReleaseShared(int): 共享式释放同步状态
  • isHeldExclusively(): 是否被当前线程独占

    实现自定义同步组件时,一般通过自定义子类Sync 继承AQS,重写以上若干方法,会调用同步器提供的模板方法,可被调用的与同步相关的模板方法如下:

    

Java Lock 实现 java lock trylock_Java Lock 实现_03

  •     acquire(int): 独占式获取同步状态, 如果当前线程获取同步状态成功,则由该方法返回,否则,进入同步队列等待, 会调用重写的tryAcquire(int arg)
  •     acquireInterruptibly(int):与acquire一样,不过会响应中断。若线程未获取到同步状态进入同步队列中,当前线程被中断,该方法会抛出InterruptedException并返回。
  •     tryAcquireNanos(int,long): 在acquireInterruptibly(int) 基础上增加了超时限制,当前线程在超时时间内没有获取到同步状态,则返回false。
  •     release(int): 独占式释放同步状态,并将同步队列里第一个节点包含的线程唤醒
  •     acquireShared(int): 共享式获取同步状态,与独占式区别是同一时刻有多个线程获取到同步状态。
  •     acquireSharedInterruptibly(int): 与acquireShared(int)相同,该方法相应中断
  •     tryAcquireSharedNanos(int,long):在acquireSharedInterruptibly(int) 基础上增加超时限制
  •     releaseShared(int) : 共享式释放同步状态

      在看具体的代码实例之前,着重描述下AQS的原理:

      既然有同步队列,一定会有相应的结点,Node结构如下:

Java Lock 实现 java lock trylock_Java Lock 实现_04

    

    waitStatus: 等待状态:

  • (1)CANCELLED 值为1,由于同步队列中等待超时或被中断,需要从同步队列中取消等待,最终状态。
  • (2) SIGNAL 值为-1 ,后继节点的线程处于等待状态,当前节点的线程若释放了同步状态或被取消,将会通知后继节点,使后继节点的线程得以运行。
  • (3) CONDITION 值为-2 ,节点在等待队列中,线程等待在Condition上,当其他线程对Condition 调用了signal()后,节点将从等待队列中转移到同步队列中。
  • (4) PROPAGATE,值为-3,表示下一次共享式同步状态获取将会无条件地被传播下去
  • (5) INITIAL,值为0,初始状态。

    prev: 前驱节点,当节点加入同步队列时被设置(尾部添加)

    next: 后继节点

    nextWaiter: 等待队列中的后继节点,如果当前节点是共享的,那么这个字段将是一个SHARED常量,也就是说节点类型(独占和共享) 和等待队列中的后继节点共用一个字段。

    thread: 获取同步状态的线程。

    一个同步队列的基本结构如下图:

Java Lock 实现 java lock trylock_java_05


     2.1 独占式获取

     在AQS实现类的注解里有如下代码,实现了一个简单的不可重入的互斥锁:

public class Mutex implements Lock {
    // 静态内部类,自定义同步器
    private static class Sync extends AbstractQueuedSynchronizer {
        // 是否处于占用状态
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }
        // 当状态为0的时候获取锁
        public boolean tryAcquire(int aquires) {
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }
        // 释放锁,将状态设置为0
        protected boolean tryRelease(int releases) {
            if (getState() == 0)
                throw new IllegalMonitorStateException();
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }
        // 返回一个Condition,每个condition都包含了一个condition队列
        Condition newCondition() {
            return new ConditionObject();
        }
    }
    // 仅需要将操作代理到Sync上即可
    private final Sync sync = new Sync();
    @Override
    public void lock() {
        sync.acquire(1);
    }
    @Override
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }
    @Override
    public boolean tryLock() {
        return sync.tryAcquire(1);
    }
    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(time));
    }
    @Override
    public void unlock() {
        sync.release(1);
    }
    @Override
    public Condition newCondition() {
        return sync.newCondition();
    }
}

    Mutex 重写了AQS的 tryAcquire ,tryRelease 方法,当调用lock时,调用 AQS的acquire() 方法:

// 独占式获取同步状态,对中断不敏感
    public final void acquire(int arg) {
        // 首先调用tryAcquire获取同步状态,若失败,构造同步节点并调用addWaiter加入到同步队列中
        // 调用acquireQueued 使该节点以死循环方式获取同步状态
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

    tryAcquire里,重写的逻辑是若state为0,CAS为1,返回true,否则返回false。

    addWaiter方法如下:

// 创建一个指定mode的Node节点,并入队。 mode 为EXCLUSIVE即是独占模式
    private Node addWaiter(Node mode) {
        Node node = new Node(Thread.currentThread(), mode);
        // 快速尝试在尾部添加node
        Node pred = tail;
        if (pred != null) {
            node.prev = pred;
            // 使用unsafe.compareAndSwapObject 保证是线程安全的
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        enq(node);
        return node;
    }
// 入队,初始化,使用死循环方式,保证节点能够正确添加,否则不断重试
     // 并且通过CAS将并发添加节点的请求 串行化 
     private Node enq(final Node node) {
        for (;;) {
            Node t = tail;
            if (t == null) { // 初始化队列
                if (compareAndSetHead(new Node()))
                    tail = head;
            } else {
                node.prev = t;
                if (compareAndSetTail(t, node)) {
                    t.next = node;
                    return t;
                }
            }
        }
    }

    而节点进入同步队列后,就通过acquireQueued方法 进入了一个自旋的过程,每个节点都在自省的观察,条件满足,则获取到同步状态,否则就处于自旋过程中,阻塞节点的线程。

    

// 独占模式获取锁,且忽略 中断
     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;
                }
                // 节点不是头节点,检查节点状态看是否SIGNAL,若是,则阻塞当前线程,LockSupport.park()
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

    而unlock时会调用 sync.release 方法,释放同步状态,并唤醒后续节点,

// 释放独占同步状态,并唤醒后继节点   
    public final boolean release(int arg) {
        // 本例setState 为0
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }
private void unparkSuccessor(Node node) {
        int ws = node.waitStatus;
        if (ws < 0)
            compareAndSetWaitStatus(node, ws, 0);
        Node s = node.next;
        if (s == null || s.waitStatus > 0) {
            s = null;
            for (Node t = tail; t != null && t != node; t = t.prev)
                if (t.waitStatus <= 0)
                    s = t;
        }
        if (s != null)
            LockSupport.unpark(s.thread);
    }


    2.2 共享式获取

     共享式获取与独占式获取不同在于,能否有多个线程同时获取到同步状态。文件读写,写是独占,读可以共享。

     而AQS的acquireShared 可共享式的获取同步状态,此方法内部调用 doAcquireShared:

     

private void doAcquireShared(int arg) {
        final Node node = addWaiter(Node.SHARED);
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                if (p == head) {
                    int r = tryAcquireShared(arg);
                    if (r >= 0) {
                        setHeadAndPropagate(node, r);
                        p.next = null; // help GC
                        if (interrupted)
                            selfInterrupt();
                        failed = false;
                        return;
                    }
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }


     2.3 独占超时获取

    AQS得问doAcquireNanos(int arg,long nanosTimeout) 方法可以超时获取同步状态,指定时间未获取到,则返回false,并且此方法算是acquireInterruptibly的增强版,若线程被中断,会立刻返回,抛出InterruptedException。

private boolean doAcquireNanos(int arg, long nanosTimeout)
            throws InterruptedException {
        if (nanosTimeout <= 0L)
            return false;
        final long deadline = System.nanoTime() + nanosTimeout;
        final Node node = addWaiter(Node.EXCLUSIVE);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return true;
                }
                nanosTimeout = deadline - System.nanoTime();
                // 超时返回
                if (nanosTimeout <= 0L)
                    return false;
                // spinForTimeoutThreshold为1000纳秒
                if (shouldParkAfterFailedAcquire(p, node) &&
                    nanosTimeout > spinForTimeoutThreshold)
                    LockSupport.parkNanos(this, nanosTimeout);
                if (Thread.interrupted())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

    


三、ReetrantLock的实现细节

    可重入锁支持重进入,一个线程可以对资源重复加锁,此外,还支持获取锁的公平和非公平性选择。

    上面实现mutex 是典型的不可重入锁,线程获取mutex资源后,在调用lock方法,调用tryAcquire会返回false,导致线程被阻塞,synchronized关键字隐式支持重进入,比如synchronized修饰的递归方法。

    公平性锁,简单来说就是先获取的请求优先被满足。公平性锁性能没有非公平的效率高,由于非公平锁连续获得同步状态的记录非常大,所以公平性锁会有更多的线程切换,导致性能损耗。

    ReetrantLock 使用了上述提到的AQS实现 可重入和公平性 ,先看ReetrantLock如何重写AQS里的方法:

Java Lock 实现 java lock trylock_自定义_06

  

    Sync是个抽象类,lock为抽象方法, 继承自AQS,FairSync 与 NonfairSync实现了不同的lock 和 tryAcquire,可看出公平锁与非公平锁主要不同在 tryAcquire上。


3.1 可重入的实现

     非公平时,获取同步状态时 都会使用到 Sync里的nonfairTryAcquire(int),此方法实现了可重入,源码如下:

// nonfair try lock 
       final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            // 若首次加锁
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            // 判断是否是同一线程,若是,则加acquires,同一时刻只有当前线程访问
            // 实现可重入
            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;
        }

        释放同步状态时,会使用到 tryRelease方法 ,如下:

// 释放同步资源
        protected final boolean tryRelease(int releases) {
            // 释放 releases个同步状态
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            // 只有同步状态为0 才真正释放此锁
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }


3.2 公平性的实现      

     ReentrantLock其中有个构造方法:

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

    调用lock 时,会调用sync.lock(), 若是非公平性锁,NonfairSync 的实现如下:

final void lock() {
            // CAS设置成功 ,则获取锁
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            // 若不成功,看是否重进入
            else
                acquire(1);
        }

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

    若是公平性锁, FairSync的实现如下:

final void lock() {
            acquire(1);
        }
        // 公平性锁的实现
        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;
        }

 

// 判断当前节点是否有前驱节点
    public final boolean hasQueuedPredecessors() { 
        Node t = tail; 
        Node h = head;
        Node s;
        return h != t &&
            ((s = h.next) == null || s.thread != Thread.currentThread());
    }

 


四、读写锁的实现细节

    Mutex与ReentrantLock都是排它锁,同一时刻只允许一个线程访问。 这种对于文件读写这样的场景来说效率是低的,若能对文件的读可以多线程,写时,所有线程阻塞。读写锁ReetrantReadWriteLock实现了这点 ,其维护了一个读锁和一个写锁,通过分离读锁和写锁,使得性能有很大提升。

    使用方式如下:

static ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
    static Lock r = rwl.readLock();
    static Lock w = rwl.writeLock();

    之后读场景对r.lock() r.unlock,而对于写锁 w.lock,w.unlock。

    读写锁同样依赖AQS,通过设置同步状态实现锁。读写锁将一个同步整型变量 『按位切割』,将变量分为两个部分,高16位表示读,低16位表示写,划分如下:

    

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

    这样,假设同步状态值为S,写状态等于S&0x0000FFFF(高16位全部抹去),读状态等于S >>> 16 (无符号补0右移16位)。当写状态增加1时,等于S+1,当读状态增加1时,等于S+(1<<16) ,也就是S + 0x00010000。

    当S不等于0时,当写状态(S & 0x0000FFFF)等于0时,则 读状态大于0,即读锁已被获取。


4.1 写锁的实现

    ReentrantReadWriteLock的结构如下:

Java Lock 实现 java lock trylock_自定义_07

    Sync实现了AQS,我们先看WriteLock的获取和释放:

    writeLock.lock 调用如下方法:sync.acquire(1), 由上文可知,会调用我们再sync里重写的tryAcquire 方法:

//1.如果读锁非0 或 写锁非0且持有者是不同的线程,失败
//2.如果计数值溢出,失败
//3.非上述情况,则说明锁可被获取
protected final boolean tryAcquire(int acquires) {
            Thread current = Thread.currentThread();
            int c = getState();
            // 得到写状态
            int w = exclusiveCount(c);
            if (c != 0) {
                // (Note: if c != 0 and w == 0 then shared count != 0)
                if (w == 0 || current != getExclusiveOwnerThread())
                    return false;
                if (w + exclusiveCount(acquires) > MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");
                // Reentrant acquire
                setState(c + acquires);
                return true;
            }
            // 公平锁则判断是否有前驱,非公平直接获取
            if (writerShouldBlock() ||
                !compareAndSetState(c, c + acquires))
                return false;
            setExclusiveOwnerThread(current);
            return true;
        }

writerShouldBlock():
static final class NonfairSync extends Sync {
        final boolean writerShouldBlock() {
            return false; 
        }
}
static final class FairSync extends Sync {
        final boolean writerShouldBlock() {
            return hasQueuedPredecessors();
        }
}

    写锁的释放,会调用sync的tryRelease(int) 方法:

protected final boolean tryRelease(int releases) {
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            // 写锁-1
            int nextc = getState() - releases;
            // 看是否为0,0表示写锁释放
            boolean free = exclusiveCount(nextc) == 0;
            if (free)
                setExclusiveOwnerThread(null);
            setState(nextc);
            return free;
        }


4.2 读锁的实现

    readLock 比 之前见到的逻辑略显复杂,是因为增加了一些关于计数的功能,如下:

    在Sync类里:    

// 每个线程读锁的计数器,是threadLocal的,cache在cachedHoldCounter
        static final class HoldCounter {
            int count = 0;
            // 用id ,而不是引用,避免垃圾保留
            final long tid = getThreadId(Thread.currentThread());
        }
        // ThreadLocal的子类,为了反序列化机制,易于明确定义
        static final class ThreadLocalHoldCounter
            extends ThreadLocal<HoldCounter> {
            public HoldCounter initialValue() {
                return new HoldCounter();
            }
        }
        // 当前线程拿到的可重入读锁的数目,在构造函数和readObject里初始化。
        // 当一个线程读锁次数降到0时,删除此对象
        private transient ThreadLocalHoldCounter readHolds;

        // 最后一个成功获取readLock的线程的读锁次数
        private transient HoldCounter cachedHoldCounter;

        // firstReader是第一个获得读锁的线程,firstReaderHoldCount是此线程获得读锁的次数
        private transient Thread firstReader = null;
        private transient int firstReaderHoldCount;

        Sync() {
            readHolds = new ThreadLocalHoldCounter();
            setState(getState()); // ensures visibility of readHolds
        }

readLock 的lock方法,调用了sync.acquireShared(1) ,其调用我们重写的tryAcquireShared方法:

// 1.如果写锁被其他线程获取,则失败
// 2.若写锁没被占,线程是可以拿状态的,这样取决于是否是公平锁。若不是,尝试CAS更新状态以及更新计数,
// 注意此步骤不检查可重入的获取,延期到full version,避免大多数是非重入锁,而导致的消耗
// 3.如果第二步失败,重试。
protected final int tryAcquireShared(int unused) {
            Thread current = Thread.currentThread();
            int c = getState();
            // 写锁检查
            if (exclusiveCount(c) != 0 &&
                getExclusiveOwnerThread() != current)
                return -1;
            int r = sharedCount(c);
            // 公平锁则检查前驱节点,非公平锁则判断第一个节点是否是写节点,若是,则阻塞,来避免写 无限等待
            if (!readerShouldBlock() &&
                r < MAX_COUNT &&
                compareAndSetState(c, c + SHARED_UNIT)) {
                // 第一个锁节点
                if (r == 0) {
                    firstReader = current;
                    firstReaderHoldCount = 1;
                // 第一个锁节点重进入
                } else if (firstReader == current) {
                    firstReaderHoldCount++;
                } else {
                    // 锁计数++
                    HoldCounter rh = cachedHoldCounter;
                    if (rh == null || rh.tid != getThreadId(current))
                        cachedHoldCounter = rh = readHolds.get();
                    else if (rh.count == 0)
                        readHolds.set(rh);
                    rh.count++;
                }
                return 1;
            }

            return fullTryAcquireShared(current);
        }
    static final class NonfairSync extends Sync {
        final boolean readerShouldBlock() {
            return apparentlyFirstQueuedIsExclusive();
        }
    }
    final boolean apparentlyFirstQueuedIsExclusive() {
        Node h, s;
        return (h = head) != null &&
            (s = h.next)  != null &&
            !s.isShared()         &&
            s.thread != null;
    }

    调用tryAcquireShared 完整版:         

//full version的读获取锁,处理CAS失败与重复读
        final int fullTryAcquireShared(Thread current) {
            // 代码比tryAcquireShared要重,但是使得tryAcquiredShared方法简单化,避免重试,延后读hold counts
            HoldCounter rh = null;
            for (;;) {
                int c = getState();
                if (exclusiveCount(c) != 0) {
                    if (getExclusiveOwnerThread() != current)
                        return -1;
                    // else we hold the exclusive lock; blocking here
                    // would cause deadlock.
                } else if (readerShouldBlock()) {
                    // 确认我们不是重进入获取锁
                    if (firstReader == current) {
                        // assert firstReaderHoldCount > 0;
                    // 不是重进入
                    } else {
                        if (rh == null) {
                            rh = cachedHoldCounter;
                            if (rh == null || rh.tid != getThreadId(current)) {
                                rh = readHolds.get();
                                if (rh.count == 0)
                                    readHolds.remove();
                            }
                        }
                        if (rh.count == 0)
                            return -1;
                    }
                }
                if (sharedCount(c) == MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");
                if (compareAndSetState(c, c + SHARED_UNIT)) {
                    // 第一个读锁
                    if (sharedCount(c) == 0) {
                        firstReader = current;
                        firstReaderHoldCount = 1;
                    // 当前读锁重进入
                    } else if (firstReader == current) {
                        firstReaderHoldCount++;
                    } else {
                        if (rh == null)
                            rh = cachedHoldCounter;
                        if (rh == null || rh.tid != getThreadId(current))
                            rh = readHolds.get();
                        else if (rh.count == 0)
                            readHolds.set(rh);
                        rh.count++;
                        cachedHoldCounter = rh; // cache for release
                    }
                    return 1;
                }
            }
        }

    readLock的unlock方法,调用了sync.releaseShared(1),其调用了tryReleaseShared(1)方法:

protected final boolean tryReleaseShared(int unused) {
            Thread current = Thread.currentThread();
            // 若当前线程是firstReader,若计数为1 ,则firstReader至为空
            if (firstReader == current) {
                // assert firstReaderHoldCount > 0;
                if (firstReaderHoldCount == 1)
                    firstReader = null;
                else
                    firstReaderHoldCount--;
            } else {
                // 看是否是最新获取锁的线程
                HoldCounter rh = cachedHoldCounter;
                if (rh == null || rh.tid != getThreadId(current))
                    rh = readHolds.get();
                int count = rh.count;
                if (count <= 1) {
                    readHolds.remove();
                    if (count <= 0)
                        throw unmatchedUnlockException();
                }
                --rh.count;
            }
            for (;;) {
                int c = getState();
                int nextc = c - SHARED_UNIT;
                if (compareAndSetState(c, nextc))
                    // 释放读锁对所有的readers没有影响,但是会允许等待的写线程优先处理
                    // 如果读锁与写锁都存在
                    return nextc == 0;
            }
        }

    至此,JUC里中两种主要的锁的实现,和锁的原理已解读完毕。