ReentrantLock基于volatile state建立的
2019-07-15 本文已影响0人
王侦
以非公平锁为例。
1.加锁
public void lock() {
sync.lock();
}
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
其中tryAcquire(arg)调用的是NonfairSync的:
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
nonfairTryAcquire(acquires)是其父类Sync中的final方法:
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
加锁总结如下:
- 抢占锁使用CAS更新state;
2.解锁
public void unlock() {
sync.release(1);
}
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
解锁总结:
- 解锁首先会调用getState读取,然互殴调用 setState(c)更新
3.volatile写-读内存语义
- 当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量值刷新到主内存中。
- 当读一个volatile变量时,JMM会把该线程对应的本地内存置为无效,线程直接从主存中读取共享变量
当第二个操作是volatile写时,不允许重排序。确保了volatile写之前的操作不会重排序到volatile写之后。
当第一个操作是volatile读时,不允许重排序。确保了volatile读之后的操作不会重排序到volatile读之前。
volatile变量的happens-before规则:
- 对于以volatile域的写,happens-before任意后续对于这个volatile域的读。
总结上面的ReentrantLock的加锁和解锁:
- 加锁使用CAS更新,相当于同时兼具了volatile的读和写
- 解锁先读后写,也相当于同时兼具了volatile的读和写。
因此在lock期间更新的共享内容对于另一个线程而言总是可见的。