Condition接口
目的:替代傳統的Object的wait()、notify()。
相較於Object的wait()、notify(),使用Condition的await()、signal()來實現線程間的協作更加的安全,效率也更高。
使用wait、notify的前提是必須獲取到監視器對象,否則會拋異常。因爲wait會釋放鎖,釋放鎖的前提肯定是必須先擁有鎖。
和wait、notify一樣,使用await、signal的前提也是必須先獲取到鎖,否則也會拋異常。
如下:
public static void main(String[] args) throws InterruptedException {
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
condition.await();
}
Exception in thread "main" java.lang.IllegalMonitorStateException
Condition需要與Lock配合使用!
API
-
void await()
線程進入等待狀態。 -
void awaitUninterruptibly()
線程進入等待狀態,不理會中斷。 -
long awaitNanos(long nanosTimeout)
線程等待,支持納秒級的超時,返回剩餘時間。 -
boolean awaitUntil(Date deadline)
線程等待,直到被通知,中斷,或到達deadline時間。 -
void signal()
喚醒一個等待在Condition上的線程。 -
void signalAll()
喚醒所有等待在Condition上的線程。
使用示例
Condition內部維護了一個等待隊列,當線程調用condition.await()時,會將當前線程封裝成一個Node並添加到隊列中,然後釋放鎖,供其他線程競爭。
調用condition.signal()時,會喚醒等待隊列中等待時間最長的節點(頭節點),並將該節點移出隊列,該節點中的線程會繼續競爭鎖,執行邏輯代碼。
經典的消費者生產者
public class ConditionDemo {
//最大庫存數
private final int MAX_COUNT = 10;
//庫存數
private volatile int goodsCount = 0;
//隨機決定線程休眠時間
private Random random = new Random();
//鎖
private Lock lock = new ReentrantLock();
//生產者condition
private Condition producerCondition = lock.newCondition();
//消費者condition
private Condition consumerCondition = lock.newCondition();
public class Producer extends Thread {
volatile boolean flag = true;
@Override
public void run() {
while (flag) {
lock.lock();
try {
if (goodsCount >= MAX_COUNT) {
//System.err.println("庫存滿.");
//庫存滿 停止生產 通知消費者消費
consumerCondition.signalAll();
producerCondition.await();
}
SleepUtil.sleep(random.nextInt(500));
System.out.println("生產:"+(++goodsCount));
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}
private class Consumer extends Thread{
@Override
public void run() {
while (true) {
lock.lock();
try {
if (goodsCount <= 0) {
//沒有庫存,停止消費 通知生產者生產
//System.err.println("沒有庫存了..");
producerCondition.signalAll();
consumerCondition.await();
}else {
SleepUtil.sleep(random.nextInt(500));
System.out.println("消費:" + (--goodsCount));
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}
public static void main(String[] args) {
ConditionDemo demo = new ConditionDemo();
//創建一個生產者
demo.new Producer().start();
//創建5個消費者
for (int i = 0; i < 5; i++) {
demo.new Consumer().start();
}
}
}