JUC ReentrantLock与ReentrantReadWriteLock

重入锁

JUC中的重入锁ReentrantLock建立在AQS之上,其内部类Sync继承AQS,并实现其抽象方法,以完成可重入特性。实现可重入锁的需要注意的是:线程已经成功获取到锁才可重入;线程重入n次之后,历经释放n次,其他线程可以请求并获取到锁。在JUC重入锁的设计中提供了公平与非公平锁两种实现。其区别主要在于获取锁的顺序(公平锁有序),由于公平锁的有序性可能引起上下文切换,所以公平锁的吞吐性能表现不佳。
ReentranLock里面的功能均是委托给Sync实现,而Sync内部的lock()抽象方法由子类实现,下面给出非公平锁lock()方法的实现

final void lock() {
    if (compareAndSetState(0, 1))//CAS设置状态
        setExclusiveOwnerThread(Thread.currentThread());
    else//获取锁失败
        acquire(1);
}

在该lock()方法中,首先快速CAS设置状态值(0时无锁状态),获取失败则调用AQS的acquire(int arg)方法,非公平锁的抽象方法tryAcquire(int arg),实际是对Sync中nonfairTryAcquire(int 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)
            throw new Error("Maximum lock count exceeded");
        setState(nextc);//设置状态
        return true;
    }
    return false;
}

公平锁的获取则是直接调用AQS中的模板方法acquire(int arg);

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;
    }
}

对比公平锁与非公平锁的tryAcquire抽象方法的实现,公平锁在获取锁时必须为同步队列中的第一个节点,其他细节实现基本一致
在ReentranLock锁的释放中,委托给Sync的relase(int arg)执行,同时Sync内部实现了AQS的抽象方法tryRelease(int arg)

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;
}

读写锁

读写锁ReentrantReadWriteLock,将锁包装为读锁与写锁,允许多个读锁线程同时访问,但是在写线程时,其他线程的写与读均被阻塞。通过分离读锁与写锁,使得锁的性能大大提升。其特性如下:
《JUC ReentrantLock与ReentrantReadWriteLock》
读写锁内部与重入锁类似包含内部类Sync继承至AQS并实现相应的抽象方法。在该Sync中volatile的状态变量维护需要维护读和写两种锁的状态,状态变量采用低16位维护写锁状态,高16位维护读锁状态。因此写状态为 (S&0x0000FFFF),读状态为(S>>16)。
1、关于公平性
在读写锁的设计中Sync定义了抽象方法
1) final boolean writerShouldBlock();
2) final boolean readerShouldBlock();
NonfairSync与FairSync继承Sync并实现上述抽象方法以实现公平与非公平获取功能
2、读与写锁
读锁ReadLock(共享锁)的lock()获取委托sync.acquireShared(1)实现,unlock()释放委托给sync.releaseShared(1)实现
写锁WriteLock(互斥锁)的lock()委托sync.acquire(1)实现,unlock()释放委托给sync.release(1)实现
此外读锁与写锁的超时,中断响应等也是委托给sync实现
最后来看看,Sync中关于AQS抽象方法的具体实现。
写锁获取依赖的抽象方法tryAcquire(int acquires)

protected final boolean tryAcquire(int acquires) {
    Thread current = Thread.currentThread();
    int c = getState();
    int w = exclusiveCount(c);//写锁状态
    if (c != 0) {//有线程获取到锁
        //存在读锁且获取读锁的线程不为当前线程,写锁获取失败
        if (w == 0 || current != getExclusiveOwnerThread())
            return false;
        if (w + exclusiveCount(acquires) > MAX_COUNT)
            throw new Error("Maximum lock count exceeded");
        setState(c + acquires);
        return true;
    }
    if (writerShouldBlock() ||
        !compareAndSetState(c, c + acquires))
        return false;
    setExclusiveOwnerThread(current);//设置线程独占
    return true;
}

写锁释放依赖的抽象方法tryRelease(int acquires)

protected final boolean tryRelease(int releases) {
    if (!isHeldExclusively())//非独占,异常
        throw new IllegalMonitorStateException();
    int nextc = getState() - releases;
    boolean free = exclusiveCount(nextc) == 0;//重入写锁完成释放
    if (free)
        setExclusiveOwnerThread(null);
    setState(nextc);
    return free;
}

读锁的获取依赖抽象方法tryAcquireShared(int acquires)

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);
}

当获取读锁不满足公平性条件或持有线程数不满足时,执行fullTryAcquireShared(current)

final int fullTryAcquireShared(Thread current) {
    HoldCounter rh = null;
    for (;;) {
        int c = getState();
        if (exclusiveCount(c) != 0) {//存在写锁
            if (getExclusiveOwnerThread() != current)//写锁不为当前线程
                return -1;
        } 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;
        }
    }
}

读锁的释放依赖的抽象方法tryReleaseShared(int acquires)

protected final boolean tryReleaseShared(int unused) {
    Thread current = Thread.currentThread();
    if (firstReader == current) {//当前线程为第一个读锁获取线程
        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))//CAS设置锁状态值
            return nextc == 0;
    }
}
    原文作者:JUC
    原文地址: https://blog.csdn.net/Song_Russell/article/details/79428445
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞