Lock和Condition實現等待通知

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();
		}
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章