轉載請注明出處:http://blog.csdn.net/linxdcn/article/details/72850375
1 輔助内部類
在ReetrantLock内部基于AQS類實作了一個抽象類Sync同步器,對于AQS不熟悉的,可以看看這篇文章:AbstractQueuedSynchronizer同步器。基于Sync還實作了公平鎖和非公平鎖:
- 公平鎖
- 線程按照他們送出請求的順序擷取鎖
- 如果有另一個線程持有鎖或者有其他線程在等待隊列中等待這個所,那麼新發出的請求的線程将被放入到隊列中。
- 非公平鎖
- 當一個線程請求非公平鎖時,如果在送出請求的同時該鎖變成可用狀态,那麼這個線程可能會跳過隊列中所有的等待線程而獲得鎖
- 非公平鎖上,隻有當鎖被某個線程持有時,新送出請求的線程才會被放入隊列中
//抽象同步器Sync繼承AQS,子類可以非公平或者公平鎖
abstract static class Sync extends AbstractQueuedSynchronizer {
abstract void lock();
// 非公平鎖的嘗試擷取
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == ) {
// 跟公平鎖擷取的差別時,這裡少了判斷隊列是否為空的函數hasQueuedPredecessors
// 即不管排隊隊列是否為空,該線程都将直接嘗試擷取鎖
if (compareAndSetState(, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
// 以下這個函數實作了重入鎖
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < ) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
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 == ) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
}
//非公平鎖的同步器
static final class NonfairSync extends Sync {
final void lock() {
if (compareAndSetState(, ))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire();
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
// 公平鎖的同步器
static final class FairSync extends Sync {
final void lock() {
acquire();
}
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == ) {
if (!hasQueuedPredecessors() &&
compareAndSetState(, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < )
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
2 主要方法
ReentrantLock的方法源碼比較簡單,主要是委托給Sync同步器實作。
//構造函數,預設使用非公平鎖同步器
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
public void lock() {
sync.lock();
}
public void unlock() {
sync.release();
}
// 實作了條件變量
public Condition newCondition() {
return sync.newCondition();
}
3 條件變量
條件變量是實作了Java中的Condition接口的類,其中Condition中的await、signal、signalAll方法與Object中的wait、notify、notifyAll類似。
假設現在我們有三個線程A、B、C,申請了一個ReetrantLock,以及兩個條件變量,如下代碼,下面舉例說明Condition如何工作
Lock lock = new ReentrantLock();
Condition conditionX = lock.newCondition();
Condition conditionY = lock.newCondition();
初始狀态
假設已經有一個線程擷取的了lock,然後線程A、B、C依次擷取lock,狀态圖如下:

Step 1
線程A、B分别調用了
conditionX.await()
,源碼如下
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
// 把等待線程包裝為Node
Node node = addConditionWaiter();
// 釋放鎖
int savedState = fullyRelease(node);
int interruptMode = ;
while (!isOnSyncQueue(node)) {
// 線程在此挂起
LockSupport.park(this);
if ((interruptMode = checkInterruptWhileWaiting(node)) != )
break;
}
// 當收到signal通知後,線程會繼續,搶占鎖
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null) // clean up if cancelled
unlinkCancelledWaiters();
// 如果搶占不成功,線程繼續挂起
if (interruptMode != )
reportInterruptAfterWait(interruptMode);
}
//在等待隊列中建立一個Node
private Node addConditionWaiter() {
Node t = lastWaiter;
if (t != null && t.waitStatus != Node.CONDITION) {
unlinkCancelledWaiters();
t = lastWaiter;
}
Node node = new Node(Thread.currentThread(), Node.CONDITION);
if (t == null)
firstWaiter = node;
else
t.nextWaiter = node;
lastWaiter = node;
return node;
}
線程A、B均在函數
LockSupport.park(this)
處被挂起,等待通知,目前的狀态圖如下:
Step 2
線程C獲得鎖,執行。當C執行完後,調用
signal
通知
await
的線程
// 将一個等待時間最長的waitQueue的Node移到lockQueue
public final void signal() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
doSignal(first);
}
private void doSignal(Node first) {
do {
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
first.nextWaiter = null;
} while (!transferForSignal(first) &&
(first = firstWaiter) != null);
}
final boolean transferForSignal(Node node) {
if (!compareAndSetWaitStatus(node, Node.CONDITION, ))
return false;
Node p = enq(node);
int ws = p.waitStatus;
if (ws > || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
LockSupport.unpark(node.thread);
return true;
}
4 總結
(1)synchronized關鍵字無法中斷一個正在等候獲得鎖的線程,也無法通過輪詢得到鎖;ReentrantLock 類實作了 Lock ,它擁有與 synchronized 相同的并發性和記憶體語義,但是添加了類似輪詢鎖、定時鎖等候和可中斷鎖等候的一些特性。
(2)根類 Object 包含某些特殊的方法,用來線上程的 wait() 、 notify() 和 notifyAll() 之間進行通信;Lock 架構包含了對 wait 和 notify 的概括,這個概括叫作 條件(Condition),對于指定的 Lock ,可以有不止一個條件變量與它關聯。
(3)synchronized的優點:使用 synchronized 的時候,不可能忘記釋放鎖;在退出 synchronized 塊時,JVM 會做這件事;當 JVM 用 synchronized 管理鎖定請求和釋放時,JVM 在生成線程轉儲時能夠包括鎖定資訊。這些對調試非常有價值,因為它們能辨別死鎖或者其他異常行為的來源
(4)java.util.concurrent.lock 中的鎖定類是用于進階使用者和進階情況的工具 。一般來說,除非您對 Lock 的某個進階特性有明确的需要,或者有明确的證據(而不是僅僅是懷疑)表明在特定情況下,同步已經成為可伸縮性的瓶頸,否則還是應當繼續使用 synchronized。
參考
https://www.ibm.com/developerworks/cn/java/j-jtp10264/index.html
轉載請注明出處:http://blog.csdn.net/linxdcn/article/details/72850375