读写锁-ReadWriteLock
作者:互联网
读写锁
一.读写状态的设计
(ReadWriteLock是个接口,ReentrantReadWriteLock是该接口的具体实现类)
回想之前ReentrantLock重入锁中,同步状态state表示锁被一个线程重复获取的次数。
读写锁的同步状态state表示维护多个读线程和一个写线程的状态,这个同步状态的高16位表示读状态,低16位表示写状态
假设当前同步状态值为S,写状态等于S & 0x0000FFFF(将高16位全部抹去),读状态等于S>>>16(无符号补0右移16位)。当写状态增加1时,等于S+1(低16位的),当读状态增加1时,等于S+(1<<16), 添加到高16位中。
二.写锁的获取和释放
写锁是一个支持重进入的排它锁。如果已经获取了写锁的线程再次去获取写锁,则增加写状态。
在下面两种情况下线程进入等待状态:
- 当前线程在获取写锁时,读锁已经被获取(读状态不为0,写状态为0);
- 或者该线程不是已经获取写锁的线程;
写锁的获取:
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");
// Reentrant acquire
setState(c + acquires);
return true;
}
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))
return false;
setExclusiveOwnerThread(current);
return true;
}
分析:
如果存在读锁,则写锁不能被获取,原因在于:读写锁要保证写锁的操作对读锁可见,如果允许读锁在已被获取的情况下对写锁的获取,那么正在运行的其他线程就无法感知到当前写线程的操作(数据没有使用voliate修饰)。因此,只有等待其他线程都释放了读锁,写锁才能被当前线程获取,而写锁一旦被获取,则其他线程的后续访问均被阻塞。
写锁的释放:
写锁的释放与ReentrantLock的释放过程类似,每次释放均减少写状态,当写状态为0时表示写锁已被释放,从而等待的读写线程能够继续访问读写锁,同时前次写线程的修改对后续线程可见 (数据未使用volatile修饰时的保证)。
三.读锁的获取与释放
读锁是一个支持重进入的共享锁。它能被多个线程同时访问。
获取锁时(tryAcquireShared方法):如果当前线程已经获取过了则增加读状态(是使用CAS操作线程安全的,因为是可能同时存在多个线程进入读操作),如果其他线程获取了写锁,则当前线程进入等待状态。
读状态是所有线程获取读锁次数的总和,而每个线程各自获取读锁的次数只能选择保存在ThreadLocal中,由线程自身维护,例如getReadHoldCount()方法返回当前线程获取读锁的次数。
释放锁(tryReleaseShared方法): 每次释放均减少读状态(线程安全的,可能同时有多个线程释放读锁),减少的值是(1<<16), 高16位减少1.
四.锁降级
锁降级是指写锁降级成为读锁。过程为:当前线程持有写锁,再获取到读锁,随后释放写锁的过程;如果是当前线程拥有写锁,然后将其释放,最后再获取读锁,这种分段完成的就不是锁降级。
一个问题:锁降级中的获取读锁是否必要吗?
答案:为了保证数据的可见性,如果当前线程不获取读锁而是直接释放锁,假设另外一个线程(假设为线程T)获取了写锁并修改了数据,那么当前线程无法感知到线程T的数据更新 (数据没有使用voliate修饰)。
如果当前线程获取读锁,即遵循锁降级的步骤,则线程T将会被阻塞,直到当前线程使用完数据并释放读锁之后,线程T才能获取写锁进行数据更新(此时的写操作对其他线程可见)。
ReentrantReadWriteLock不支持锁升级(先持有读锁,然后获取写锁,最后释放读锁的过程):目的也是保证数据可见性,如果读锁已被多个线程获取,其中任意线程成功获取了写锁并更新了数据,则其更新对其他获取了读锁的线程是不可见的(数据未使用volatile修饰)。
标签:状态,释放,写锁,ReadWriteLock,读写,获取,读锁,线程 来源: https://blog.csdn.net/jawnhaha/article/details/114702666