2017-07-06 16 views
0

我一直在爲這幾個模型生產者/消費者的簡單併發Oracle問題掙扎了幾天。這是我第一次使用防護塊,等待和notifyAll。不過,我知道這些方法的作用。我不會先發生什麼步驟。我會盡力追蹤問題,因爲我可以告訴我,如果我是對的,你可以告訴我。在Java中跟蹤保護塊

  1. 生產者/消費者線程從主線程啓動。每個都被賦予相同的Drop實例。
  2. 如果客戶線程速度比生產者速度快,則它獲取內在鎖定丟棄並嘗試在一個循環中打印來自drop.take()的消息。然而,由於empty屬實,製片人沒有給消費者留言。這導致線程被掛起並且鎖定被釋放。它現在正在等待。
  3. 生產者線程在循環中調用drop.put()。它獲取內在鎖的下降並繼續該方法,因爲empty爲真,它需要爲消費者準備消息。它將empty設置爲false並存儲消息。 notifyAll()被稱爲喚醒消費者線程。生產者也在等待,因爲empty現在是錯誤的,鎖定被釋放。
  4. 由於drop.take()已收到通知,生產者對內存有固有的鎖定,因此它喚醒了方法。 Empty設置爲true,並將消息返回並打印在循環中。它現在通知生產者線程醒來,因爲它需要一條新消息。
  5. 製片人一直在等待。由於empty爲真,並且線程已被通知(並且鎖已被訪問),它現在可以喚醒併產生另一條消息。

跌落類

package Store; 
 

 
public class Drop { 
 
    // Message sent from producer 
 
    // to consumer. 
 
    private String message; 
 
    // True if consumer should wait 
 
    // for producer to send message, 
 
    // false if producer should wait for 
 
    // consumer to retrieve message. 
 
    private boolean empty = true; 
 

 
    public synchronized String take() { 
 
     // Wait until message is 
 
     // available. 
 
     while (empty) { 
 
      try { 
 
       wait(); 
 
      } catch (InterruptedException e) {} 
 
     } 
 
     // Toggle status. 
 
     empty = true; 
 
     // Notify producer that 
 
     // status has changed. 
 
     notifyAll(); 
 
     return message; 
 
    } 
 

 
    public synchronized void put(String message) { 
 
     // Wait until message has 
 
     // been retrieved. 
 
     while (!empty) { 
 
      try { 
 
       wait(); 
 
      } catch (InterruptedException e) {} 
 
     } 
 
     // Toggle status. 
 
     empty = false; 
 
     // Store message. 
 
     this.message = message; 
 
     // Notify consumer that status 
 
     // has changed. 
 
     notifyAll(); 
 
    } 
 
}

消費階層:

package Store; 
 

 
import java.util.Random; 
 

 

 
public class Consumer implements Runnable { 
 
    private Drop drop; 
 

 
    public Consumer(Drop drop) { 
 
     this.drop = drop; 
 
    } 
 

 
    public void run() { 
 
     Random random = new Random(); 
 
     for (String message = drop.take(); 
 
      ! message.equals("DONE"); 
 
      message = drop.take()) { 
 
      System.out.format("MESSAGE RECEIVED: %s%n", message); 
 
      try { 
 
       Thread.sleep(random.nextInt(5000)); 
 
      } catch (InterruptedException e) {} 
 
     } 
 
    } 
 
}

製作類:

package Store; 
 

 

 
import java.util.Random; 
 

 
public class Producer implements Runnable { 
 
    private Drop drop; 
 

 
    public Producer(Drop drop) { 
 
     this.drop = drop; 
 
    } 
 

 
    public void run() { 
 
     String importantInfo[] = { 
 
      "Mares eat oats", 
 
      "Does eat oats", 
 
      "Little lambs eat ivy", 
 
      "A kid will eat ivy too" 
 
     }; 
 
     Random random = new Random(); 
 

 
     for (int i = 0; 
 
      i < importantInfo.length; 
 
      i++) { 
 
      drop.put(importantInfo[i]); 
 
      try { 
 
       Thread.sleep(random.nextInt(5000)); 
 
      } catch (InterruptedException e) {} 
 
     } 
 
     drop.put("DONE"); 
 
    } 
 
}

主線:

public class ProducerConsumerExample { 
 
    public static void main(String[] args) { 
 
     Drop drop = new Drop(); 
 
     (new Thread(new Producer(drop))).start(); 
 
     (new Thread(new Consumer(drop))).start(); 
 
    } 
 
}

回答

0

我沒有一個完整的答案,但我有一對夫婦的意見。

包裝等待的while循環會導致異常。等待需要鎖定,但等待釋放鎖定。幸運的是,你不應該遇到這種行爲。

您可能會遇到問題,您的實例變量不會跨線程更新。你同步,然後等待。這爲這些變量提供了不同價值的機會。標記它們不穩定會對此有所幫助。

你沒有說你的代碼實際上做了什麼......

+0

我只是追蹤第一條消息的步驟,這將重複其他消息。我喜歡你所說的關於如何等待並釋放鎖定的內容。 – retchers