位置:首頁 > Java技術 > Java教學 > Java線程間通訊

Java線程間通訊

考慮經典的排隊問題,其中一個線程正在生產一些數據,另一個是消費它。為了使問題更有趣,假設生產者必須等待,直到它會產生更多的數據消費完畢之前。

在一個輪詢係統,消費者會浪費大量的CPU周期,而它等待著生產者生產。一旦生產結束了,就開始輪詢,浪費更多的CPU周期等待消費者​​完成,依此類推。顯然,這種情況是不希望的。

為了避免輪詢,Java包括通過下麵的方法優雅的進程間通信機製:

  • wait( ): 這個方法告訴調用線程放棄監視器和進入睡眠狀態,直到其他線程進入同一監視器和調用notify()。

  • notify( ): 這種方法喚醒第一個線程調用wait()在同一個對象上。

  • notifyAll( ): 這種方法喚醒所有調用wait()的同一個對象上的線程。最高優先級的線程將首先運行。

這些方法被實現為final的方法在Object,因此所有的類都有它們。這三種方法都隻能從一個同步的上下文中被調用。

這些方法的對象中聲明。各種形式的wait( ) 存在,使可以指定一段時間等待。

例子:

下麵的示例程序包括四個類:Q,想同步隊列,Producer,也就是生產隊列的條目線程對象;Consumer,即消耗隊列的條目線程對象和PC,tiny類創建一個Q,生產者和消費者。

寫這個程序在Java中正確的方法是使用wait()和notify()方法,以在兩個方向的信號,如下所示:

class Q {
   int n;
   boolean valueSet = false;
   synchronized int get() {
      if(!valueSet)
      try {
         wait();
      } catch(InterruptedException e) {
         System.out.println("InterruptedException caught");
      }
      System.out.println("Got: " + n);
      valueSet = false;
      notify();
      return n;
   }

   synchronized void put(int n) {
      if(valueSet)
      try {
         wait();
      } catch(InterruptedException e) {
         System.out.println("InterruptedException caught");
      }
      this.n = n;
      valueSet = true;
      System.out.println("Put: " + n);
      notify();
   }
}

class Producer implements Runnable {
   Q q;
   Producer(Q q) {
      this.q = q;
      new Thread(this, "Producer").start();
   }

   public void run() {
      int i = 0;
      while(true) {
         q.put(i++);
      }
   }
}

class Consumer implements Runnable {
    Q q;
    Consumer(Q q) {
       this.q = q;
       new Thread(this, "Consumer").start();
    }
    public void run() {
       while(true) {
       q.get();
    }
  }
}
public class PCFixed {

   public static void main(String args[]) {
      Q q = new Q();
      new Producer(q);
      new Consumer(q);
      System.out.println("Press Control-C to stop.");
   }
}

內部的get(),wait()調用。這將導致其執行暫停,直到生產者通知有些數據已準備就緒。

當發生這種情況,執行裡麵的get( ) 恢複。該數據已獲得後,get() 調用notify()。這告訴生產者,這都是可以的把更多的數據在隊列中。

內部的put(),wait()暫停執行,直到消費者已經從隊列中刪除的項目。當恢複執行,數據的下一個項目被放入隊列中,notify()被調用。這就告訴消費者,它現在應該將其刪除。

下麵是這個程序,它顯示了乾淨的同步行為的一些輸出:

Put: 1
Got: 1
Put: 2
Got: 2
Put: 3
Got: 3
Put: 4
Got: 4
Put: 5
Got: 5