ReentrantLock(重入鎖)的好搭檔:Condition 條件


如果大家理解了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高並發程序設計》葛一鳴  郭超 編著:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM