Java併發——使用Condition線程間通信

1. Java中線程協作的最常見的兩種方式:利用Object.wait()、Object.notify()和使用Condition

(1)複習一下Object.wait()、Object.notify()

在java中,對於任意一個java對象,它都擁有一組定義在java.lang.Object上監視器方法,包括wait(),wait(long timeout),notify(),notifyAll(),這些方法配合synchronized關鍵字一起使用可以實現等待/通知模式。

以前的文章:https://blog.csdn.net/zhm1563550235/article/details/84259542

(2)什麼是Condition接口?

Condition接口也提供了類似Object監視器的方法,通過與Lock配合來實現等待/通知模式。

2. Condition接口 

接口Condition把Object的wait和notification方法(包括wait()、notify()、notifyAll())分解到不同的條件對象中。通過把這些條件和任意Lock實現的使用組合起來,起到讓每個對象上具有多重等待集合的作用。這裏Lock取代了同步方法、同步代碼塊,condition取代了Object的wait、notification方法。 

3. Condition聲明的方法

方法名稱 描述
void await() 在接收到信號或被中斷以前,強制調用線程一直等待。
boolean await(long time, TimeUnit unit) 在接收到信號、被中斷,或者超過指定的等待時間之前,強制調用線程一直等待。

同樣是在await()基礎上增加了超時響應,不同的是:

  • 可以自定義超時時間單位;
  • 返回值返回true/false,在time之前被喚醒,返回true,超時返回false。
long awaitNanos(long nanosTimeout)

在接收到信號,被中斷,或者超過指定的等待時間之前,強制調用線程一直等待。同樣是在await()基礎上增加了超時響應,不同的是:

返回值表示當前剩餘的時間,如果在nanosTimeout之前被喚醒,返回值 = nanosTimeout - 實際消耗的時間,返回值 <= 0表示超時;

void awaitUninterruptibly() 在接收到信號之前,強制當前線程一直等待。
boolean awaitUntil(Date deadline) 在接收到信號、被中斷,或者超過指定的截止時間之前,強制當前的線程一直等待。
void signal() 喚醒一個等待中的線程。
void signalAll() 喚醒所有等待中的線程。

4. 獲取Condition 

Condition實例實質上被綁定到一個鎖上。一個鎖內部可以有多個Condition,即有多路等待和通知。要爲特定 Lock 實例獲得 Condition 實例,請使用其 newCondition() 方法。

Conditon newCondition() 返回用來與當前Lock實例一起使用的Condition實例。

類似於 object.wait()和object.notify()的功能。object.wait()與object.notify()需要結合synchronized使用。Condition需要結合ReentrantLock使用。

5. Condition與循環一起使用,防止"虛假喚醒"

在等待Condition時,允許發生"虛假喚醒",這通常作爲對基礎平臺語義的讓步。若使用"if(!條件)"則被"虛假喚醒"的線程可能繼續執行。所以"while(!條件)"可以防止"虛假喚醒"。建議總是假定這些"虛假喚醒"可能發生,因此總是在一個循環中等待。

6. Condition的使用

程序案例來自:http://www.cnblogs.com/dolphin0520/p/3920385.html

(1)使用Object的wait()和notify()實現生產者消費者: 

public class Test {
    private int queueSize = 10;
    private PriorityQueue<Integer> queue = new PriorityQueue<Integer>(queueSize);
      
    public static void main(String[] args)  {
        Test test = new Test();
        Producer producer = test.new Producer();
        Consumer consumer = test.new Consumer();
          
        producer.start();
        consumer.start();
    }
      
    class Consumer extends Thread{
          
        @Override
        public void run() {
            consume();
        }
          
        private void consume() {
            while(true){
                synchronized (queue) {
                    while(queue.size() == 0){
                        try {
                            System.out.println("隊列空,等待數據");
                            queue.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                            queue.notify();
                        }
                    }
                    queue.poll();          //每次移走隊首元素
                    queue.notify();
                    System.out.println("從隊列取走一個元素,隊列剩餘"+queue.size()+"個元素");
                }
            }
        }
    }
      
    class Producer extends Thread{
          
        @Override
        public void run() {
            produce();
        }
          
        private void produce() {
            while(true){
                synchronized (queue) {
                    while(queue.size() == queueSize){
                        try {
                            System.out.println("隊列滿,等待有空餘空間");
                            queue.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                            queue.notify();
                        }
                    }
                    queue.offer(1);        //每次插入一個元素
                    queue.notify();
                    System.out.println("向隊列取中插入一個元素,隊列剩餘空間:"+(queueSize-queue.size()));
                }
            }
        }
    }
}

(2)使用Condition實現消費者生產者

public class Test {
    private int queueSize = 10;
    private PriorityQueue<Integer> queue = new PriorityQueue<Integer>(queueSize);
    private Lock lock = new ReentrantLock();
    private Condition notFull = lock.newCondition();
    private Condition notEmpty = lock.newCondition();
     
    public static void main(String[] args)  {
        Test test = new Test();
        Producer producer = test.new Producer();
        Consumer consumer = test.new Consumer();
          
        producer.start();
        consumer.start();
    }
      
    class Consumer extends Thread{
          
        @Override
        public void run() {
            consume();
        }
          
        private void consume() {
            while(true){
                lock.lock();
                try {
                    while(queue.size() == 0){
                        try {
                            System.out.println("隊列空,等待數據");
                            notEmpty.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    queue.poll();                //每次移走隊首元素
                    notFull.signal();
                    System.out.println("從隊列取走一個元素,隊列剩餘"+queue.size()+"個元素");
                } finally{
                    lock.unlock();
                }
            }
        }
    }
      
    class Producer extends Thread{
          
        @Override
        public void run() {
            produce();
        }
          
        private void produce() {
            while(true){
                lock.lock();
                try {
                    while(queue.size() == queueSize){
                        try {
                            System.out.println("隊列滿,等待有空餘空間");
                            notFull.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    queue.offer(1);        //每次插入一個元素
                    notEmpty.signal();
                    System.out.println("向隊列取中插入一個元素,隊列剩餘空間:"+(queueSize-queue.size()));
                } finally{
                    lock.unlock();
                }
            }
        }
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章