Java—多线程8—ReentranReadWriteLock可重入读写锁

Java—多线程8 ReentranReadWriteLock可重入读写锁

读写者模型

读写锁允许同一时刻被多个读线程访问,但在写线程访问时,所有的读线程以及其他写线程均会被阻塞。

写锁是一个独占锁:

读锁!= 无锁:

如果 读锁==无锁,当有写线程时,读线程不会停止。

如果 读锁!=写锁 当有写线程访问时,读线程会被停止

写锁—独占锁

1.写锁的获取:

 protected final boolean tryAcquire(int acquires) {
     //1.当前的读写锁没有被任何读线程获取,并且写锁要么是0要么被自己拿着(可重入)
   
            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;
    		 //此时读写状态为0,写锁可以正常获取到同步状态
     		//当前线程置为写锁线程
            setExclusiveOwnerThread(current);
            return true;
        }
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;//左移16位
static final int SHARED_SHIFT   = 16;

如何区分读状态和写状态

同步状态的高16位表示 读锁的次数;同步状态的低16位表示 写锁的次数

2.写锁的释放

 protected final boolean tryRelease(int releases) {
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
     		//同步状态减去写锁状态
            int nextc = getState() - releases;
     		//当前写锁状态是否为0,为0则释放写锁
            boolean free = exclusiveCount(nextc) == 0;
            if (free)
                setExclusiveOwnerThread(null);
     		//不为0则更新同步状态
            setState(nextc);
            return free;
        }

读锁—共享锁(一般与独占锁搭配使用实现读写者模型)

获取:只要当前没有写线程获取到写锁,并且读锁的获取次数不超过最大值,读锁就可以获取成功。

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

释放:自旋,将同步状态减去读状态即可,如果减到0,就可以释放锁

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))
            return nextc == 0;
    }
}

应用场景:所有缓存的实现必有读写锁,缓存一定是个共享资源,

写锁的降级

写锁可以降级成写锁,写锁不能降级成读锁。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值