ReentrantReadWriteLock使用

ReentrantReadWriteLock

下图来源《Java并发编程的艺术》一书

锁在同一时刻只允许一个线程进行访问,而读写锁在同一时刻可以允许多个读线程访问,但是在写线程访问时,所有的读
线程和其他写线程均被阻塞。读写锁维护了一对锁,一个读锁和一个写锁,通过分离读锁和写锁,使得并发性相比一般的排他锁有了很大提升。一般情况下,读写锁的性能都会比排它锁好,因为大多数场景读是多于写的。在读多于写
的情况下,读写锁能够提供比排它锁更好的并发性和吞吐量。Java并发包提供读写锁的实现是
ReentrantReadWriteLock,它提供的特性如表5-8所示。

ReentrantReadWriteLock使用_第1张图片

ReentrantReadWriteLock使用_第2张图片

简单的示例代码
package reentrant;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @author sun
 * @date 2019/8/20
 */
public class ReentrantReadWriteLockDemo {
    static Map datas = new HashMap();
    static ReentrantReadWriteLock lock =  new ReentrantReadWriteLock();
    static Lock r = lock.readLock();
    static Lock w = lock.writeLock();

    public static void main(String[] args) {
        new Thread(){
            @Override
            public void run() {
                for (int i=0;i<10000;i++)
                    setData(i+"",i+"");
            }
        }.start();
        new Thread(){
            @Override
            public void run() {
                for (int i=0;i<10000;i++)
                   getData(i+"");
            }
        }.start();
    }
    public static void setData(String name ,String value){
        try{
            w.lock();
            datas.put(name,value);
            System.out.println("写入的值是:"+value);
        }finally {
            w.unlock();
        }
    }
    public static void getData(String name){

        try{

            r.lock();
            System.out.println("读取的值是:"+ datas.get(name));
        }finally {
            r.unlock();
        }
    }
}

 

ReentrantReadWriteLock的实现主要包括:读写状态的设计、写锁的获取与释放、读锁的获取与释放以及锁降,ReentrantReadWriteLock与其他锁不同他包含两个锁,一个读锁一个写锁通过一个整型变量来维护,高16位表示读锁,低16位表示写锁

ReentrantReadWriteLock使用_第3张图片

 

我们自先来看写锁源码

write.lock()

调用

和reentrantlock类似最后调用的是静态内部类Sync的tryAcquire方法

protected final boolean tryAcquire(int acquires) {
    /*
     * Walkthrough:
     * 1. If read count nonzero or write count nonzero
     *    and owner is a different thread, fail.
     * 2. If count would saturate, fail. (This can only
     *    happen if count is already nonzero.)
     * 3. Otherwise, this thread is eligible for lock if
     *    it is either a reentrant acquire or
     *    queue policy allows it. If so, update state
     *    and set owner.
     */
    Thread current = Thread.currentThread();
    int c = getState();
    int w = exclusiveCount(c);//判断是否为写锁,写锁为独占锁,这里清掉高16位的值,如果w=0表示被读锁占有
    if (c != 0) {//c不为0表明被读锁占有
        // (Note: if c != 0 and w == 0 then shared count != 0)
        if (w == 0 || current != getExclusiveOwnerThread())//如果写锁状态为0或者不是当前线程占有写锁,则返回失败
            return false;
       if (w + exclusiveCount(acquires) > MAX_COUNT) //MAX_COUNT该值为65535 大于这个值表示写锁已经超过最大获取次数
            throw new Error("Maximum lock count exceeded");
        // Reentrant acquire
        setState(c + acquires);//更新AQS中state状态
        return true;
    }

    if (writerShouldBlock() ||
        !compareAndSetState(c, c + acquires))
        return false;
    setExclusiveOwnerThread(current);
    return true;
}

写锁的释放

最终调用AQS中的

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

再调用Sync中的

ReentrantReadWriteLock使用_第4张图片

读锁的获取

调用Sync内部类中的

再调用AQS中的

ReentrantReadWriteLock使用_第5张图片

调用Sync中的

protected final int tryAcquireShared(int unused) {
    /*
     * Walkthrough:
     * 1. If write lock held by another thread, fail.
     * 2. Otherwise, this thread is eligible for
     *    lock wrt state, so ask if it should block
     *    because of queue policy. If not, try
     *    to grant by CASing state and updating count.
     *    Note that step does not check for reentrant
     *    acquires, which is postponed to full version
     *    to avoid having to check hold count in
     *    the more typical non-reentrant case.
     * 3. If step 2 fails either because thread
     *    apparently not eligible or CAS fails or count
     *    saturated, chain to version with full retry loop.
     */
    Thread current = Thread.currentThread();
    int c = getState();
    if (exclusiveCount(c) != 0 &&
        getExclusiveOwnerThread() != current)//是写锁或者当前线程不是获得锁的线程
        return -1;
    int r = sharedCount(c);//将低16位清0,剩下的就是高16位
    if (!readerShouldBlock() &&//读线程是否应该被阻塞、并且小于最大值、并且比较设置成功
        r < MAX_COUNT &&
        compareAndSetState(c, c + SHARED_UNIT)) {
        if (r == 0) {
            firstReader = current;//设置第一个读线程
            firstReaderHoldCount = 1;
        } else if (firstReader == current) {//第一个读线程重入
            firstReaderHoldCount++;
        } else {// 读锁数量不为0并且不为当前线程
            HoldCounter rh = cachedHoldCounter;//获取本地计数器
          if (rh == null || rh.tid != getThreadId(current))// 计数器为空或者计数器的tid不为当前正在运行的线程的tid
                cachedHoldCounter = rh = readHolds.get();
            else if (rh.count == 0)
                readHolds.set(rh);
            rh.count++;
        }
        return 1;
    }
    return fullTryAcquireShared(current);
}
final int fullTryAcquireShared(Thread current) {//该方法与tryAcquireShared类似
    /*
     * This code is in part redundant with that in
     * tryAcquireShared but is simpler overall by not
     * complicating tryAcquireShared with interactions between
     * retries and lazily reading 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()) {
            // Make sure we're not acquiring read lock reentrantly
            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;
        }
    }
}

 

读锁的释放

protected final boolean tryReleaseShared(int unused) {
    Thread current = Thread.currentThread();
    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))
            // Releasing the read lock has no effect on readers,
            // but it may allow waiting writers to proceed if
            // both read and write locks are now free.
            return nextc == 0;
    }
}

 

 

ReentrantReadWriteLock使用_第6张图片

锁降级

ReentrantReadWriteLock使用_第7张图片

 

ReentrantReadWriteLock使用_第8张图片

有写得更好的https://www.cnblogs.com/xiaoxi/p/9140541.html

你可能感兴趣的:(java,concurrency)