是一種可重入同步互斥鎖,其行爲和語義和synchronized相同,但是對其進行了延申和升級,比如支持超時獲取與公平策略,能響應線程中斷,能夠知道是否獲取到了鎖,更加靈活,效率更低.公平策略會降低吞吐量,但是能有效避免線程飢餓,在爭用情況下,公平策略鎖傾向於授予對等待時間最長的線程的訪問權,避免線程爭搶某個線程一直得不到CPU使用權.Lock不會像synchronized一樣,異常的時候自動釋放鎖,所以最佳實踐是,finally中釋放鎖,以便保證發生異常的時候鎖一定被釋放
源碼分析
java.lang.Object
java.util.concurrent.locks.ReentrantLock
public class ReentrantLock
extends Object
implements Lock, Serializable
//構造方法
/**
* 創造一個ReentrantLock實例
* 這相當於使用ReentrantLock(false),默認非公平策略
*/
public ReentrantLock() {
sync = new NonfairSync();
}
/**
* Creates an instance of {@code ReentrantLock} with the
* given fairness policy.
*
* @param fair {@code true} if this lock should use a fair ordering policy
*/
public ReentrantLock(boolean fair) {
//FairSync和NonfairSync分別實現公平與非公平策略
sync = fair ? new FairSync() : new NonfairSync();
}
//重要方法
* @return 當前線程對此鎖的保持數,如果當前線程不保持此鎖,則爲零
*
*/
public int getHoldCount() {
return sync.getHoldCount();
}
/**
* 確定公平策略是否開啓,如果開啓返回true否則返回false
*
* 默認是false
*/
public final boolean isFair() {
return sync instanceof FairSync;
}
/**
* 獲取鎖。
* 如果鎖未被另一個線程持有,則獲取該鎖並立即返回,將鎖持有計數設置爲1。
* 如果當前線程已經持有鎖,那麼持有計數將增加1,並且方法立即返回。
* 如果鎖被另一個線程持有,則當前線程將因線程調度而禁用,並處於休眠狀態,直到獲得鎖爲止,此時鎖持有計數
* 設置爲1。這裏解釋了Lock確實是一個重入鎖
*/
public void lock() {
sync.lock();
}
/**
* 獲取鎖,除非當前線程被中斷。
*
* 如果鎖未被另一個線程持有,則獲取該鎖並立即返回,將鎖持有計數設置爲1。
*
* 如果當前線程已經持有此鎖,則保持計數將增加1,並且方法將立即返回。
*
* 如果鎖被另一個線程持有,則當前線程將被禁用以進行線程調度
*
*
*在獲取鎖時被中斷,然後拋出InterruptedException並清除當前線程的中斷狀態。
*在這個實現中,由於這個方法是一個顯式的中斷點,所以優先考慮響應中斷,而不是對鎖的正常或可重入獲取。
*
* @throws InterruptedException i如果獲取鎖被打斷
*/
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
/**
*嘗試獲取鎖,支持重入操作,
*如果獲取成功返回true否則返回false,和lock()不同的是不會發生阻塞
*公平策略對這個方法不起作用
*/
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
/**
*
*在指定的時間內去獲取lock,如果獲取成功返回true否則返回false,這個方法支持公平策略,可重入,
*響應中斷
* @throws InterruptedException 如果被中斷
* @throws NullPointerException 參數錯誤
*/
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
/**
* 由鎖的持有者釋放鎖
*
* 釋放時計數器減一,計數器爲0才能釋放
*
* @throws IllegalMonitorStateException 非持有者試圖釋放鎖報錯
*
*/
public void unlock() {
sync.release(1);
}
案例分析
ArrayBlockingQueue重要方法分析
/**
*將指定的元素插入到此隊列的尾部(如果立即可行且不會超過該隊列的容量
*在成功時返回 true,如果此隊列已滿,則返回 false
*
* @throws NullPointerException 如果插入的元素爲空
*/
public boolean offer(E e) {
Objects.requireNonNull(e);
final ReentrantLock lock = this.lock;
//加鎖
lock.lock();
try {
//判斷隊列元素個數和數組的長度,如果相同隊列滿了,返回false
if (count == items.length)
return false;
else {
enqueue(e);
return true;
}
} finally {
//釋放鎖
lock.unlock();
}
}
/**
* 將指定的元素加入隊列,如果隊列滿了發生阻塞
*
* @throws InterruptedException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
public void put(E e) throws InterruptedException {
Objects.requireNonNull(e);
final ReentrantLock lock = this.lock;
//加鎖
lock.lockInterruptibly();
try {
while (count == items.length)
//當隊列滿了就阻塞
notFull.await();
//有可用空間就插入元素
enqueue(e);
} finally {
//釋放鎖
lock.unlock();
}
}