/*@author shijin
* 生產者與消費者模型中,要保證以下幾點:
* 1 同一時間內隻能有一個生產者生產 生產方法加鎖sychronized
* 2 同一時間內隻能有一個消費者消費 消費方法加鎖sychronized
* 3 生產者生產的同時消費者不能消費 生產方法加鎖sychronized
* 4 消費者消費的同時生產者不能生產 消費方法加鎖sychronized
* 5 共享空間空時消費者不能繼續消費 消費前循環判斷是否為空,空的話將該線程wait,釋放鎖允許其他同步方法執行
* 6 共享空間滿時生產者不能繼續生產 生產前循環判斷是否為滿,滿的話將該線程wait,釋放鎖允許其他同步方法執行
*/
//主類
class ProducerConsumer
{
public static void main(String[] args)
{
StackBasket s = new StackBasket();
Producer p = new Producer(s);
Consumer c = new Consumer(s);
Thread tp = new Thread(p);
Thread tc = new Thread(c);
tp.start();
tc.start();
}
}
//
class Mantou
{
private int id;
Mantou(int id){
this.id = id;
}
public String toString(){
return "Mantou :" + id;
}
}
//共享棧空間
class StackBasket
{
Mantou sm[] = new Mantou[6];
int index = 0;
/**
* show 生產方法.
* show 該方法為同步方法,持有方法鎖;
* show 首先循環判斷滿否,滿的話使該線程等待,釋放同步方法鎖,允許消費;
* show 當不滿時首先喚醒正在等待的消費方法,但是也隻能讓其進入就緒狀態,
* show 等生產結束釋放同步方法鎖後消費才能持有該鎖進行消費
* @param m 元素
* @return 沒有返回值
*/
public synchronized void push(Mantou m){
try{
while(index == sm.length){
System.out.println("!!!!!!!!!生產滿瞭!!!!!!!!!");
this.wait();
}
this.notify();
}catch(InterruptedException e){
e.printStackTrace();
}catch(IllegalMonitorStateException e){
e.printStackTrace();
}
sm[index] = m;
index++;
System.out.println("生產瞭:" + m + " 共" + index + "個饅頭");
}
/**
* show 消費方法
* show 該方法為同步方法,持有方法鎖
* show 首先循環判斷空否,空的話使該線程等待,釋放同步方法鎖,允許生產;
* show 當不空時首先喚醒正在等待的生產方法,但是也隻能讓其進入就緒狀態
* show 等消費結束釋放同步方法鎖後生產才能持有該鎖進行生產
* @param b true 表示顯示,false 表示隱藏
* @return 沒有返回值
*/
public synchronized Mantou pop(){
try{
while(index == 0){
System.out.println("!!!!!!!!!消費光瞭!!!!!!!!!");
this.wait();
}
this.notify();
}catch(InterruptedException e){
e.printStackTrace();
}catch(IllegalMonitorStateException e){
e.printStackTrace();
}
index–;
System.out.println("消費瞭:———" + sm[index] + " 共" + index + "個饅頭");
return sm[index];
}
}
class Producer implements Runnable
{
StackBasket ss = new StackBasket();
Producer(StackBasket ss){
this.ss = ss;
}
/**
* show 生產進程.
*/
public void run(){
for(int i = 0;i < 20;i++){
Mantou m = new Mantou(i);
ss.push(m);
// System.out.println("生產瞭:" + m + " 共" + ss.index + "個饅頭");
// 在上面一行進行測試是不妥的,對index的訪問應該在原子操作裡,因為可能在push之後此輸出之前又消費瞭,會產生輸出混亂
try{
Thread.sleep((int)(Math.random()*500));
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable
{
StackBasket ss = new StackBasket();
Consumer(StackBasket ss){
this.ss = ss;
}
/**
* show 消費進程.
*/
public void run(){
for(int i = 0;i < 20;i++){
Mantou m = ss.pop();
// System.out.println("消費瞭:———" + m + " 共" + ss.index + "個饅頭");
// 同上 在上面一行進行測試也是不妥的,對index的訪問應該在原子操作裡,因為可能在pop之後此輸出之前又生產瞭,會產生輸出混亂
try{
Thread.sleep((int)(Math.random()*1000));
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
}
摘自 shijinupc的專欄