1. 程式人生 > >利用wait()和notify()實現生產者與消費者問題

利用wait()和notify()實現生產者與消費者問題

     生產者與消費者問題是併發程式設計裡面的經典問題,下面用wait()和notify()來實現消費者執行緒和生產者執行緒的併發執行。

   說之前先講幾個概念:

   wait()與sleep()的區別:

       1.首先sleep()是Thread()類的方法,而wait()是Object類的方法,包括notify(),notifyAll()都是Object類的方法

       2.sleep()方法是休眠,阻塞執行緒的同時仍然會持有鎖,也就是說它休眠期間其他執行緒仍然無法獲得鎖,同時sleep()休眠時自動醒           的;而呼叫wait()方法時,則自動釋放鎖,也就是其他執行緒可以獲得鎖,而且wait()是無法自動醒的,只有通過notify()或

 notifyAll()         才行。

    notify()與notifyAll()的區別

    notify()一次只能啟用一個對這個物件進行wait()的執行緒,當多個執行緒都對此物件wait()時,是隨機挑一個notify(),而notifyAll()是一次      性啟用所以對此物件進行wait()的執行緒。

   接下來說說利用wait()和notify()來實現生產者和消費者併發問題:

   顯然要保證生產者和消費者併發執行不出亂,主要要解決:當生產者執行緒的快取區為滿的時候,就應該呼叫wait()來停止生產者繼續生產,而當生產者滿的緩衝區被消費者消費掉一塊時,則應該呼叫notify()喚醒生產者,通知他可以繼續生產;同樣,對於消費者,當消費者執行緒的快取區為空的時候,就應該呼叫wait()停掉消費者執行緒繼續消費,而當生產者又生產了一個時就應該呼叫notify()來喚醒消費者執行緒通知他可以繼續消費了。

當然我們必須在wait()和notify()的時候鎖住我們所要操作的物件,這裡即快取區,下面是一個使用wait()的notify()的規範程式碼模板:

synchronized (sharedObject) { //鎖住操作物件
    while (condition) { //當某個條件下
    sharedObject.wait(); //進入wait
        
    } 
    // 做了什麼事,就可以啟用
    shareObject.notify();
} 


下面就貼一下wait和notify實現一個生產者執行緒和一個消費者執行緒併發執行的程式碼:

import java.util.LinkedList; 
import java.util.Queue; 
import java.util.Random; 

public class ProducerConsumerInJava { 
public static void main(String args[]) { 
  System.out.println("How to use wait and notify method in Java"); 
  System.out.println("Solving Producer Consumper Problem"); 
  Queue<Integer> buffer = new LinkedList<>(); 
  int maxSize = 10; 
  Thread producer = new Producer(buffer, maxSize, "PRODUCER"); 
  Thread consumer = new Consumer(buffer, maxSize, "CONSUMER");<span style="font-family: Arial, Helvetica, sans-serif;"> </span>
<span style="font-family: Arial, Helvetica, sans-serif;"> //開啟生產者和消費者執行緒</span>
  producer.start(); 
  consumer.start(); } 
} 

//生產者執行緒
class Producer extends Thread 
{ private Queue<Integer> queue; 
  private int maxSize; 
  public Producer(Queue<Integer> queue, int maxSize, String name){ 
   super(name); this.queue = queue; this.maxSize = maxSize; 
  } 
  @Override public void run() 
  { 
   while (true) 
    { 
     synchronized (queue) { 
      while (queue.size() == maxSize) { //當快取區滿的時候
       try { 
        //進入wait
        queue.wait(); 
       } catch (Exception ex) { 
        ex.printStackTrace(); 
      } 
       } 
       //快取區不為空的時候就可以繼續生產,生產後喚醒消費者執行緒的wait
        queue.add(i); 
        queue.notifyAll(); 
      } 
     } 
    } 
   } 

//消費者執行緒
class Consumer extends Thread { 
  private Queue<Integer> queue; 
  private int maxSize; 
  public Consumer(Queue<Integer> queue, int maxSize, String name){ 
   super(name); 
   this.queue = queue; 
   this.maxSize = maxSize; 
  } 
  @Override public void run() { 
   while (true) { 
    synchronized (queue) { 
     while (queue.isEmpty()) { //當快取區為空的時候
      
      try { 
       queue.wait(); //進入wait
      } catch (Exception ex) { 
       ex.printStackTrace(); 
      } 
     } 
      //當快取區不為空的時候,就可以喚醒所有的wait的消費者執行緒或者生產者執行緒
      queue.notifyAll(); 
    } 
   } 
  } 
} 

所以從以上可以看出,notify()實際上是可以實現執行緒間通訊,可以在一個執行緒裡通知喚醒另一個執行緒裡的wait,實質上也是因為他們 wait和notify操作的是同一物件,這也是因為wait和notify是相對於Object的。

這就是利用wait和notify實現生產者和消費者問題。