import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
/**
* @ClassName NonReentrantLock
* @Author laixiaoxing
* @Date 2019/8/13 下午11:26
* @Description 可重入鎖, 每次進入一次state就加1 出去一次就減1
* 不可重入鎖,定義state爲1表示鎖已經被某個線程獲取了, 0表示鎖還在 不需要記錄獲取鎖的次數
* <p>
* 這個是個不可重入鎖,且支持條件變量
* @Version 1.0
*/
public class NonReentrantLock implements Lock {
private final Sync sync = new Sync();
@Override
public void lock() {
sync.acquire(1);
}
@Override
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
@Override
public boolean tryLock() {
return sync.tryAcquire(1);
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(time));
}
@Override
public void unlock() {
sync.release(1);
}
@Override
public Condition newCondition() {
return sync.newCondition();
}
/**
* 輔助內部類
* 繼承AQS 重寫一些方法實現自己想要的功能
* 1.獲取鎖狀態 通過state
* 2.嘗試獲取鎖 設置state爲1
* 3.嘗試釋放鎖 設置state爲0
* 4.提供條件變量接口
*/
private static class Sync extends AbstractQueuedSynchronizer {
/**
* 是否鎖已經被持有
*
* @return
*/
@Override
protected boolean isHeldExclusively() {
return getState() == 1;
}
/**
* 嘗試獲取鎖
*
* @param acquires
* @return
*/
@Override
public boolean tryAcquire(int acquires) {
//如果state爲0 設置爲1 成功
if (compareAndSetState(0, 1)) {
//設置獨佔模式的擁有者
setExclusiveOwnerThread(Thread.currentThread());
return true;
} else {
return false;
}
}
@Override
protected boolean tryRelease(int releases) {
if (getState() == 0) {
throw new IllegalMonitorStateException();
}
//清空獨佔模式的擁有者
setExclusiveOwnerThread(null);
setState(0);
return true;
}
/**
* 提供條件變量接口
*
* @return
*/
Condition newCondition() {
return new ConditionObject();
}
}
/**
* 使用這個鎖實現生產者消費者模型
*
* @param args
*/
public static void main(String[] args) {
NonReentrantLock reentrantLock = new NonReentrantLock();
Condition full = reentrantLock.newCondition();
Condition empty = reentrantLock.newCondition();
int size = 5;
Queue queue = new LinkedBlockingQueue(size);
Thread producer = new Thread(() -> {
while (true) {
reentrantLock.lock();
//滿了
if (queue.size() == size) {
//阻塞
try {
full.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
queue.add("a");
empty.signal();
}
reentrantLock.unlock();
}
});
Thread comsumer = new Thread(() -> {
while (true) {
reentrantLock.lock();
//不空
if (queue.size() != 0) {
String a = (String) queue.poll();
System.out.println("消費者消費" + a);
full.signal();
} else {
try {
empty.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
reentrantLock.unlock();
}
});
producer.start();
comsumer.start();
}
}
原理:AQS是一個抽象類,裏面定義了一個state變量和一個隊列,隊列元素爲用線程對象封裝成的Node, 同時還有一個內部類conditionObject, conditionObject內有一個條件隊列,元素和AQS的裏面的Node類似。
這裏定義了state爲1時鎖被拿走,0時無鎖。 當通過cas獲取鎖失敗的時候,會將這個線程封裝成node放到AQS內的等待隊列裏面去,同時使用park方法掛起這個線程。
如果獲取鎖成功,會將state更新爲1。
當釋放鎖的時候,將state更新爲0,同時去阻塞隊列裏面喚醒頭節點下一個節點的Node裏面的線程,讓它競爭鎖。
調用condition的await方法時,將state更新爲0,且將該線程封裝成node放到condition的條件隊列裏面,然後掛起。
調用condition的sign方法時,將線程從條件隊列移到AQS的阻塞隊列裏面,然後喚醒這個線程,讓這個線程能夠參與競爭鎖