標籤:sync log 使用 containe col obj 寫法 start notify
在電腦領域中,生產者-消費者問題(也叫bounded-buffer問題)是一類很經典的多進程同步問題。該問題描述了兩類進程,即生產者進程和消費者進程,它們共用一個固定大小的緩衝區作為隊列。生產者的任務是產生資料,並放到緩衝區中;同時消費者會消費資料(或者說將資料從緩衝區中移走)。每次生產或者消費資料的個數都是一個。在解決該問題時要確保當緩衝區滿了之後,不會再向其中添加資料;當緩衝區為空白的時候,消費者不能從中提取資料。
當緩衝區滿了時,生產者要麼進入休眠狀態,要麼丟棄產生的資料。等到下次消費者從緩衝區中移走一項資料之後,要通知生產者繼續往緩衝區中添加資料。同樣的,當消費者發現緩衝區為空白時,消費者進入休眠狀態。當生產者往緩衝區中寫入資料之後,生產者要喚醒消費者來消費資料。該問題可以通過處理序間通訊來解決,典型的做法是使用訊號量。如果該問題解決不當會導致死結,即生產者和消費者都處於等待喚醒的狀態。
這裡參考了網上的寫法,寫了一個很簡單的版本。有4個檔案:
1. 容器,Container.java
2. 生產者,Producer.java
3. 消費者,Consumer.java
4. 測試檔案,Test.java
Producer.java
package com.tuhooo.practice.pcmodel;/** * 生產者 */public class Producer implements Runnable { private Container<Integer> container; private Object producerMonitor; private Object consumerMonitor; Producer(Container<Integer> container, Object producerMonitor, Object consumerMonitor) { this.container = container; this.producerMonitor = producerMonitor;/*生產者的鎖*/ this.consumerMonitor = consumerMonitor;/*消費者的鎖*/ } public void run() { while (true) { produce(); } } private void produce() { if (container.isFull()) { synchronized (producerMonitor) { try { if (container.isFull()) { producerMonitor.wait(); } } catch (InterruptedException e) { e.printStackTrace(); } } } else { synchronized (producerMonitor) { if (!container.isFull()) { container.add(0); try { Thread.currentThread().sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("生產者【" + Thread.currentThread().getId() + "】生產了一個, 一共" + container.getSize() + "個"); } } } if (!container.isEmpty()) { synchronized (consumerMonitor) { if (!container.isEmpty()) { consumerMonitor.notify(); } } } }}
Consumer.java
package com.tuhooo.practice.pcmodel;/** * 消費者 */public class Consumer implements Runnable { private Container<Integer> container; private Object producerMonitor; private Object consumerMonitor; Consumer(Container<Integer> container, Object producerMonitor, Object consumerMonitor) { this.container = container; this.producerMonitor = producerMonitor;/*生產者的鎖*/ this.consumerMonitor = consumerMonitor;/*消費者的鎖*/ } public void run() { while (true) { consume(); } } /*消費方法怎麼寫*/ private void consume() { if (container.isEmpty()) { //消費者掛起 synchronized (consumerMonitor) { try { if (container.isEmpty()) { consumerMonitor.wait(); } } catch (InterruptedException e) { e.printStackTrace(); } } } else { synchronized (consumerMonitor) { if (!container.isEmpty()) { container.get(); try { Thread.currentThread().sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("消費者【" + Thread.currentThread().getId() + "】消費了一個, 還有" + container.getSize() + "個"); } } } if (!container.isFull()) { synchronized (producerMonitor) { if (!container.isFull()) { producerMonitor.notify(); } } } }}
Container.java
package com.tuhooo.practice.pcmodel;import java.util.LinkedList;import java.util.List;/** * 容器 */public class Container<T> { private int capacity; private List<T> list; public Container(int capacity) { this.capacity = capacity; list = new LinkedList<T>(); } /*往容器中添加*/ public synchronized boolean add(T product) { if(list.size() < capacity) { list.add(product); return true; } return false; } /*從容器中取*/ public synchronized T get() { if(list.size() > 0) { list.remove(0); } return null; } /*判斷是否是滿的*/ public boolean isFull() { return list.size() >= capacity; } public boolean isEmpty() { return list.size() == 0; } public synchronized int getSize() { return list.size(); } public int getCapacity() { return this.capacity; }}
Container有點坑的地方就是不知道什麼時候應該加synchronized
Test.java
package com.tuhooo.practice.pcmodel;public class Test { public static void main(String[] args) { Container<Integer> container = new Container<Integer>(10); Object producerMonitor = new Object(); Object consumerMonitor = new Object(); Thread p1 = new Thread(new Producer(container, producerMonitor, consumerMonitor)); Thread p2 = new Thread(new Producer(container, producerMonitor, consumerMonitor)); Thread c1 = new Thread(new Consumer(container, producerMonitor, consumerMonitor)); Thread c2 = new Thread(new Consumer(container, producerMonitor, consumerMonitor)); p1.start(); p2.start(); c1.start(); c2.start(); }}
目前先就這麼寫,暫時運行起來沒啥問題,如果有問題懇請各位看官指出。
有待改進地方:
1. Container有沒有更好的實現方法
2. Container可以有多個,這樣的話可以隨機找到一個可用的Container分配給Producer或者Consumer用
3. 感覺代碼中有好多的synchronized,感覺效能不是很好
生產者和消費者問題學習以及Java實現