1. 程式人生 > >Java併發程式設計(十)Condition介面

Java併發程式設計(十)Condition介面

一、Condition介面簡介

java.util.concurrent.locks.Condition是java併發包中的一個介面,是為配合Lock提供的執行緒等待/通知功能。我們知道Object的監視器方法wait()和notify()配合sychronized關鍵字一樣可以實現等待/通知機制,Condition的優勢在於它可以為多個執行緒間建立不同的Condition,控制粒度更細。如阻塞佇列同時有讀寫執行緒,該喚醒讀執行緒還是寫執行緒,notify方法無法直接指定,而Condition可以做到。

Conditon的所有方法:

public interface Condition {

	/**
	 * 執行緒進入等待狀態,可被中斷
	 * @throws InterruptedException
	 */
	void await() throws InterruptedException;

	/**
	 * 執行緒進入等待狀態,不可被中斷
	 */
	void awaitUninterruptibly();

	/**
	 * 執行緒進入等待狀態,直到被中斷、到達指定時間或喚醒
	 * @param nanosTimeout
	 * @return
	 * @throws InterruptedException
	 */
	long awaitNanos(long nanosTimeout) throws InterruptedException;

	/**
	 * 執行緒進入等待狀態,直到被中斷、到達指定時間或喚醒
	 * @param time
	 * @param unit
	 * @return
	 * @throws InterruptedException
	 */
	boolean await(long time, TimeUnit unit) throws InterruptedException;

	/**
	 * 執行緒進入等待狀態,直到被中斷、到達指定時間或喚醒
	 * @param deadline
	 * @return
	 * @throws InterruptedException
	 */
	boolean awaitUntil(Date deadline) throws InterruptedException;

	/**
	 * 喚醒一個等待執行緒
	 */
	void signal();

	/**
	 * 喚醒所有等待執行緒
	 */
	void signalAll();
}

二、Condition介面應用

典型應用就是LinkedBlockingQueue的實現,通過兩個Condition分別控制讀寫執行緒的等待與通知,這裡特別強調下,呼叫await方法和signal方法之前,該執行緒必須先獲得鎖,原始碼如下:

public class LinkedBlockingQueue {

	private final ReentrantLock takeLock = new ReentrantLock();

	private final Condition notEmpty = takeLock.newCondition();

	private final ReentrantLock putLock = new ReentrantLock();

	private final Condition notFull = putLock.newCondition();

	public void put(E e) throws InterruptedException {

		// ...


		final AtomicInteger count = this.count;
		final ReentrantLock putLock = this.putLock;
        // 必須先獲得鎖才能呼叫condition方法
		putLock.lockInterruptibly();
		try {
            // 佇列滿時,通過notFull這個Conditon一直等待
			while (count.get() == capacity) {
				notFull.await();
			}

			// ...

		} finally {
			putLock.unlock();
		}

		// ...
	}

	public E take() throws InterruptedException {
		
		// ...
		
		final AtomicInteger count = this.count;
		final ReentrantLock takeLock = this.takeLock;
        // 必須先獲得鎖才能呼叫condition方法
		takeLock.lockInterruptibly();
		try {
            // 佇列空時,通過notEmpty這個condition一直等待
			while (count.get() == 0) {
				notEmpty.await();
			}
			
			// ...
			
		} finally {
			takeLock.unlock();
		}
		
		// ...
	}
}

 

參考資料:

https://www.cnblogs.com/jalja/p/5895051.html