前言
Reentrant是一種可重入鎖前翎,是一種遞歸無阻塞的同步機制稚配。實現(xiàn)了和synchronized類似的同步策略。與synchronized配合使用的wait港华、notify药有、notifyall等函數(shù),由Codition負責提供苹丸,這個后續(xù)另外會說愤惰。
使用
1、在使用上與synchronized差異的是 實現(xiàn)lock接口的reentrant需要手動的去lock和release赘理,因為synchronized是JVM也就是Java語法層面實現(xiàn)的宦言,而Lock是JDK里面實現(xiàn)的。相對于sychronized來說商模,我們使用時要比synchronized更加嚴謹奠旺,因為忘記釋放鎖非常容易導致死鎖蜘澜。建議選擇在finally中進行鎖的釋放
2、lock實現(xiàn)的鎖粒度可以控制更加小
3响疚、Lock 實現(xiàn)能更支持更多高級的特性鄙信,比如說鎖超時等。
4忿晕、因為是JDK實現(xiàn)装诡,所以具有了更多特性的高級鎖比如說:read lock、write lock践盼,并且支持我們自定義特殊的鎖鸦采,這個雖然通常用不太到,但必要時是非常有用的咕幻。
demo:首先是使用synchronize渔伯,感受一下
class Test1 {
private static volatile int condition = 0;
private static final Object lock = new Object();
public static void main(String[] args) throws InterruptedException {
Thread A = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock) {
while (!(condition == 1)) {
try {
lock.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
System.out.println("a executed by notify");
}
}
});
A.start();
Thread.sleep(2000);
condition = 1;
synchronized (lock) {
lock.notify();
}
}
}
然后是使用Lock
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Test2 {
private static volatile int condition = 0;
private static Lock lock = new ReentrantLock();
private static Condition lockCondition = lock.newCondition();
public static void main(String[] args) throws InterruptedException {
Thread A = new Thread(new Runnable() {
@Override
public void run() {
lock.lock();
try {
while (!(condition == 1)) {
lockCondition.await();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.unlock();
}
System.out.println("a executed by condition");
}
});
A.start();
Thread.sleep(2000);
condition = 1;
lock.lock();
try {
lockCondition.signal();
} finally {
lock.unlock();
}
}
}
原理
開始看源碼:
首先可以看到ReentrantLock實現(xiàn)了Lock
和Serializable
接口,序列化不多說肄程,Lock定義了是現(xiàn)在JDK中鎖的規(guī)范锣吼,然后類中持有一個Sync
對象,其中Sync是ReentrantLock的一個靜態(tài)內(nèi)部類蓝厌,這是整個ReentrantLock的基礎吐限,Sync繼承自AQS,換句話說AQS也就是ReentrantLock的實現(xiàn)基礎褂始。
public class ReentrantLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = 7373984872572414699L;
/** Synchronizer providing all implementation mechanics */
private final Sync sync;
/**
* Base of synchronization control for this lock. Subclassed
* into fair and nonfair versions below. Uses AQS state to
* represent the number of holds on the lock.
*/
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
然后往后看會得到另外幾個靜態(tài)內(nèi)部類:FairSync
诸典、NonfairSync
,他們均繼承自Sync
這兩個區(qū)別最大的操作是:
如果當前線程不是鎖的占有者,則NonfairSync
并不判斷是否有等待隊列,直接使用CAS去進行鎖的占用;
如果當前線程不是鎖的占有者,則FairSync
則會判斷當前是否有等待隊列,如果有則將自己加到等待隊列尾;
這其實就是公平鎖&非公平鎖的實現(xiàn)崎苗,默認非公平狐粱。
下面的代碼中,我加了幾行注釋胆数,大家注重關注下可重入及公平非公平是如何實現(xiàn)的肌蜻。
/**
* Sync object for non-fair locks
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
它這里使用的是Sync里面的實現(xiàn):
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
/**
* Performs non-fair tryLock. tryAcquire is implemented in
* subclasses, but both need nonfair try for trylock method.
*/
@ReservedStackAccess
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()) {//可重入的實現(xiàn)
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
然后是FairSync的實現(xiàn)
/**
* Sync object for fair locks
*/
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/
@ReservedStackAccess
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()) {//可重入部分的實現(xiàn)
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
看到這里,大體已經(jīng)能猜到具體實現(xiàn)了必尼。ReentrantLock中維護著一個AQS蒋搜,然后競爭鎖的線程是在這里排隊的,然后通過對應的CAS操作進行鎖的爭用判莉。具體的實現(xiàn)參考AQS及CAS豆挽。
默認非公平:
/**
* Creates an instance of {@code ReentrantLock}.
* This is equivalent to using {@code ReentrantLock(false)}.
*/
public ReentrantLock() {
sync = new NonfairSync();
}
可以很明顯的看到底層實現(xiàn)幾乎完全依賴于AQS,其實就是AQS包了一層罷了券盅。
public void lock() {
sync.acquire(1);
}
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
public void unlock() {
sync.release(1);
}
public int getHoldCount() {
return sync.getHoldCount();
}