ReentrantReadWriteLock(可重入读写锁)

本文详细介绍了JavaReentrantReadWriteLock的实现,包括读锁和写锁的获取、释放机制,以及公平锁和非公平锁的区别,重点围绕AQS同步器和ThreadLocal在锁管理中的应用。
摘要由CSDN通过智能技术生成

基于AQS的互斥锁(写)和共享锁(读)实现的可重入读写锁

属性

public interface ReadWriteLock {
    Lock readLock();
    Lock writeLock();
}

public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable {
    private static final long serialVersionUID = -6992448646407690164L;
    //读锁
    private final ReentrantReadWriteLock.ReadLock readerLock;
	//写锁
    private final ReentrantReadWriteLock.WriteLock writerLock;
    //同步器
    final Sync sync;
	//默认创建非公平锁同步器
    public ReentrantReadWriteLock() {
        this(false);
    }
	
    public ReentrantReadWriteLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
        readerLock = new ReadLock(this);
        writerLock = new WriteLock(this);
    }

    public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; }
    public ReentrantReadWriteLock.ReadLock  readLock()  { return readerLock; }
}

Sync同步器

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

    /*
     * Read vs write count extraction constants and functions.
     * Lock state is logically divided into two unsigned shorts:
     * The lower one representing the exclusive (writer) lock hold count,
     * and the upper the shared (reader) hold count.
     */
	//将32位int拆分成2部分,高16位表示读锁线程数,低16位表示写锁线程数
    static final int SHARED_SHIFT   = 16;
    static final int SHARED_UNIT    = (1 << SHARED_SHIFT);
    static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;
    // 用于获取低16位值的掩码值
    static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
    
    //获取当前持有读锁的线程/资源数
    static int sharedCount(int c)    { return c >>> SHARED_SHIFT; }

    //获取当前持有写锁的线程/资源数
    static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }

    //单个线程读锁重入的次数,通过ThreadLocal来维护这个计数器
    static final class HoldCounter {
        int count = 0;
      
        final long tid = getThreadId(Thread.currentThread());
    }

    static final class ThreadLocalHoldCounter
        extends ThreadLocal<HoldCounter> {
        public HoldCounter initialValue() {
            return new HoldCounter();
        }
    }
	//创建ThreadLocal
    private transient ThreadLocalHoldCounter readHolds;

    // 缓存最后一个线程获取的读锁数量
    private transient HoldCounter cachedHoldCounter;

    /**
     * firstReader is the first thread to have acquired the read lock.
     * firstReaderHoldCount is firstReader's hold count.
     *
     * <p>More precisely, firstReader is the unique thread that last
     * changed the shared count from 0 to 1, and has not released the
     * read lock since then; null if there is no such thread.
     *
     * <p>Cannot cause garbage retention unless the thread terminated
     * without relinquishing its read locks, since tryReleaseShared
     * sets it to null.
     *
     * <p>Accessed via a benign data race; relies on the memory
     * model's out-of-thin-air guarantees for references.
     *
     * <p>This allows tracking of read holds for uncontended read
     * locks to be very cheap.
     */
    private transient Thread firstReader = null;
    private transient int firstReaderHoldCount;

    Sync() {
        //初始化ThreadLocal对象
        readHolds = new ThreadLocalHoldCounter();
        //使用state变量的volatile,用于保证可见性
        setState(getState()); 
    }

    abstract boolean readerShouldBlock();

    abstract boolean writerShouldBlock();

    private IllegalMonitorStateException unmatchedUnlockException() {
        return new IllegalMonitorStateException(
            "attempt to unlock read lock, not locked by current thread");
    }

    /**
     * Performs tryLock for write, enabling barging in both modes.
     * This is identical in effect to tryAcquire except for lack
     * of calls to writerShouldBlock.
     */
    final boolean tryWriteLock() {
        Thread current = Thread.currentThread();
        int c = getState();
        if (c != 0) {
            int w = exclusiveCount(c);
            if (w == 0 || current != getExclusiveOwnerThread())
                return false;
            if (w == MAX_COUNT)
                throw new Error("Maximum lock count exceeded");
        }
        if (!compareAndSetState(c, c + 1))
            return false;
        setExclusiveOwnerThread(current);
        return true;
    }

    /**
     * Performs tryLock for read, enabling barging in both modes.
     * This is identical in effect to tryAcquireShared except for
     * lack of calls to readerShouldBlock.
     */
    final boolean tryReadLock() {
        Thread current = Thread.currentThread();
        for (;;) {
            int c = getState();
            if (exclusiveCount(c) != 0 &&
                getExclusiveOwnerThread() != current)
                return false;
            int r = sharedCount(c);
            if (r == MAX_COUNT)
                throw new Error("Maximum lock count exceeded");
            if (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 true;
            }
        }
    }

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

    // Methods relayed to outer class

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

    final Thread getOwner() {
        // Must read state before owner to ensure memory consistency
        return ((exclusiveCount(getState()) == 0) ?
                null :
                getExclusiveOwnerThread());
    }

    final int getReadLockCount() {
        return sharedCount(getState());
    }

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

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

    final int getReadHoldCount() {
        if (getReadLockCount() == 0)
            return 0;

        Thread current = Thread.currentThread();
        if (firstReader == current)
            return firstReaderHoldCount;

        HoldCounter rh = cachedHoldCounter;
        if (rh != null && rh.tid == getThreadId(current))
            return rh.count;

        int count = readHolds.get().count;
        if (count == 0) readHolds.remove();
        return count;
    }

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

    final int getCount() { return getState(); }
}
tryAcquire(写锁获取子类实现)
protected final boolean tryAcquire(int acquires) {
    //获取当前线程
    Thread current = Thread.currentThread();
    int c = getState();
    //获取当前持有写锁的线程数量
    int w = exclusiveCount(c);
    if (c != 0) {  //已经有线程获取锁,但此时不区分读/写锁,在下一步w == 0时区分
        if (w == 0 //没有线程获取写锁,但是有线程获取到读锁了
            || current != getExclusiveOwnerThread())  //如果有,判断获取写锁的线程是不是当前线程
            //获取锁失败,执行AQS排队
            return false;
        //写锁重入,最大值不得大于MAX_COUNT
        if (w + exclusiveCount(acquires) > MAX_COUNT)
            throw new Error("Maximum lock count exceeded");
        // 可重入,更新state值
        setState(c + acquires);
        return true;
    }
    //既没有读锁,也没有写锁
    if (writerShouldBlock() ||  //判断是否当前线程获取写锁(由子类(公平/非公平方式)实现)
        !compareAndSetState(c, c + acquires))  //CAS抢写锁,失败后走AQS排队
        return false;
    setExclusiveOwnerThread(current);  //获取写锁成功,将当前线程标识为获取互斥锁的线程对象
    return true;
}
writerShouldBlock
//非公平锁实现
static final class NonfairSync extends Sync {
    private static final long serialVersionUID = -8159625535654395037L;
    final boolean writerShouldBlock() {
        return false; // 非公平锁实现方式,写锁总是去抢,抢完再说
    }
    final boolean readerShouldBlock() {
        return apparentlyFirstQueuedIsExclusive();
    }
}

//公平锁实现
static final class FairSync extends Sync {
    private static final long serialVersionUID = -2274990926593161451L;
    final boolean writerShouldBlock() {
        return hasQueuedPredecessors();  //需要先判断队列中有没有人排队
    }
    final boolean readerShouldBlock() {
        return hasQueuedPredecessors();
    }
}

tryRelease(释放写锁)
//该方法也是线程安全(因为锁还没释放完成)
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(读锁获取)
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)  //获取写锁的线程不是当前线程,返回-1,告知AQS获取读锁失败
        return -1;
    // 获取读锁的持有数
    int r = sharedCount(c);
    if (!readerShouldBlock() &&  //子类实现,判定当前获取读锁的线程是否应该被阻塞
        r < MAX_COUNT &&  //线程持有数必须小于MAX_COUNT
        compareAndSetState(c, c + SHARED_UNIT)) { //CAS增加state的高16位的读锁持有数
        //计数为0,表示当前线程就是第一个获取读锁的线程
        if (r == 0) {
            //设置第1个获取读锁的线程和该线程持有state数(重入)
            firstReader = current;
            firstReaderHoldCount = 1;
        } else if (firstReader == current) {
            //当前获取读锁的线程就是第一个线程,也就是锁重入,直接加1计数位
            firstReaderHoldCount++;
        } else {
            //当前线程不是第一个读线程,此时将其获取读锁的次数保存在ThreadLocal中
            HoldCounter rh = cachedHoldCounter;
            if (rh == null || rh.tid != getThreadId(current))
                 /*这里要说明一下,当rh == null时,其实整套代码看下来,没有任何地方有对rh的创建和初始化,实际上				 			  *readHolds.get()这个方法默认会创建一个空值的rh对象,详细实现可以看ThreadLocal.get()源码
                  */
                cachedHoldCounter = rh = readHolds.get();
            else if (rh.count == 0)
                readHolds.set(rh);
            rh.count++;
        }
        return 1;
    }
    //这个地方需要说明一下,看fullTryAcquireShared方法实际跟上面做的事情是一样的,那为什么还要做两次呢,实际上是对性能做的优化,就是把一些常见的场景前置
    return fullTryAcquireShared(current);
}
fullTryAcquireShared
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(释放共享锁)
protected final boolean tryReleaseShared(int unused) {
    Thread current = Thread.currentThread();
    //当前线程就是第1个获取读锁的线程
    if (firstReader == current) {
        //如果为1,证明没有锁重入,则直接释放firstReader
        if (firstReaderHoldCount == 1)
            firstReader = null;
        else
            firstReaderHoldCount--;  //有锁重入,做--处理
    } else {
        //不是第1个获取读锁线程,从ThreadLocal中获取当前线程持有的数量
        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;
        //释放高16位数
        if (compareAndSetState(c, nextc))
            //释放成功,返回true后,通知AQS唤醒阻塞队列节点
            return nextc == 0;
    }
}
readerShouldBlock和writerShouldBlock

读/写锁是否应该阻塞分非公平和公平两种实现方式

//非公平实现
static final class NonfairSync extends Sync {
    private static final long serialVersionUID = -8159625535654395037L;
    final boolean writerShouldBlock() {
        return false; // 非公平锁实现方式,写锁总是去抢,抢完再说
    }
    final boolean readerShouldBlock() {
        return apparentlyFirstQueuedIsExclusive();
    }
}
//第1个排队的线程节点是互斥的
final boolean apparentlyFirstQueuedIsExclusive() {
    Node h, s;
    return (h = head) != null &&
        (s = h.next)  != null &&
        !s.isShared()         &&
        s.thread != null;
}

//公平实现
static final class FairSync extends Sync {
    private static final long serialVersionUID = -2274990926593161451L;
    final boolean writerShouldBlock() {
        return hasQueuedPredecessors(); // //需要先判断队列中有没有人排队
    }
    final boolean readerShouldBlock() {
        return hasQueuedPredecessors();
    }
}
//这个方法是AQS中实现的,判断阻塞队列中是否还有前驱节点,只要有那么就排队去,不管读/写锁
public final boolean hasQueuedPredecessors() {
    Node t = tail; 
    Node h = head;
    Node s;
    return h != t &&
        ((s = h.next) == null || s.thread != Thread.currentThread());
}

WriteLock写锁

public static class WriteLock implements Lock, java.io.Serializable {
    private static final long serialVersionUID = -4992448646407690164L;
    private final Sync sync;
	//sync同步器由ReentrantReadWriteLock决定并传入
    protected WriteLock(ReentrantReadWriteLock lock) {
        sync = lock.sync;
    }
   	//获取锁,调用ReentrantReadWriteLock中同步器的acquire实现方法
    public void lock() {
        sync.acquire(1);
    }
   //可响应中断的锁方法
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }
    //尝试获取锁,如果获取不到,立马返回,不做排队
    public boolean tryLock( ) {
        return sync.tryWriteLock();
    }
    //带超时时间的尝试获取锁操作
    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 boolean isHeldByCurrentThread() {
        return sync.isHeldExclusively();
    }

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

多栖码农

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值