Lock物件Condition介面實現等待/通知

z1340954953發表於2018-05-03

關鍵字Synchronized與wait()和notify()/notifyAll()方法相結合可以實現等待通知,ReentrantLock藉助Condition物件可以實現同樣的功能,而且一個lock物件可以建立多個condition物件,從而能夠選擇性condition物件進行等待/通知

condition物件實現等待通知的簡單案例

public class ConditionLockDemo {
	private Lock lock = new ReentrantLock();
	private Condition condition = lock.newCondition();
	public void csleep(){
		try{
			lock.lock();
			System.out.println(Thread.currentThread().getName()+"current time :"+System.currentTimeMillis());
			condition.await();
			System.out.println(Thread.currentThread().getName()+"喚醒後 current time :"+System.currentTimeMillis());
		} catch (InterruptedException e) {
			e.printStackTrace();
		}finally{
			lock.unlock();
		}
	}
	public void signal(){
		try{
			lock.lock();
			condition.signal();
		}finally{
			lock.unlock();
		}
	}
}

啟動兩個執行緒,分別呼叫兩個方法

public static void main(String[] args) throws InterruptedException {
	final ConditionLockDemo cl = new ConditionLockDemo();
	Thread a = new Thread(new Runnable() {
		@Override
		public void run() {
			cl.csleep();
		}
	}, "A");
	Thread b = new Thread(new Runnable() {
		@Override
		public void run() {
			cl.signal();
		}
	}, "B");
	a.start();
	Thread.sleep(1000);
	b.start();
}

輸出:

Acurrent time :1525329885799
A喚醒後 current time :1525329886799

從這個簡單案例:

*  condition 物件是lock物件進行建立的,而且一個lock物件可以建立多個condition物件

*  等待通知的實現,藉助condition 物件的await()方法進入阻塞狀態釋放鎖,signal方法喚醒waiting的執行緒

await()和signal方法的呼叫必須都要先在獲取到鎖之後(lock.lock())

condition部分方法描述
方法描述
await()

當前執行緒進入waiting狀態,並且釋放當前執行緒的鎖,當前執行緒被喚醒,直到其他執行緒呼叫signal、signalAll或者interrupt方法

如果執行緒從await方法返回,表示已經獲取到鎖

awaitUninterruptibly()和上面方法一致,區別在於對於其他執行緒的中斷方法不敏感
awaitUntil(Date deadline)當前執行緒進入等待狀態直到被通知、中斷或者到某個時間點,如果沒有到時間點就被通知,方法返回true,否則到了指定時間,返回false
signal()獲取到鎖後,喚醒處於waiting狀態的執行緒
signalAll()獲取到鎖後,喚醒所有處在waiting狀態的執行緒

condition實現生產者消費者模型

3個執行緒輪流列印1,2,3 。。。

思想:

3個執行緒,建立3個condition物件

3個執行緒讀取同一個共享變數的值,然後根據值,判斷是否進入阻塞狀態

,如果不是阻塞狀態,修改這個值,並喚醒下一個執行緒,  A-B-C-A輪流喚醒

public class ThreeConditionDemo {
	private Lock lock = new ReentrantLock();
	private Condition condition1 = lock.newCondition();
	private Condition condition2 = lock.newCondition();
	private Condition condition3 = lock.newCondition();
	private volatile int count = 1;
	public void printA() {
		try{
			lock.lock();
			while(count!=1){
				condition1.await();
			}
			Thread.sleep(1000);
			System.out.println("1");
			count = 2 ;
			condition2.signal();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}finally{
			lock.unlock();
		}
	}
	public void printB(){
		try{
			lock.lock();
			while(count!=2){
				condition2.await();
			}
			Thread.sleep(1000);
			System.out.println("2");
			count = 3;
			condition3.signal();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}finally{
			lock.unlock();
		}
	}
	public void printC(){
		try{
			lock.lock();
			while(count!=3){
				condition3.await();
			}
			Thread.sleep(1000);
			System.out.println("3");
			count = 1;
			condition1.signal();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}finally{
			lock.unlock();
		}
	}
}

啟動三個執行緒測試:

public static void main(String[] args) {
		final ThreeConditionDemo tcd = new ThreeConditionDemo();
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				while(true){
					tcd.printA();
				}
			}
		});
		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				while(true){
					tcd.printB();
				}
			}
		});
		Thread t3 = new Thread(new Runnable() {
			@Override
			public void run() {
				while(true){
					tcd.printC();
				}
			}
		});
		t1.start();
		t2.start();
		t3.start();
	}
Object監視器鎖和Condition方法的對比

對比項Object監視器方法Condition
前置條件獲取object物件的鎖呼叫lock.lock()獲取鎖
呼叫方法object.wait/notify,notifyAll

Condition condition = lock.newCondition()

condition.await/signal,signalAll

釋放鎖進入等待狀態,能夠不響應中斷不支援支援
釋放鎖進入超時等待支援支援
等待佇列的個數1個

多個,lock可以建立多個condition,呼叫一個condition.await方法

就加入等待佇列中


相關文章