1. 程式人生 > >淺談Java簡單實現的生產者與消費者問題

淺談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 }

執行結果: