淺談Java簡單實現的生產者與消費者問題


一、面對生產者和消費者的問題,首先我們得明白幾點

生產者:生產數據;
消費者:消費數據。
消費者在沒有數據可供消費的情況下,不能消費;
生產者在原數據沒有被消費掉的情況下,不能生產新數據。
假設,數據空間只有一個。
實際上,如果實現了正確的生產和消費,則,兩個線程應該是嚴格的交替執行。

synchronized關鍵字若用在代碼中,形成一個同步塊,且,必須要執行鎖:
    synchronized (鎖對象) {
        同步塊
    }
同步塊使得鎖對象稱為thread monitor
二、代碼實現:

1.首先我們建立一個生產者和消費者共同擁有的鎖的類:

1 package com.mec.about_procuder_customer.core;
2 
3 public class ProcuderCustomer {
4     //初始狀態的數據為0個
5     protected static volatile int count = 0;
6     //執行鎖
7     protected final static Object lock = new Object();
8 }

上述代碼有一個關鍵字volatile,它是保證線程之間有序的一種方式,最重要也是最直接的是禁止寄存器優化。就是如果線程run方法中只是一個循環,並沒有執行語句,那么,這個線程將不會執行。

2.我們再來建立一個生產者的類:

 

 1 package com.mec.about_procuder_customer.core;
 2 
 3 //生產者
 4 public class Procuder extends ProcuderCustomer implements Runnable {
 5     
 6     //存放數據的空間
 7     private int[] dataSpace;
 8     
 9     public Procuder(int[] dataSpace, String threadName) {
10         this.dataSpace = dataSpace;
11         //啟動線程
12         new Thread(this, threadName).start();
13     }
14     
15     @Override
16     public void run() {
17         int i = 0;
18         
19         while (true) {
20             synchronized (lock) {
21                 //判斷是否空間已滿
22                 if (count < dataSpace.length) {
23                     //產生者放數據
24                     dataSpace[count] = i++;
25                     System.out.println("[" + Thread.currentThread().getName()
26                             + "]線程生產了一個數:" + dataSpace[count++]
27                             + " " + count);
28                     try {
29                         //只是為了看的清楚,沉睡2秒
30                         Thread.sleep(200);
31                     } catch (InterruptedException e) {
32                         e.printStackTrace();
33                     }
34                     //喚醒消費者
35                     lock.notify();
36                 } else {
37                     try {
38                         //使自己處於阻塞狀態
39                         lock.wait();
40                     } catch (InterruptedException e) {
41                     e.printStackTrace();
42                     }
43                 }
44             }
45         }
46     }
47 }

 

3.建立消費者的類:

 1 package com.mec.about_procuder_customer.core;
 2 
 3 //消費者
 4 public class Customer extends ProcuderCustomer implements Runnable {
 5     //存放數據的空間
 6     private int[] dataSpace;
 7     
 8     public Customer(int[] dataSpace, String threadName) {
 9         this.dataSpace = dataSpace;
10         //啟動線程
11         new Thread(this, threadName).start();
12     }
13     
14     @Override
15     public void run() {
16         while (true) {
17             //加鎖
18             synchronized (lock) {
19                 //判斷是否有數據
20                 if (count > 0) {
21                     System.out.println("[" + Thread.currentThread().getName()
22                             + "]線程消費了一個數:" + dataSpace[--count]);
23                     //喚醒生產者
24                     lock.notifyAll();
25                 } else {
26                     try {
27                         //使自己處於阻塞狀態
28                         lock.wait();
29                     } catch (InterruptedException e) {
30                         e.printStackTrace();
31                     }
32                 }
33             }
34         }
35     }
36 
37 }

4.測試類

 1 package com.mec.about_procuder_customer.test;
 2 
 3 import com.mec.about_procuder_customer.core.Customer;
 4 import com.mec.about_procuder_customer.core.Procuder;
 5 
 6 public class Test {
 7 
 8     public static void main(String[] args) {
 9         int[] data = new int[10];
10         new Procuder(data, "生產者1");
11         new Procuder(data, "生產者2");
12         new Customer(data, "消費者");
13     }
14 
15 }

運行結果:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM