读写锁ReentrantReadWriteLock类
ReentrantReadWriteLock是做什么作用的呢?
我们知道,多线程操作同一数据时,如果不加锁,会产生冲突。其实对数据的操作就是两种,读和写。那么什么情况下会发生冲突呢?
- 两个线程同时写,会产生冲突。
- 一个线程写,一个线程读,也会产生冲突,因为读取的可能不是最新写的内容。
- 两个线程同时读, 不会产生冲突。
这样我们就知道ReentrantReadWriteLock作用了,它有两个锁,读锁(共享锁)和写锁(独占锁)。分为下列情况:
- 当前已经有线程获取读锁了,这个时候有另一个线程准备获取读锁,那么可以获取成功。如果有另一个线程获取写锁,那么获取失败,必须等待读锁释放,才有机会获取写锁。
- 当前已经有线程获取写锁了,那么另一个线程不管获取读锁还是写锁,都失败,必须等待写锁释放。
public interface ReadWriteLock {
/**
* 返回读锁
*/
Lock readLock();
/**
* 返回写锁
*/
Lock writeLock();
}
public class ReentrantReadWriteLock
implements ReadWriteLock, java.io.Serializable {}
ReentrantReadWriteLock实现ReadWriteLock接口和Serializable序列化接口。
ReentrantReadWriteLock并没有实现Lock接口,所以它本身不能调用lock方法给线程加锁,只能readLock和writeLock返回Lock锁进行操作。
成员属性和构造函数
成员属性
/** 读锁(共享锁) */
private final ReadLock readerLock;
/** 写锁(独占锁) */
private final WriteLock writerLock;
/** 使用sync来实现加锁操作 */
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);
}
在构造函数中,初始化三个成员变量。
Sync内部类
它用了很巧妙的方法,int整形变量的高16位表示读锁(共享锁)次数,低16位表示写锁(独占锁)的次数。
所以要获取写锁(独占锁)的次数就是将state & 65535(0b011..1),这样高16位的数据剔除了,因为都是变成0了。要获取读锁(共享锁)次数就更简单了,state >>> 16右移16位,低16位的数据都被清除了。
成员变量
// 创建一个线程本地变量,用来存储HoldCounter对象
private transient ThreadLocalHoldCounter readHolds;
// 用来缓存最近一次获取读锁线程的HoldCounter对象
private transient HoldCounter cachedHoldCounter;
// 表示第一个获取读锁的线程
private transient Thread firstReader = null;
// 表示第一个获取读锁的线程获取读锁的次数
private transient int firstReaderHoldCount;
// 记录线程获取读锁的次数count,和判断是不是该线程的tid标识
static final class HoldCounter {
// 表示线程获取读锁的次数
int count = 0;
// 得到线程的tid,没有使用Thread.currentThread().tid的方式,
// 是为了防止产生依赖,导致垃圾回收器不能回收线程对象
final long tid = getThreadId(Thread.currentThread());
}
tryAcquire方法获取写锁(独占锁)
protected final boolean tryAcquire(int acquires) {
Thread current = Thread.currentThread();
// 获取当前状态state
int c = getState();
// 得到当前写锁(即独占锁)被获取的次数
int w = exclusiveCount(c);
// c != 0表示读锁或者写锁已经被获取了
if (c != 0) {
// 1. w == 0表示写锁(即独占锁)没有被获取,但是c != 0,表示一定有读锁(共享锁)被获取了,
// 这个时候不能获取写锁(即独占锁),所以返回false
// 2. 持有写锁的线程不是当前线程,那么当前线程也不能获取写锁(即独占锁,所以返回false
if (w == 0 || current != getExclusiveOwnerThread())
return false;
// 获取写锁次数超出上限,因为高16位是用来储存读锁,所以获取写锁次数不能超过65535(MAX_COUNT)
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// 持有写锁的线程再次获取写锁
setState(c + acquires);
return true;
}
// writerShouldBlock()返回true,或者设置state状态失败,表示获取写锁失败
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))
return false;
setExclusiveOwnerThread(current);
return true;
}
- 如果c != 0表示有读锁或者写锁已经被获取了。如果是读锁被获取了(即w == 0),这个时候是不能获取写锁的,返回false,如果是写锁被获取了,那么就要判断获取写锁的线程是不是当前线程,是的话,能重复获取写锁。
- 如果c==0,表示没有一个线程获取任何锁(包括读锁和写锁),那么就调用writerShouldBlock和compareAndSetState方法,看当前线程能否获取锁。
tryWriteLock方法获取写锁(独占锁)
final boolean tryWriteLock() {
Thread current = Thread.currentThread();
// 获取当前状态state
int c = getState();
// c != 0表示读锁或者写锁已经被获取了
if (c != 0) {
// 写锁(即独占锁)被获取的次数
int w = exclusiveCount(c);
// 1. w == 0表示写锁(即独占锁)没有被获取,但是c != 0,表示一定有读锁(共享锁)被获取了,
// 这个时候不能获取写锁(即独占锁),所以返回false
// 2. 持有写锁的线程不是当前线程,那么当前线程也不能获取写锁(即独占锁,所以返回false
if (w == 0 || current != getExclusiveOwnerThread())
return false;
// 如果当前获取写锁(即独占锁)的次数已经是最大值,抛出Error
if (w == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
}
// 设置state状态失败,表示获取写锁失败
if (!compareAndSetState(c, c + 1))
return false;
setExclusiveOwnerThread(current);
return true;
}
与tryAcquire方法相比,有两个不同:
- 它没有接收参数acquires,相当于1。
- 它没有调用writerShouldBlock方法。即如果发现读锁和写锁都是空闲的,那么就直接获取写锁,当然compareAndSetState必须调用成功。
tryRelease方法 释放写锁(独占锁)
protected final boolean tryRelease(int releases) {
// 如果当前线程不是持有写锁线程即抛出异常
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
// 计算state的值
int nextc = getState() - releases;
// 如果exclusiveCount(nextc)返回0,表示写锁应该被释放。
// 至于读锁(即共享锁)的个数是否为0,没有任何影响
boolean free = exclusiveCount(nextc) == 0;
if (free)
// 设置持有写锁为null
setExclusiveOwnerThread(null);
setState(nextc);
return free;
}
尝试释放写锁(独占锁),如果新的写锁(独占锁)获取次数为0,那么表示释放写锁(独占锁)成功。
tryAcquireShared方法获取读锁(共享锁)
protected final int tryAcquireShared(int unused) {
Thread current = Thread.currentThread();
int c = getState();
// exclusiveCount(c) != 0 表示写锁(即独占锁)被获取,
// getExclusiveOwnerThread() != current 表示获取写锁(即独占锁)的线程不是当前线程
// 如果以上条件都符合,就返回-1,表示获取读锁(共享锁)失败
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current)
return -1;
// 返回读锁(即共享锁)被获取的次数r
int r = sharedCount(c);
// 如果readerShouldBlock()返回false,且获取次数r小于MAX_COUNT,且设置state状态成功。
// 表示获取读锁成功
// 这里c + SHARED_UNIT相当于加一,因为对于读锁来说只有高16位有效的
if (!readerShouldBlock() &&
r < MAX_COUNT &&
compareAndSetState(c, c + SHARED_UNIT)) {
// r == 0表示第一次获取读锁
if (r == 0) {
// 将当前线程设置成第一个获取读锁的线程
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) { // 当前线程是第一个获取读锁的线程
// 将它获取读锁的次数加一
firstReaderHoldCount++;
} else {
// 将缓存的cachedHoldCounter对象赋值给rh
HoldCounter rh = cachedHoldCounter;
// 如果rh为null,或者rh.tid不是当前线程
if (rh == null || rh.tid != getThreadId(current))
// 从线程本地变量readHolds中获取一个HoldCounter对象
cachedHoldCounter = rh = readHolds.get();
else if (rh.count == 0)
// rh.count == 0表示rh已经从线程中移除了,在tryReleaseShared方法中移除的
// 所以要重新设置,
readHolds.set(rh);
// 将该线程获取读锁次数加一
rh.count++;
}
return 1;
}
// 继续尝试获取读锁
return fullTryAcquireShared(current);
}
final int fullTryAcquireShared(Thread current) {
HoldCounter rh = null;
for (;;) {
int c = getState();
// exclusiveCount(c) != 0 表示写锁(即独占锁)被获取,
if (exclusiveCount(c) != 0) {
// getExclusiveOwnerThread() != current 表示获取写锁(即独占锁)的线程不是当前线程
// 就返回-1,表示获取读锁(共享锁)失败
if (getExclusiveOwnerThread() != current)
return -1;
// else 表示获取写锁(即独占锁)的线程就是当前线程,那么当前线程是有可能继续获取读锁(共享锁)的
// 如果写锁(即独占锁)没有被获取,但是readerShouldBlock返回true,即获取读锁(共享锁)可能被阻塞
// 那么就要判断当前线程是不是已经获取过读锁(共享锁),如果是,那么下面的代码,如果不是,那么返回-1,
// 表示获取读锁(共享锁)失败
} else if (readerShouldBlock()) {
// 当前线程是第一个获取读锁(共享锁)线程,表示已经获取过读锁(共享锁)了
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
} else {
if (rh == null) {
rh = cachedHoldCounter;
// 如果rh为null,或者rh.tid不是当前线程
if (rh == null || rh.tid != getThreadId(current)) {
// 从线程本地变量readHolds中获取当前线程的HoldCounter对象
rh = readHolds.get();
// 如果rh.count == 0表示当前线程已经释放了读锁,或者没有获取过读锁
if (rh.count == 0)
readHolds.remove();
}
}
// 如果rh.count == 0表示当前线程已经释放了读锁,或者没有获取过读锁
if (rh.count == 0)
// 直接返回获取读锁(共享锁)失败
return -1;
}
}
// 获取读锁的次数超过最大值,抛出异常
if (sharedCount(c) == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// 设置state状态,c + SHARED_UNIT相当于加一。如果成功,表示获取到读锁
if (compareAndSetState(c, c + SHARED_UNIT)) {
// r == 0表示第一次获取读锁
if (sharedCount(c) == 0) {
// 将当前线程设置成第一个获取读锁的线程
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) { // 当前线程是第一个获取读锁的线程
// 将它获取读锁的次数加一
firstReaderHoldCount++;
} else {
if (rh == null)
rh = cachedHoldCounter;
// 如果rh为null,或者rh.tid不是当前线程
if (rh == null || rh.tid != getThreadId(current))
// 从线程本地变量readHolds中获取当前线程的HoldCounter对象
rh = readHolds.get();
else if (rh.count == 0)
// rh.count == 0表示rh已经从线程中移除了,在tryReleaseShared方法中移除的
// 所以要重新设置,
readHolds.set(rh);
// 将该线程获取读锁次数加一
rh.count++;
cachedHoldCounter = rh;
}
return 1;
}
}
}
要获取读锁(共享锁):
- 如果写锁(独占锁)已经被获取,那么直接返回-1,获取读锁失败
- readerShouldBlock方法返回false,不阻塞当前线程获取读锁
r < MAX_COUNT:读锁的获取次数不能超过MAX_COUNT(65535),
compareAndSetState(c, c + SHARED_UNIT)设置成功,说明锁的状态没有被其他线程改变。- 如果上面条件满足,那么就要设置当前线程读锁的获取次数。
- 返回int整数类型,如果小于0,表示获取共享锁失败。大于或等于0,都表示成功。
因为共享锁可以被多个线程获取,而且每个线程又可以重复获取共享锁,那么我们怎么记录没有线程获取共享锁的次数呢?
- HoldCounter内部类:这是一个很特殊内部类,它有两个成员变量count:记录当前线程获取读锁(共享锁)次数。tid:线程的tid,用来表示属于哪个线程。
- readHolds:是一个 线程本地变量,存储HoldCounter对象。通过它能够获取当前线程的HoldCounter对象,就可以知道当前线程获取读锁(共享锁)次数
- firstReader 与 firstReaderHoldCount: 记录第一个获取读锁的线程和第一个持有读锁的线程获取读锁的次数。提高效率用的,如果当前线程就是第一个获取读锁的线程,就不用通过readHolds获取HoldCounter对象,再获取读锁(共享锁)次数。
- cachedHoldCounter: 用来缓存最近一次获取读锁线程的HoldCounter对象. 也是提高效率用的。
tryReadLock方法获取读锁(共享锁)
final boolean tryReadLock() {
Thread current = Thread.currentThread();
for (;;) {
int c = getState();
// exclusiveCount(c) != 0 表示写锁(即独占锁)被获取,
// getExclusiveOwnerThread() != current 表示获取写锁(即独占锁)的线程不是当前线程
// 如果以上条件都符合,就返回-1,表示获取读锁(共享锁)失败
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current)
return false;
// 返回读锁(即共享锁)被获取的次数r
int r = sharedCount(c);
// 获取读锁的次数超过最大值,抛出异常
if (r == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// 设置state状态,c + SHARED_UNIT相当于加一。如果成功,表示获取到读锁
if (compareAndSetState(c, c + SHARED_UNIT)) {
// r == 0表示第一次获取读锁
if (r == 0) {
// 将当前线程设置成第一个获取读锁的线程
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) { // 当前线程是第一个获取读锁的线程
// 将它获取读锁的次数加一
firstReaderHoldCount++;
} else {
HoldCounter rh = cachedHoldCounter;
// 如果rh为null,或者rh.tid不是当前线程
if (rh == null || rh.tid != getThreadId(current))
// 从线程本地变量readHolds中获取当前线程的HoldCounter对象
cachedHoldCounter = rh = readHolds.get();
else if (rh.count == 0)
// rh.count == 0表示rh已经从线程中移除了,在tryReleaseShared方法中移除的
// 所以要重新设置,
readHolds.set(rh);
// 将该线程获取读锁次数加一
rh.count++;
}
return true;
}
}
}
与tryAcquireShared方法,有四个不同:
- 它没有接收参数acquires,相当于1。
- 它的返回值是boolean,而不是int。
- 它没有调用readerShouldBlock方法, 它不作为能否获取读锁(共享锁)条件。
- 不会调用fullTryAcquireShared方法。
tryReleaseShared方法释放读锁(共享锁)
protected final boolean tryReleaseShared(int unused) {
Thread current = Thread.currentThread();
// 当前线程是第一个获取读锁(共享锁)的线程
if (firstReader == current) {
// 将firstReaderHoldCount减一,如果就是1,那么表示该线程需要释放读锁(共享锁),
// 将firstReader设置为null
if (firstReaderHoldCount == 1)
firstReader = null;
else
firstReaderHoldCount--;
} else {
HoldCounter rh = cachedHoldCounter;
// 获取当前线程的HoldCounter变量
if (rh == null || rh.tid != getThreadId(current))
rh = readHolds.get();
// 将rh变量的count减一,
int count = rh.count;
if (count <= 1) {
readHolds.remove();
// count <= 0表示当前线程就没有获取到读锁(共享锁),这里释放就抛出异常。
if (count <= 0)
throw unmatchedUnlockException();
}
--rh.count;
}
for (;;) {
int c = getState();
// 因为读锁是利用高16位储存的,低16位的数据是要屏蔽的,
// 所以这里减去SHARED_UNIT(65536),相当于减一
// 表示一个读锁已经释放
int nextc = c - SHARED_UNIT;
// 利用CAS函数重新设置state值
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
它分为两步:
- 减少当前线程获取读锁(共享锁)的次数。即减少firstReaderHoldCount或者当前线程对应的rh. count次数。
- 重新设置state变量。因为读锁(共享锁)是利用高16位储存,所以减去SHARED_UNIT(65536),相当于减一。
注意:读锁(共享锁)释放成功的条件是nextc == 0,也就是state等于0,所以表示不但读锁(共享锁)释放了,写锁(独占锁)也要被释放了才行。
小结
- 将state分成高16位与低16位,使用高16位储存读锁(共享锁)被获取的次数,使用低16位储存写锁(独占锁)被获取次数。
- 使用HoldCounter对象记录线程获取读锁(共享锁)次数,使用线程本地变量readHolds,来存储每个线程的HoldCounter对象。
- 实现了获取读锁(共享锁)和写锁(独占锁)方法
非公平锁和公平锁
/**
* 非公平锁
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = -8159625535654395037L;
// 非公平锁,不会阻塞写锁,所以返回false
final boolean writerShouldBlock() {
return false;
}
// 非公平锁,只有当CLH队列第一个节点处于独占锁模式才返回true
final boolean readerShouldBlock() {
return apparentlyFirstQueuedIsExclusive();
}
}
/**
* 公平锁
*/
static final class FairSync extends Sync {
private static final long serialVersionUID = -2274990926593161451L;
// hasQueuedPredecessors返回true,表示在CLH队列中还有其他线程在当前线程前面
// 根据公平锁的规则,当前线程不能获取锁
final boolean writerShouldBlock() {
return hasQueuedPredecessors();
}
final boolean readerShouldBlock() {
return hasQueuedPredecessors();
}
}
非公平锁与公平锁的区别就是当前线程获取读锁或者写锁时,是不是还要加判断其他条件。公平锁要求当前线程必须是等待锁线程队列的第一个线程。
ReadLock 与 WriteLock
/**
* 读锁
*/
public static class ReadLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = -5992448646407690164L;
private final Sync sync;
// sync与ReentrantReadWriteLock中的sync是一个对象
protected ReadLock(ReentrantReadWriteLock lock) {
sync = lock.sync;
}
// 获取共享锁,如果获取不到,就一直等待。不响应中断请求
public void lock() {
sync.acquireShared(1);
}
// 获取共享锁,如果获取不到,就一直等待。如果在线程等待期间有中断请求就抛出异常
public void lockInterruptibly() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
// 尝试获取共享锁,立即返回。返回true表示获取成功,返回false表示获取失败
public boolean tryLock() {
return sync.tryReadLock();
}
// 在规定的unit时间内获取共享锁,如果时间到了还没有获取到共享锁,则返回false,表示获取失败
// 如果在线程等待期间有中断请求就抛出异常
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
// 当前线程释放占用的共享锁,并唤醒这个共享锁上的等待线程
public void unlock() {
sync.releaseShared(1);
}
// 共享锁不能创建Condition对象,所以直接抛出异常
public Condition newCondition() {
throw new UnsupportedOperationException();
}
public String toString() {
int r = sync.getReadLockCount();
return super.toString() +
"[Read locks = " + r + "]";
}
}
/**
* 写锁
*/
public static class WriteLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = -4992448646407690164L;
private final Sync sync;
// sync与ReentrantReadWriteLock中的sync是一个对象
protected WriteLock(ReentrantReadWriteLock lock) {
sync = lock.sync;
}
// 获取独占锁,如果获取不到,就一直等待。不响应中断请求
public void lock() {
sync.acquire(1);
}
// 获取独占锁,如果获取不到,就一直等待。如果在线程等待期间有中断请求就抛出异常
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
// 尝试获取独占锁,立即返回。返回true表示获取成功,返回false表示获取失败
public boolean tryLock( ) {
return sync.tryWriteLock();
}
// 在规定的unit时间内获取独占锁,如果时间到了还没有获取到独占锁,则返回false,表示获取失败
// 如果在线程等待期间有中断请求就抛出异常
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
// 当前线程释放占用的独占锁,并唤醒这个独占锁上的等待线程
public void unlock() {
sync.release(1);
}
// 创建一个Condition对象
public Condition newCondition() {
return sync.newCondition();
}
public String toString() {
Thread o = sync.getOwner();
return super.toString() + ((o == null) ?
"[Unlocked]" :
"[Locked by thread " + o.getName() + "]");
}
// 当前线程是不是获取写锁的线程
public boolean isHeldByCurrentThread() {
return sync.isHeldExclusively();
}
// 返回写锁(独占锁)被获取的次数
public int getHoldCount() {
return sync.getWriteHoldCount();
}
}
读锁和写锁的区别:
- 读锁(共享锁)调用sync对象获取共享锁和释放共享锁的方法,而写锁(独占锁)调用sync对象获取独占锁和释放独占锁的方法。
- 读锁是不能创建Condition对象的。
代码示例
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
class Helper {
private ReadWriteLock lock;
public Helper(ReadWriteLock lock) {
this.lock = lock;
}
public void read() {
lock.readLock().lock();
try {
System.out.println("====线程"+Thread.currentThread().getName()+" 获取了读锁");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
} finally {
System.out.println("----线程"+Thread.currentThread().getName()+" 释放了读锁");
lock.readLock().unlock();
}
}
public void write() {
lock.writeLock().lock();
try {
System.out.println("====线程"+Thread.currentThread().getName()+" 获取了写锁");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
} finally {
System.out.println("----线程"+Thread.currentThread().getName()+" 释放了写锁");
lock.writeLock().unlock();
}
}
}
public class ReadWriteLockTest {
public static void newThread(Helper helper, String name, boolean isRead) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程"+Thread.currentThread().getName()+" 运行");
if (isRead) helper.read();
else helper.write();
}
}, name).start();
}
public static void main(String[] args) {
ReadWriteLock lock = new ReentrantReadWriteLock();
Helper helper = new Helper(lock);
newThread(helper, "t1111", true);
newThread(helper, "t2222", true);
newThread(helper, "t3333", false);
newThread(helper, "t444", true);
}
}
输出结果:
线程t1111 运行
====线程t1111 获取了读锁
线程t2222 运行
====线程t2222 获取了读锁
线程t3333 运行
线程t444 运行
----线程t1111 释放了读锁
----线程t2222 释放了读锁
====线程t3333 获取了写锁
----线程t3333 释放了写锁
====线程t444 获取了读锁
----线程t444 释放了读锁
从结果中分析,读锁和读锁之间是没有等待的,读锁与读锁一起用就必须等待。
附源码
package java.util.concurrent.locks;
import java.util.Collection;
import java.util.concurrent.TimeUnit;
public class ReentrantReadWriteLock
implements ReadWriteLock, java.io.Serializable {
private static final long serialVersionUID = -6992448646407690164L;
/** 读锁(共享锁) */
private final ReadLock readerLock;
/** 写锁(独占锁) */
private final WriteLock writerLock;
/** 使用sync来实现加锁操作 */
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 WriteLock writeLock() { return writerLock; }
// 返回写锁(独占锁)
public ReadLock readLock() { return readerLock; }
/**
* 是AbstractQueuedSynchronizer子类,实现了获取读锁(共享锁)和写锁(独占锁)方法
* 在AQS中用state变量表示锁的获取次数,是int类型。
* 因为在Sync中,既有读锁(共享锁)又有写锁(独占锁),怎么样操作呢?
* 它用了很巧妙的方法,int整形变量的高16位表示读锁(共享锁)次数,低16位表示写锁(独占锁)的次数。
*
* 所以要获取写锁(独占锁)的次数就是将state & 65535(0b011..1),这样高16位的数据剔除了,因为都是变成0了。
* 要获取读锁(共享锁)次数就更简单了,state >>> 16右移16位,低16位的数据都被清除了。
*
*/
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 6317671515068378041L;
// 表示 16位的偏移
static final int SHARED_SHIFT = 16;
// 将1左移16位, ob10000..0即65536
static final int SHARED_UNIT = (1 << SHARED_SHIFT);
// 将1左移16位减一, ob0111...1即65535
static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1;
// 用来计算写锁(即独占锁)的个数。将1左移16位减一, ob0111...1即65535
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
/** 返回读锁(即共享锁)被获取的次数,可以看出读锁利用高16位储存的,所以这里左移了16位 */
static int sharedCount(int c) { return c >>> SHARED_SHIFT; }
/** 返回持有写锁(即独占锁)的线程获取锁的次数,因为独占锁只能有一个线程获取,但是这个线程可以获取多次,
* 可以看出写锁是利用低16位储存的,所以直接与EXCLUSIVE_MASK进行与操作 */
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
// 记录线程获取读锁的次数count,和判断是不是该线程的tid标识
static final class HoldCounter {
// 表示线程获取读锁的次数
int count = 0;
// 得到线程的tid,没有使用Thread.currentThread().tid的方式,
// 是为了防止产生依赖,导致垃圾回收器不能回收线程对象
final long tid = getThreadId(Thread.currentThread());
}
// 是ThreadLocal线程本地变量的子类,用来存储HoldCounter对象
static final class ThreadLocalHoldCounter
extends ThreadLocal<HoldCounter> {
public HoldCounter initialValue() {
return new HoldCounter();
}
}
// 创建一个线程本地变量,用来存储HoldCounter对象
private transient ThreadLocalHoldCounter readHolds;
// 用来缓存最近一次获取读锁线程的HoldCounter对象
private transient HoldCounter cachedHoldCounter;
// 表示第一个获取读锁的线程
private transient Thread firstReader = null;
// 表示第一个持有读锁的线程获取读锁的次数
private transient int firstReaderHoldCount;
Sync() {
readHolds = new ThreadLocalHoldCounter();
//
setState(getState()); // ensures visibility of readHolds
}
/**
* 表示当前线程获取读锁(共享)是否阻塞,返回true,表示线程应该被阻塞(但是注意不是由这个方法将线程阻塞的)
*
* 在非公平锁的实现中调用apparentlyFirstQueuedIsExclusive方法,
* 如果同步队列第一个节点处于独占锁模式,返回true,当前线程应该被阻塞
*
* 在公平锁实现中调用hasQueuedPredecessors方法,如果不同队列中有其他线程在当前线程之前,
* 就会返回true,当前线程应该被阻塞
* @return
*/
abstract boolean readerShouldBlock();
/**
* 表示当前线程获取写锁(独占锁)是否阻塞,返回true,表示线程应该被阻塞(但是注意不是由这个方法将线程阻塞的)
* 一般在非公平锁的实现中直接返回false。
*
* 在公平锁实现中调用hasQueuedPredecessors方法,如果不同队列中有其他线程在当前线程之前,
* 就会返回true,当前线程应该被阻塞
* @return
*/
abstract boolean writerShouldBlock();
protected final boolean tryRelease(int releases) {
// 如果当前线程不是持有写锁线程即抛出异常
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
// 计算state的值
int nextc = getState() - releases;
// 如果exclusiveCount(nextc)返回0,表示写锁应该被释放。
// 至于读锁(即共享锁)的个数是否为0,没有任何影响
boolean free = exclusiveCount(nextc) == 0;
if (free)
// 设置持有写锁为null
setExclusiveOwnerThread(null);
setState(nextc);
return free;
}
protected final boolean tryAcquire(int acquires) {
Thread current = Thread.currentThread();
// 获取当前状态state
int c = getState();
// 得到当前写锁(即独占锁)被获取的次数
int w = exclusiveCount(c);
// c != 0表示读锁或者写锁已经被获取了
if (c != 0) {
// 1. w == 0表示写锁(即独占锁)没有被获取,但是c != 0,表示一定有读锁(共享锁)被获取了,
// 这个时候不能获取写锁(即独占锁),所以返回false
// 2. 持有写锁的线程不是当前线程,那么当前线程也不能获取写锁(即独占锁,所以返回false
if (w == 0 || current != getExclusiveOwnerThread())
return false;
// 获取写锁次数超出上限,因为高16位是用来储存读锁,所以获取写锁次数不能超过65535(MAX_COUNT)
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// 持有写锁的线程再次获取写锁
setState(c + acquires);
return true;
}
// writerShouldBlock()返回true,或者设置state状态失败,表示获取写锁失败
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))
return false;
setExclusiveOwnerThread(current);
return true;
}
protected final boolean tryReleaseShared(int unused) {
Thread current = Thread.currentThread();
// 当前线程是第一个获取读锁(共享锁)的线程
if (firstReader == current) {
// 将firstReaderHoldCount减一,如果就是1,那么表示该线程需要释放读锁(共享锁),
// 将firstReader设置为null
if (firstReaderHoldCount == 1)
firstReader = null;
else
firstReaderHoldCount--;
} else {
HoldCounter rh = cachedHoldCounter;
// 获取当前线程的HoldCounter变量
if (rh == null || rh.tid != getThreadId(current))
rh = readHolds.get();
// 将rh变量的count减一,
int count = rh.count;
if (count <= 1) {
readHolds.remove();
// count <= 0表示当前线程就没有获取到读锁(共享锁),这里释放就抛出异常。
if (count <= 0)
throw unmatchedUnlockException();
}
--rh.count;
}
for (;;) {
int c = getState();
// 因为读锁是利用高16位储存的,低16位的数据是要屏蔽的,
// 所以这里减去SHARED_UNIT(65536),相当于减一
// 表示一个读锁已经释放
int nextc = c - SHARED_UNIT;
// 利用CAS函数重新设置state值
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
// 如果当前线程没有持有读锁(共享锁),却在此线程中调用了释放读锁的操作,
// 就会抛出IllegalMonitorStateException异常
private IllegalMonitorStateException unmatchedUnlockException() {
return new IllegalMonitorStateException(
"attempt to unlock read lock, not locked by current thread");
}
protected final int tryAcquireShared(int unused) {
Thread current = Thread.currentThread();
int c = getState();
// exclusiveCount(c) != 0 表示写锁(即独占锁)被获取,
// getExclusiveOwnerThread() != current 表示获取写锁(即独占锁)的线程不是当前线程
// 如果以上条件都符合,就返回-1,表示获取读锁(共享锁)失败
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current)
return -1;
// 返回读锁(即共享锁)被获取的次数r
int r = sharedCount(c);
// 如果readerShouldBlock()返回false,且获取次数r小于MAX_COUNT,且设置state状态成功。
// 表示获取读锁成功
// 这里c + SHARED_UNIT相当于加一,因为对于读锁来说只有高16位有效的
if (!readerShouldBlock() &&
r < MAX_COUNT &&
compareAndSetState(c, c + SHARED_UNIT)) {
// r == 0表示第一次获取读锁
if (r == 0) {
// 将当前线程设置成第一个获取读锁的线程
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) { // 当前线程是第一个获取读锁的线程
// 将它获取读锁的次数加一
firstReaderHoldCount++;
} else {
// 将缓存的cachedHoldCounter对象赋值给rh
HoldCounter rh = cachedHoldCounter;
// 如果rh为null,或者rh.tid不是当前线程
if (rh == null || rh.tid != getThreadId(current))
// 从线程本地变量readHolds中获取一个HoldCounter对象
cachedHoldCounter = rh = readHolds.get();
else if (rh.count == 0)
// rh.count == 0表示rh已经从线程中移除了,在tryReleaseShared方法中移除的
// 所以要重新设置,
readHolds.set(rh);
// 将该线程获取读锁次数加一
rh.count++;
}
return 1;
}
// 继续尝试获取读锁
return fullTryAcquireShared(current);
}
final int fullTryAcquireShared(Thread current) {
HoldCounter rh = null;
for (;;) {
int c = getState();
// exclusiveCount(c) != 0 表示写锁(即独占锁)被获取,
if (exclusiveCount(c) != 0) {
// getExclusiveOwnerThread() != current 表示获取写锁(即独占锁)的线程不是当前线程
// 就返回-1,表示获取读锁(共享锁)失败
if (getExclusiveOwnerThread() != current)
return -1;
// else 表示获取写锁(即独占锁)的线程就是当前线程,那么当前线程是有可能继续获取读锁(共享锁)的
// 如果写锁(即独占锁)没有被获取,但是readerShouldBlock返回true,即获取读锁(共享锁)可能被阻塞
// 那么就要判断当前线程是不是已经获取过读锁(共享锁),如果是,那么下面的代码,如果不是,那么返回-1,
// 表示获取读锁(共享锁)失败
} else if (readerShouldBlock()) {
// 当前线程是第一个获取读锁(共享锁)线程,表示已经获取过读锁(共享锁)了
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
} else {
if (rh == null) {
rh = cachedHoldCounter;
// 如果rh为null,或者rh.tid不是当前线程
if (rh == null || rh.tid != getThreadId(current)) {
// 从线程本地变量readHolds中获取当前线程的HoldCounter对象
rh = readHolds.get();
// 如果rh.count == 0表示当前线程已经释放了读锁,或者没有获取过读锁
if (rh.count == 0)
readHolds.remove();
}
}
// 如果rh.count == 0表示当前线程已经释放了读锁,或者没有获取过读锁
if (rh.count == 0)
// 直接返回获取读锁(共享锁)失败
return -1;
}
}
// 获取读锁的次数超过最大值,抛出异常
if (sharedCount(c) == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// 设置state状态,c + SHARED_UNIT相当于加一。如果成功,表示获取到读锁
if (compareAndSetState(c, c + SHARED_UNIT)) {
// r == 0表示第一次获取读锁
if (sharedCount(c) == 0) {
// 将当前线程设置成第一个获取读锁的线程
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) { // 当前线程是第一个获取读锁的线程
// 将它获取读锁的次数加一
firstReaderHoldCount++;
} else {
if (rh == null)
rh = cachedHoldCounter;
// 如果rh为null,或者rh.tid不是当前线程
if (rh == null || rh.tid != getThreadId(current))
// 从线程本地变量readHolds中获取当前线程的HoldCounter对象
rh = readHolds.get();
else if (rh.count == 0)
// rh.count == 0表示rh已经从线程中移除了,在tryReleaseShared方法中移除的
// 所以要重新设置,
readHolds.set(rh);
// 将该线程获取读锁次数加一
rh.count++;
cachedHoldCounter = rh;
}
return 1;
}
}
}
final boolean tryWriteLock() {
Thread current = Thread.currentThread();
// 获取当前状态state
int c = getState();
// c != 0表示读锁或者写锁已经被获取了
if (c != 0) {
// 写锁(即独占锁)被获取的次数
int w = exclusiveCount(c);
// 1. w == 0表示写锁(即独占锁)没有被获取,但是c != 0,表示一定有读锁(共享锁)被获取了,
// 这个时候不能获取写锁(即独占锁),所以返回false
// 2. 持有写锁的线程不是当前线程,那么当前线程也不能获取写锁(即独占锁,所以返回false
if (w == 0 || current != getExclusiveOwnerThread())
return false;
// 如果当前获取写锁(即独占锁)的次数已经是最大值,抛出Error
if (w == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
}
// 设置state状态失败,表示获取写锁失败
if (!compareAndSetState(c, c + 1))
return false;
setExclusiveOwnerThread(current);
return true;
}
final boolean tryReadLock() {
Thread current = Thread.currentThread();
for (;;) {
int c = getState();
// exclusiveCount(c) != 0 表示写锁(即独占锁)被获取,
// getExclusiveOwnerThread() != current 表示获取写锁(即独占锁)的线程不是当前线程
// 如果以上条件都符合,就返回-1,表示获取读锁(共享锁)失败
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current)
return false;
// 返回读锁(即共享锁)被获取的次数r
int r = sharedCount(c);
// 获取读锁的次数超过最大值,抛出异常
if (r == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// 设置state状态,c + SHARED_UNIT相当于加一。如果成功,表示获取到读锁
if (compareAndSetState(c, c + SHARED_UNIT)) {
// r == 0表示第一次获取读锁
if (r == 0) {
// 将当前线程设置成第一个获取读锁的线程
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) { // 当前线程是第一个获取读锁的线程
// 将它获取读锁的次数加一
firstReaderHoldCount++;
} else {
HoldCounter rh = cachedHoldCounter;
// 如果rh为null,或者rh.tid不是当前线程
if (rh == null || rh.tid != getThreadId(current))
// 从线程本地变量readHolds中获取当前线程的HoldCounter对象
cachedHoldCounter = rh = readHolds.get();
else if (rh.count == 0)
// rh.count == 0表示rh已经从线程中移除了,在tryReleaseShared方法中移除的
// 所以要重新设置,
readHolds.set(rh);
// 将该线程获取读锁次数加一
rh.count++;
}
return true;
}
}
}
protected final boolean isHeldExclusively() {
// 返回当前线程是不是持有写锁(即独占锁)的线程
return getExclusiveOwnerThread() == Thread.currentThread();
}
final ConditionObject newCondition() {
// 创建一个条件对象ConditionObject
return new ConditionObject();
}
// 返回获取独占锁的线程,如果返回null,表示没有任何线程获取独占锁
final Thread getOwner() {
// (exclusiveCount(getState()) == 0 表示没有任何线程获取独占锁
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() {
// 表示读锁被获取的次数是0,表示没有任何线程获取读锁
if (getReadLockCount() == 0)
return 0;
Thread current = Thread.currentThread();
// 如果当前线程是第一个获取读锁(共享锁)线程,就直接返回firstReaderHoldCount
if (firstReader == current)
return firstReaderHoldCount;
HoldCounter rh = cachedHoldCounter;
// 获取当前线程的HoldCounter变量,得到count值
if (rh != null && rh.tid == getThreadId(current))
return rh.count;
int count = readHolds.get().count;
if (count == 0) readHolds.remove();
return count;
}
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(); }
}
/**
* 非公平锁
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = -8159625535654395037L;
// 非公平锁,不会阻塞写锁,所以返回false
final boolean writerShouldBlock() {
return false;
}
// 非公平锁,只有当CLH队列第一个节点处于独占锁模式才返回true
final boolean readerShouldBlock() {
return apparentlyFirstQueuedIsExclusive();
}
}
/**
* 公平锁
*/
static final class FairSync extends Sync {
private static final long serialVersionUID = -2274990926593161451L;
// hasQueuedPredecessors返回true,表示在CLH队列中还有其他线程在当前线程前面
// 根据公平锁的规则,当前线程不能获取锁
final boolean writerShouldBlock() {
return hasQueuedPredecessors();
}
final boolean readerShouldBlock() {
return hasQueuedPredecessors();
}
}
/**
* 读锁
*/
public static class ReadLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = -5992448646407690164L;
private final Sync sync;
// sync与ReentrantReadWriteLock中的sync是一个对象
protected ReadLock(ReentrantReadWriteLock lock) {
sync = lock.sync;
}
// 获取共享锁,如果获取不到,就一直等待。不响应中断请求
public void lock() {
sync.acquireShared(1);
}
// 获取共享锁,如果获取不到,就一直等待。如果在线程等待期间有中断请求就抛出异常
public void lockInterruptibly() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
// 尝试获取共享锁,立即返回。返回true表示获取成功,返回false表示获取失败
public boolean tryLock() {
return sync.tryReadLock();
}
// 在规定的unit时间内获取共享锁,如果时间到了还没有获取到共享锁,则返回false,表示获取失败
// 如果在线程等待期间有中断请求就抛出异常
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
// 当前线程释放占用的共享锁,并唤醒这个共享锁上的等待线程
public void unlock() {
sync.releaseShared(1);
}
// 共享锁不能创建Condition对象,所以直接抛出异常
public Condition newCondition() {
throw new UnsupportedOperationException();
}
public String toString() {
int r = sync.getReadLockCount();
return super.toString() +
"[Read locks = " + r + "]";
}
}
/**
* 写锁
*/
public static class WriteLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = -4992448646407690164L;
private final Sync sync;
// sync与ReentrantReadWriteLock中的sync是一个对象
protected WriteLock(ReentrantReadWriteLock lock) {
sync = lock.sync;
}
// 获取独占锁,如果获取不到,就一直等待。不响应中断请求
public void lock() {
sync.acquire(1);
}
// 获取独占锁,如果获取不到,就一直等待。如果在线程等待期间有中断请求就抛出异常
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
// 尝试获取独占锁,立即返回。返回true表示获取成功,返回false表示获取失败
public boolean tryLock( ) {
return sync.tryWriteLock();
}
// 在规定的unit时间内获取独占锁,如果时间到了还没有获取到独占锁,则返回false,表示获取失败
// 如果在线程等待期间有中断请求就抛出异常
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
// 当前线程释放占用的独占锁,并唤醒这个独占锁上的等待线程
public void unlock() {
sync.release(1);
}
// 创建一个Condition对象
public Condition newCondition() {
return sync.newCondition();
}
public String toString() {
Thread o = sync.getOwner();
return super.toString() + ((o == null) ?
"[Unlocked]" :
"[Locked by thread " + o.getName() + "]");
}
// 当前线程是不是获取写锁的线程
public boolean isHeldByCurrentThread() {
return sync.isHeldExclusively();
}
// 返回写锁(独占锁)被获取的次数
public int getHoldCount() {
return sync.getWriteHoldCount();
}
}
// Instrumentation and status
// 是否是公平锁
public final boolean isFair() {
return sync instanceof FairSync;
}
// 返回获取独占锁的线程
protected Thread getOwner() {
return sync.getOwner();
}
// 返回读锁被获取的次数
public int getReadLockCount() {
return sync.getReadLockCount();
}
// 写锁是否已经获取
public boolean isWriteLocked() {
return sync.isWriteLocked();
}
// 返回当前线程是不是获取写锁(独占锁)的线程
public boolean isWriteLockedByCurrentThread() {
return sync.isHeldExclusively();
}
// 返回写锁(独占锁)被获取的次数
public int getWriteHoldCount() {
return sync.getWriteHoldCount();
}
// 返回读锁(共享锁)被获取的次数
public int getReadHoldCount() {
return sync.getReadHoldCount();
}
// 返回等待写锁(独占锁)的线程集合
protected Collection<Thread> getQueuedWriterThreads() {
return sync.getExclusiveQueuedThreads();
}
// 返回等待读锁(共享锁)的线程集合
protected Collection<Thread> getQueuedReaderThreads() {
return sync.getSharedQueuedThreads();
}
// CLH队列是否为空 即有没有等待锁的线程
public final boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
// 线程thread 在不在等待锁的线程集合中,即CLH队列中
public final boolean hasQueuedThread(Thread thread) {
return sync.isQueued(thread);
}
// 等待锁线程队列的长度
public final int getQueueLength() {
return sync.getQueueLength();
}
// 返回等到锁的线程队列的集合
protected Collection<Thread> getQueuedThreads() {
return sync.getQueuedThreads();
}
// condition对象的condition队列是否有等待线程
public boolean hasWaiters(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
}
// condition对象上等待线程的个数
public int getWaitQueueLength(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
}
// condition对象上等待线程的集合
protected Collection<Thread> getWaitingThreads(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition);
}
public String toString() {
int c = sync.getCount();
int w = Sync.exclusiveCount(c);
int r = Sync.sharedCount(c);
return super.toString() +
"[Write locks = " + w + ", Read locks = " + r + "]";
}
// 通过UNSAFE直接从内存偏移量获取线程对象的tid,而不是用thread.tid。
// 是为了避免产生依赖,导致垃圾回收器不能回收thread对象
static final long getThreadId(Thread thread) {
return UNSAFE.getLongVolatile(thread, TID_OFFSET);
}
// Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE;
private static final long TID_OFFSET;
static {
try {
UNSAFE = sun.misc.Unsafe.getUnsafe();
Class<?> tk = Thread.class;
TID_OFFSET = UNSAFE.objectFieldOffset
(tk.getDeclaredField("tid"));
} catch (Exception e) {
throw new Error(e);
}
}
}