簡介
ReentrantLock是一個可重入的獨享鎖,是平時常用的一個鎖,用法和實現(xiàn)都比較簡單,如下:
private static ReentrantLock lock = new ReentrantLock();
private static void testLock() {
for (int i=0;i<100000;i++) {
lock.lock();
try {
test++;
} catch (Exception e) {
System.out.println(e.getMessage());
} finally {
lock.unlock();
}
}
}
private static void testLock2() {
for (int i=0;i<100000;i++) {
if(lock.tryLock()) {
try {
test++;
} catch (Exception e) {
System.out.println(e.getMessage());
} finally {
lock.unlock();
}
}
}
}
private static void testLock3() throws Exception {
for (int i=0;i<100000;i++) {
if(lock.tryLock(1, TimeUnit.MINUTES)) {
try {
test++;
} catch (Exception e) {
System.out.println(e.getMessage());
} finally {
lock.unlock();
}
}
}
}
還有ReentrantLock支持可重入。
ReentrantLock是基于aqs獨占模式實現(xiàn)的,
本文重點介紹下公平和非公平模式,和ReentrantLock實現(xiàn)原理。
同步器-Sync
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
abstract void lock();
//ReentrantLock 默認是非公平模式,這里給出了非公平模式下的嘗試獲取鎖
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
// AbstractQueuedSynchronizer 的state常用于保存資源被占用狀態(tài),這里保存ReentrantLock鎖狀態(tài),=0表示現(xiàn)在鎖現(xiàn)在沒被占用
int c = getState();
if (c == 0) {
// 設置成占用狀態(tài),返回true,并設置lock擁有線程為當前線程,支持可重入
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;
}
// 實現(xiàn)tryRelease,嘗試釋放鎖,
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;
}
```
}
了解AbstractQueuedSynchronizer 都知道,AbstractQueuedSynchronizer暴露tryAcquire,tryRelease讓實現(xiàn)者自己去實現(xiàn),ReentrantLock的Sync實現(xiàn)了這兩個方法,用于判斷是否可以獲取鎖和釋放鎖,接下來介紹非公平模式和公平模式
非公平模式-NonfairSync
ReentrantLock支持公平、非公平兩種策略,并通過繼承AQS實現(xiàn)了對應兩種策略的同步器NonfairSync與FairSync,默認是非公平策略
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
// 這里實現(xiàn) lock方法,即ReentrantLock.lock方法
final void lock() {
// 這里判斷是否有其他資源占用,cas設置成功,說明當前線程獲取成功,這里
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
// 否則申請一個資源,就是這里會調用tryAcquire方法
acquire(1);
}
//嘗試獲取鎖資源,調用的是非公平獲取鎖
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
公平模式-FairSync
/**
* Sync object for fair locks
*/
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
//獲取鎖
final void lock() {
acquire(1);
}
//公平模式和非公平模式區(qū)別就在這里,多了hasQueuedPredecessors判斷,就是看是否已有等待獲取鎖資源線程并且不是當前線程,如果有不去競爭
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
公平模式和非公平模式,區(qū)別就在于一個hasQueuedPredecessors函數(shù),該函數(shù)用于判斷是否已有節(jié)點在等待資源了并且不是該線程等待的,附上代碼
public final boolean hasQueuedPredecessors() {
// The correctness of this depends on head being initialized
// before tail and on head.next being accurate if the current
// thread is first in queue.
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
以上就是公平模式和非公平模式實現(xiàn),都是實現(xiàn)了AbstractQueuedSynchronizer 的tryAcquire和tryRelease方法,用于判斷是否能夠獲取資源和釋放資源,實現(xiàn)簡單。
ReentrantLock的方法就不介紹了,都是調sync實現(xiàn)的方法,ReentrantLock最重要實現(xiàn)就是實現(xiàn)AbstractQueuedSynchronizer 的tryAcquire和tryRelease方法,支持可重入,還有支持Condition等待通知實現(xiàn)。