如果大家理解了Object.Wait()和Object.notify()方法的話,那么就會很容易的了解Condition對象了;它和wait()和notify()方法的作用是一致的,但是wait()和notify()是和synchronized關鍵字合作使用的,而Condition是和ReentrantLock(重入鎖)相關聯的。
通過ReentrantLock鎖的 new Condition() 方法可以生成一個與當前鎖相關聯的Condition實例。利用Condition對象,我們就可以讓線程在合適的時候等待,或者在某一個特定的時刻讓線程得到通知,繼續執行。
Condition接口提供的基本方法如下:
1 void await() throws InterruptedException; 2 void awaitUninterruptibly(); 3 long awaitNanos(long nanosTimeout) thows InterruptedException; 4 boolean await(long time,TimeUnit unit) throws InterruptedException; 5 boolean awaitUntil(Date deadline) throws InterruptedException; 6 void signal(); 7 void signalAll();
以上方法的含義如下:
❤ await()方法會使當前線程等待,同時釋放當前鎖,當其他線程使用signal()或者signalAll()方法時,線程會重新獲得鎖並繼續執行。或者當線程被中斷時,也能跳出等待,這和Object.wait()方法很相似;
❤ awaitUninterruptibly()方法與await()方法基本相同,但是它不會在等待過程中響應中斷;
❤ awaitNanos(long nanosTimeout) nanosTimeout為等待的最大時間,單位為納秒(ns),如果在時間內被喚醒,則返回nanosTimeout減去已等待的時間;如果在時間內沒有被喚醒,則返回0或者負數;該方法在等待時間內也會相應中斷;
❤ await(long time,TimeUnit unit) 與await()基本一致,但不同的是在時間內未被喚醒或者被中斷都會返回false,其余情況返回true;
❤ awaitUntil() 與awaitNanos(long nanosTimeout)一致,不同的是它不是等待時間段,而是時間到達參數指定的某一時刻;
❤ signal()方法用於喚醒一個在等待中的線程。相對的signalAll()方法會喚醒所有在等待中的線程,這和Object.notify()方法很類似;
下面演示下Condition的用法:
1 public class ReentrantLockCondition implements Runnable { 2
3 public static ReentrantLock lock = new ReentrantLock(); 4 public static Condition condition = lock.newCondition(); 5
6 @Override 7 public void run() { 8 try { 9 lock.lock(); 10 System.out.println("Thread is waiting! : " + System.currentTimeMillis()); 11 condition.await(); 12 System.out.println("Thread is going on! : " + System.currentTimeMillis()); 13 } catch (InterruptedException e) { 14 e.printStackTrace(); 15 }finally { 16 lock.unlock(); 17 } 18 } 19 //測試
20 public static void main(String[] args) throws InterruptedException { 21 ReentrantLockCondition reen = new ReentrantLockCondition(); 22 Thread thread = new Thread(reen); 23 thread.start(); 24 Thread.sleep(3000); 25 //通知線程reen繼續執行
26 lock.lock(); 27 condition.signal(); 28 lock.unlock(); 29 } 30 }
輸出結果:
1 Thread is waiting! : 1537841252752
2 Thread is going on! : 1537841255753
在代碼的第4行,通過lock生成一個與之綁定的Confition對象,並在代碼的第11行,要求線程在Condition對象上進行等待。代碼的第27行,由main線程發出通知,告知等待Condition上的線程可以繼續執行了;由輸出結果來看,線程等待了3S后,繼續執行了,符合我們預期。
注意:
和Object.wait()和notify()方法一樣,當線程使用Condition.await()時,要求線程持有相關的重入鎖,在Condition.await()調用后,這個線程會釋放這把鎖;同理,在Condition.signal()方法調用時,也要求線程獲得相應的鎖。在signal()方法調用后,系統會從當前Condition對象的等待隊列中,喚醒一個線程。一旦線程被喚醒,它會重新嘗試獲得與之綁定的重入鎖,一旦獲取成功,就可以繼續執行了。因此在signal()方法調用后,一般需要釋放相關的鎖,如果省略掉代碼的第28行,那么雖然喚醒了線程reen,但是由於線程無法重新獲得鎖,因而也就無法繼續執行。
Condition具有比wait()/notify()更好的靈活性,具體體現在:
❤ 一個鎖實例,可以綁定多個Condition實例,實現多路通知;
❤ notify()方法進行通知時,是隨機進行選擇的,但重入鎖結合Condition對象,可以實現有選擇性的通知,這是非常重要的。
參考:《Java高並發程序設計》葛一鳴 郭超 編著: