java併發-重入鎖(ReentrantLock)
阿新 • • 發佈:2018-12-22
文章目錄
重入鎖(ReentrantLock)
含義
重入鎖,標識在一個執行緒中,可重複對該資源重複加鎖。
- synchronized就是重入鎖
- ReentrantLock也支援衝入操作
- 是排它鎖(獨佔鎖)
針對於AQS實現重入功能
在重寫tryAquiresxxx的時候考慮同一個執行緒多次lock的情況即可
虛擬碼
- aquire方法
Thread currentThread = Thread.currentThread();
//getExclusiveOwnerThread() 標識獨佔模式下的當前執行緒物件引用
if(currentThread == getExclusiveOwnerThread())
- release方法
- 這裡,就是當前執行緒獲取了多次
- 比如1.lock() 2.lock() 3.unlock() 4.unlock
- 這裡ReentrantLock的aquire()方法傳入的是1
- 執行1,2後state分別是 1,2
- 執行3 c = 2-1 //setState(2-1)
- 執行4 c = 1-1 //直接釋放
protected final boolean tryRelease(int releases) { //同一個執行緒多次獲取資源鎖的話,state會累加,那麼這裡做累減操作 int c = getState() - releases; //不是當前執行緒去release的話,丟擲monitor異常,當然並不是monitor底層實現的 if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; //c == 0的話,就表示不存在一個執行緒獲取多次,那麼直接release if (c == 0) { free = true; setExclusiveOwnerThread(null); } //這裡,就是當前執行緒獲取了多次 //比如1.lock() 2.lock() 3.unlock() 4.unlock //這裡ReentrantLock的aquire()方法傳入的是1 //執行1,2後state分別是 1,2 //執行3 c = 2-1 //setState(2-1) //執行4 c = 1-1 //直接釋放 setState(c); return free; }
公平鎖和非公平鎖
- AQS 預設沒有處理鎖的公平爭奪策略,獲取鎖的邏輯是需要使用者自行定義
- ReentrantLock實現了公平和非公平
- 多執行緒下,執行緒去獲取鎖的順序是不固定的
- 公平鎖比非公平鎖效能要低(需要拒絕獲取,直到該執行緒是head的時候才會成功獲得資源鎖)
Node連結串列 head–>N1(pre,next)–>N2(pre,next)<–tail
//true 標識在佇列中的該執行緒擁有前置節點
//false 該執行緒是head或者 null==null即空佇列 tail==head==null
public final boolean hasQueuedPredecessors() {
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());
}
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
//非公平鎖 沒有hasQueuedPredecessors()方法
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;
}
公平鎖最終獲得鎖的順序和佇列中的順序是一致的,FIFO
公平與非公平效能
- 公平鎖能保證FIFO規則,但是增加了執行緒切換的次數
為什麼?
AQS操作雖然使用CAS無鎖操作機制,但是,CPU在排程的時候,切換至該執行緒的時候,該執行緒去獲取該資源鎖,但是FIFO原則,無法獲取鎖,將處於自旋操作,後續執行緒任務無法執行,cpu排程結束,就切換至下一個執行緒。
公平鎖大大的增加了CPU執行緒排程次數,導致吞吐率(TPS)降低
- 非公平鎖,只要該執行緒獲得到CPU時間片,那麼在沒有執行緒獲取鎖的時候,就可以得到鎖,執行任務,減少了執行緒切換,提高了TPS。
使用
/**
* describe:
* E-mail:[email protected] date:2018/12/16
*
* @Since 0.0.1
*/
public class ReentRantLockTest {
//預設構造是非公平
//true是公平鎖
//false是非公平鎖
public static final Lock lock = new ReentrantLock(true);
static class T extends Thread {
public T(String name){
super(name);
}
@Override
public void run() {
lock.lock();
System.out.println("==" + Thread.currentThread().getName());
try {
//Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
test.T t = new test.T(String.valueOf(i+"Thread"));
t.start();
}
System.out.println(null == null);
}
}
不公平鎖
公平鎖