Java線程:併發協做-生產者消費者模型
對於多線程程序來講,無論任何編程語言,生產者和消費者模型都是最經典的。就像學習每一門編程語言同樣,Hello World!都是最經典的例子。
實際上,準確說應該是「生產者-消費者-倉儲」模型,離開了倉儲,生產者消費者模型就顯得沒有說服力了。
對於此模型,應該明確一下幾點:
一、生產者僅僅在倉儲未滿時候生產,倉滿則中止生產。
二、消費者僅僅在倉儲有產品時候才能消費,倉空則等待。
三、當消費者發現倉儲沒產品可消費時候會通知生產者生產。
四、生產者在生產出可消費產品時候,應該通知等待的消費者去消費。
此模型將要結合java.lang.Object的wait與notify、notifyAll方法來實現以上的需求。這是很是重要的。
/**
* Java線程:併發協做-生產者消費者模型
*
* @author leizhimin 2009-11-4 14:54:36
*/
public
class Test {
public
static
void main(String[] args) {
Godown godown =
new Godown(30);
Consumer c1 =
new Consumer(50, godown);
Consumer c2 =
new Consumer(20, godown);
Consumer c3 =
new Consumer(30, godown);
Producer p1 =
new Producer(10, godown);
Producer p2 =
new Producer(10, godown);
Producer p3 =
new Producer(10, godown);
Producer p4 =
new Producer(10, godown);
Producer p5 =
new Producer(10, godown);
Producer p6 =
new Producer(10, godown);
Producer p7 =
new Producer(80, godown);
c1.start();
c2.start();
c3.start();
p1.start();
p2.start();
p3.start();
p4.start();
p5.start();
p6.start();
p7.start();
}
}
/**
* 倉庫
*/
class Godown {
public
static
final
int max_size = 100;
//最大庫存量
public
int curnum;
//當前庫存量
Godown() {
}
Godown(
int curnum) {
this.curnum = curnum;
}
/**
* 生產指定數量的產品
*
* @param neednum
*/
public
synchronized
void produce(
int neednum) {
//測試是否須要生產
while (neednum + curnum > max_size) {
System.out.println(
"要生產的產品數量" + neednum +
"超過剩餘庫存量" + (max_size - curnum) +
",暫時不能執行生產任務!");
try {
//當前的生產線程等待
wait();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
//知足生產條件,則進行生產,這裏簡單的更改當前庫存量
curnum += neednum;
System.out.println(
"已經生產了" + neednum +
"個產品,現倉儲量爲" + curnum);
//喚醒在此對象監視器上等待的全部線程
notifyAll();
}
/**
* 消費指定數量的產品
*
* @param neednum
*/
public
synchronized
void consume(
int neednum) {
//測試是否可消費
while (curnum < neednum) {
try {
//當前的生產線程等待
wait();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
//知足消費條件,則進行消費,這裏簡單的更改當前庫存量
curnum -= neednum;
System.out.println(
"已經消費了" + neednum +
"個產品,現倉儲量爲" + curnum);
//喚醒在此對象監視器上等待的全部線程
notifyAll();
}
}
/**
* 生產者
*/
class Producer
extends Thread {
private
int neednum;
//生產產品的數量
private Godown godown;
//倉庫
Producer(
int neednum, Godown godown) {
this.neednum = neednum;
this.godown = godown;
}
public
void run() {
//生產指定數量的產品
godown.produce(neednum);
}
}
/**
* 消費者
*/
class Consumer
extends Thread {
private
int neednum;
//生產產品的數量
private Godown godown;
//倉庫
Consumer(
int neednum, Godown godown) {
this.neednum = neednum;
this.godown = godown;
}
public
void run() {
//消費指定數量的產品
godown.consume(neednum);
}
}
已經生產了10個產品,現倉儲量爲40
已經生產了10個產品,現倉儲量爲50
已經消費了50個產品,現倉儲量爲0
已經生產了80個產品,現倉儲量爲80
已經消費了30個產品,現倉儲量爲50
已經生產了10個產品,現倉儲量爲60
已經消費了20個產品,現倉儲量爲40
已經生產了10個產品,現倉儲量爲50
已經生產了10個產品,現倉儲量爲60
已經生產了10個產品,現倉儲量爲70
Process finished with exit code 0
說明:
對於本例,要說明的是當發現不能知足生產或者消費條件的時候,調用對象的wait方法,wait方法的做用是釋放當前線程的所得到的鎖,並調用對象的notifyAll() 方法,通知(喚醒)該對象上其餘等待線程,使得其繼續執行。這樣,整個生產者、消費者線程得以正確的協做執行。
notifyAll() 方法,起到的是一個通知做用,不釋放鎖,也不獲取鎖。只是告訴該對象上等待的線程「能夠競爭執行了,都醒來去執行吧」。
本例僅僅是生產者消費者模型中最簡單的一種表示,本例中,若是消費者消費的倉儲量達不到知足,而又沒有生產者,則程序會一直處於等待狀態,這固然是不對的。實際上能夠將此例進行修改,修改成,根據消費驅動生產,同時生產兼顧倉庫,若是倉不滿就生產,並對每次最大消費量作個限制,這樣就不存在此問題了,固然這樣的例子更復雜,更難以說明這樣一個簡單模型。
我喜歡簡單的例子。