目標問題:生產者與消費者問題---之代碼的實現; 生產模式:2個生產者--2個消費者--一個緩衝區; 因工作需求,最近在學習java,所以就找到一些問題來練手,這就來到了生產者與消費者的問題!
具體實現代碼如下:
import java.lang.*;
public class ProducerConsumer{
public static void main(String[] args){
SyncStack ss = new SyncStack();
Producer p = new Producer(ss);
Consumer c = new Consumer(ss);
new Thread(p).start();
new Thread(p).start();
new Thread(c).start();
new Thread(c).start();
System.out.println("總共生產了: " + ss.getTotalProducts());
System.out.println("總共消費了: " + ss.getTotalConsumer());
}
}
class Product{
int id;
Product(int id){
this.id = id;
}
public String toString(){
return "Product" + id;
}
}
class SyncStack{
int index = 0;
int totalProducts = 0;
int totalConsumer = 0;
Product[] arrProduct = new Product[6];
//生產產品;
public synchronized void push(Product pd){
while(index == arrProduct.length){
try{
this.wait(); //只有鎖住這個線程了才能wait(),是Object這個類的wait;wait的時候,該鎖就屬於自己了;
}catch(InterruptedException e){
e.printStackTrace();
}
}
this.notifyAll();
arrProduct[index] = pd;
index ++;
totalProducts++;
}
//消費者消費產品;
public synchronized Product pop(){
while(0 == index){
try{
this.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
}
this.notifyAll();
index--;
totalConsumer++;
return arrProduct[index];
}
public int getRemain(){
return index;
}
public int getTotalProducts(){
return totalProducts;
}
public int getTotalConsumer(){
return totalConsumer;
}
}
class Producer implements Runnable{
SyncStack ss = null;
int ProducerNum = 20;
Thread current = Thread.currentThread();
Producer(SyncStack ss){
this.ss = ss;
}
public void run(){
for(int i = 0; i < ProducerNum; i++){
Product pd = new Product(i);
ss.push(pd);
System.out.println(current.getId() + "生產了,存入倉庫:" + pd);
try{
Thread.sleep((int)(Math.random() * 1000));
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable{
SyncStack ss = null;
int ConsumerNum = 20;
Thread current = Thread.currentThread();
Consumer(SyncStack ss){
this.ss = ss;
}
public void run(){
for(int i = 0; i < ConsumerNum; i++){
Product pd = ss.pop();
System.out.println(current.getId() + "從倉庫取出,消費了:" + pd);
System.out.println("倉庫產品還剩:" + ss.getRemain());
try{
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
}
問題解決:<1> 關係分析。生產者和消費者對緩衝區互斥訪問是互斥關係,同時生產者和消費者又是一個相互協作的關係,只有生產者生產之後,消費者才能消費,他們也是同步關係;
<2> 整理思路。這裏比較簡單,只有生產者和消費者兩個進程,正好是這兩個進程存在着互斥關係和同步關係。那麼需要解決的是互斥和同步的位置;
第一.從緩衝區取出產品和向緩衝區投放產品必須是互斥進行的,這裏用synchronized關鍵字同步鎖來實現;
第二.生產者要等待緩衝區有空間,這樣纔可以生產投放產品,消費者要等待緩衝區不爲空,這樣纔可以取出產品進行消費。主要用wait和notify來實現;
1、如果沒有wait() 和 notify() / notufyAll() 可能會產生死鎖;因爲生產滿了就停止生產,假如消費者消費完了也不提醒生產者,這樣兩個線程就都等着了,會產生死鎖!
2、while不能換成if,因爲如果倉庫滿了,這時候生產者睡眠wait,假如此時來了一個異常,這樣程序就會繼續執行,但是倉庫還是滿的,因爲消費者沒有消費,所以這時會產生溢出;
3、wait 和sleep的區別:
wait:如果加鎖了,別人可以訪問鎖定的對象;父類是object
sleep:加鎖了,不釋放,別人不能訪問其鎖定的對象;
運行結果: