Java线程同步实例 生产者 消费者问题分析
- 实例
生产者消费者问题:
package thread.wait.notify;
public class Test1 {
public static void main(String []args) {
SynStack synStack=new SynStack();
Producer producer=new Producer(synStack);
Consumer consumer=new Consumer(synStack);
new Thread(producer, "producer").start();
new Thread(consumer,"consumer").start();
}
}
class Wotou{
int id;
Wotou(int id ){
this.id=id;
}
}
class Producer implements Runnable{
SynStack synStack;
public Producer(SynStack synStack) {
this.synStack=synStack;
}
public void run(){
System.out.println("producer开始生产馒头");
for(int i=1;i<=20;i++){
Wotou wotou=new Wotou(i);
synStack.push(wotou);
System.out.println("producer生产馒头"+wotou.id);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable {
SynStack synStack;
public Consumer(SynStack synStack) {
this.synStack=synStack;
}
public void run(){
System.out.println("consumer开始吃馒头");
for(int i=1;i<=20;i++){
Wotou w=synStack.pop();
System.out.println("consumer吃馒头"+w.id);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class SynStack{
int index=0;
Wotou [] wotous=new Wotou[10];
synchronized void push(Wotou wotou){
if(index==wotous.length){
try {
System.out.println("当前有"+index+"个馒头,吃了后才能生产,等待吃。。。");
wait();
System.out.println("当前有"+index+"个馒头,等待结束。。。");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
notify();
wotous[index]=wotou;
index++;
}
synchronized Wotou pop(){
if(index==0){
try {
System.out.println("当前有"+index+"个馒头,生产后了才能吃,等待生产。。。");
wait();
System.out.println("当前有"+index+"个馒头,生产完毕。。。");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
notify();
index--;
return wotous[index];
}
}
把main函数改为下面代码,即增加2个消费者:
public static void main(String []args) {
SynStack synStack=new SynStack();
Producer producer=new Producer(synStack);
Consumer consumer=new Consumer(synStack);
new Thread(producer, "producer").start();
new Thread(consumer,"consumer").start();
Consumer consumer2=new Consumer(synStack);
Consumer consumer3=new Consumer(synStack);
new Thread(consumer2,"consumer2").start();
new Thread(consumer3,"consumer3").start();
}
运行之后发现会报下面的错误:
报错原因:当producer生产第一个馒头之前,馒头数为0,consumer,consumer2,consumer3都在wait,当producer生产了第一个馒头,会执行一次notify,在这个例子notify了consumer3的wait,所以 consumer3吃了馒头,consumer3吃完后,又会执行notify,而此时wait的包括了consumer,consumer2,因为馒头为0,notify他们其中之一后,馒头为-1,当然会报错。改进方法:把pop函数的if改为while即可,如果当前馒头为0,则再进入wait状态:
synchronized Wotou pop(){
while(index==0){
try {
System.out.println(Thread.currentThread().getName()+" 当前有"+index+"个馒头,生产后了才能吃,等待生产。。。");
wait();
System.out.println(Thread.currentThread().getName()+" 当前有"+index+"个馒头,生产完毕。。。");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
notify();
index--;
return wotous[index];
}
同理,如果有很多生产者,也需要把push中if改为while。