java 多線程系列基礎篇(十一)之生產消費者問題

來源:互聯網
上載者:User

標籤:wait   cap   alt   容量   exception   demo   name   方法   interrupt   

1. 生產/消費者模型

生產/消費者問題是個非常典型的多線程問題,涉及到的對象包括“生產者”、“消費者”、“倉庫”和“產品”。他們之間的關係如下:
(01) 生產者僅僅在倉儲未滿時候生產,倉滿則停止生產。
(02) 消費者僅僅在倉儲有產品時候才能消費,倉空則等待。
(03) 當消費者發現倉儲沒產品可消費時候會通知生產者生產。
(04) 生產者在生產出可消費產品時候,應該通知等待的消費者去消費。

 

2. 生產/消費者實現

下面通過wait()/notify()方式實現該模型(後面在學習了線程池相關內容之後,再通過其它方式實現生產/消費者模型)。源碼如下:

  1 // Demo1.java  2 // 倉庫  3 class Depot {  4     private int capacity;    // 倉庫的容量  5     private int size;        // 倉庫的實際數量  6   7     public Depot(int capacity) {  8         this.capacity = capacity;  9         this.size = 0; 10     } 11  12     public synchronized void produce(int val) { 13         try { 14              // left 表示“想要生產的數量”(有可能生產量太多,需多此生產) 15             int left = val; 16             while (left > 0) { 17                 // 庫存已滿時,等待“消費者”消費產品。 18                 while (size >= capacity) 19                     wait(); 20                 // 擷取“實際生產的數量”(即庫存中新增的數量) 21                 // 如果“庫存”+“想要生產的數量”>“總的容量”,則“實際增量”=“總的容量”-“當前容量”。(此時填滿倉庫) 22                 // 否則“實際增量”=“想要生產的數量” 23                 int inc = (size+left)>capacity ? (capacity-size) : left; 24                 size += inc; 25                 left -= inc; 26                 System.out.printf("%s produce(%3d) --> left=%3d, inc=%3d, size=%3d\n",  27                         Thread.currentThread().getName(), val, left, inc, size); 28                 // 通知“消費者”可以消費了。 29                 notifyAll(); 30             } 31         } catch (InterruptedException e) { 32         } 33     }  34  35     public synchronized void consume(int val) { 36         try { 37             // left 表示“客戶要消費數量”(有可能消費量太大,庫存不夠,需多此消費) 38             int left = val; 39             while (left > 0) { 40                 // 庫存為0時,等待“生產者”生產產品。 41                 while (size <= 0) 42                     wait(); 43                 // 擷取“實際消費的數量”(即庫存中實際減少的數量) 44                 // 如果“庫存”<“客戶要消費的數量”,則“實際消費量”=“庫存”; 45                 // 否則,“實際消費量”=“客戶要消費的數量”。 46                 int dec = (size<left) ? size : left; 47                 size -= dec; 48                 left -= dec; 49                 System.out.printf("%s consume(%3d) <-- left=%3d, dec=%3d, size=%3d\n",  50                         Thread.currentThread().getName(), val, left, dec, size); 51                 notifyAll(); 52             } 53         } catch (InterruptedException e) { 54         } 55     } 56  57     public String toString() { 58         return "capacity:"+capacity+", actual size:"+size; 59     } 60 }  61  62 // 生產者 63 class Producer { 64     private Depot depot; 65      66     public Producer(Depot depot) { 67         this.depot = depot; 68     } 69  70     // 消費產品:建立一個線程向倉庫中生產產品。 71     public void produce(final int val) { 72         new Thread() { 73             public void run() { 74                 depot.produce(val); 75             } 76         }.start(); 77     } 78 } 79  80 // 消費者 81 class Customer { 82     private Depot depot; 83      84     public Customer(Depot depot) { 85         this.depot = depot; 86     } 87  88     // 消費產品:建立一個線程從倉庫中消費產品。 89     public void consume(final int val) { 90         new Thread() { 91             public void run() { 92                 depot.consume(val); 93             } 94         }.start(); 95     } 96 } 97  98 public class Demo1 {   99     public static void main(String[] args) {  100         Depot mDepot = new Depot(100);101         Producer mPro = new Producer(mDepot);102         Customer mCus = new Customer(mDepot);103 104         mPro.produce(60);105         mPro.produce(120);106         mCus.consume(90);107         mCus.consume(150);108         mPro.produce(110);109     }110 }

說明
(01) Producer是“生產者”類,它與“倉庫(depot)”關聯。當調用“生產者”的produce()方法時,它會建立一個線程並向“倉庫”中生產產品。
(02) Customer是“消費者”類,它與“倉庫(depot)”關聯。當調用“消費者”的consume()方法時,它會建立一個線程並消費“倉庫”中的產品。
(03) Depot是“倉庫”類,倉庫中記錄“倉庫的容量(capacity)”以及“倉庫中當前產品數目(size)”。
        “倉庫”類的生產方法produce()和消費方法consume()方法都是synchronized方法,進入synchronized方法體,意味著這個線程擷取到了該“倉庫”對象的同步鎖。這也就是說,同一時間,生產者和消費者線程只能有一個能運行。通過同步鎖,實現了對“殘酷”的互斥訪問。
       對於生產方法produce()而言:當倉庫滿時,生產者線程等待,需要等待消費者消費產品之後,生產線程才能生產;生產者線程生產完產品之後,會通過notifyAll()喚醒同步鎖上的所有線程,包括“消費者線程”,即我們所說的“通知消費者進行消費”。
      對於消費方法consume()而言:當倉庫為空白時,消費者線程等待,需要等待生產者生產產品之後,消費者線程才能消費;消費者線程消費完產品之後,會通過notifyAll()喚醒同步鎖上的所有線程,包括“生產者線程”,即我們所說的“通知生產者進行生產”。

(某一次)運行結果

Thread-0 produce( 60) --> left=  0, inc= 60, size= 60Thread-4 produce(110) --> left= 70, inc= 40, size=100Thread-2 consume( 90) <-- left=  0, dec= 90, size= 10Thread-3 consume(150) <-- left=140, dec= 10, size=  0Thread-1 produce(120) --> left= 20, inc=100, size=100Thread-3 consume(150) <-- left= 40, dec=100, size=  0Thread-4 produce(110) --> left=  0, inc= 70, size= 70Thread-3 consume(150) <-- left=  0, dec= 40, size= 30Thread-1 produce(120) --> left=  0, inc= 20, size= 50

 轉載:http://www.cnblogs.com/skywang12345/p/3480016.html

 

java 多線程系列基礎篇(十一)之生產消費者問題

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.