一生产多消费
例子:
/**
* 一生产多消费
*/
public class Run2 {
public static void main(String[] args) {
MyStack myStack=new MyStack();
P1 p1=new P1(myStack);
C1 c1=new C1(myStack);
C1 c2=new C1(myStack);
C1 c3=new C1(myStack);
C1 c4=new C1(myStack);
C1 c5=new C1(myStack);
P_Thread1 p_thread1=new P_Thread1(p1);
p_thread1.start();
C_Thread1 c_thread1=new C_Thread1(c1);
C_Thread1 c_thread2=new C_Thread1(c2);
C_Thread1 c_thread3=new C_Thread1(c3);
C_Thread1 c_thread4=new C_Thread1(c4);
c_thread1.start();
c_thread2.start();
c_thread3.start();
c_thread4.start();
}
}
/**
* 生产者
*/
class P1{
private MyStack myStack;
public P1(MyStack myStack) {
this.myStack = myStack;
}
public void push(){
myStack.push();
}
}
/**
* 生产者线程
*/
class P_Thread1 extends Thread{
private P1 p1;
public P_Thread1(P1 p1) {
super();
this.p1 = p1;
}
@Override
public void run() {
while(true){
p1.push();
}
}
}
class C_Thread1 extends Thread{
private C1 c1;
public C_Thread1(C1 c1) {
super();
this.c1 = c1;
}
@Override
public void run() {
while (true){
c1.pop();
}
}
}
/**
* 消费者
*/
class C1{
private MyStack myStack;
public C1(MyStack myStack) {
this.myStack = myStack;
}
public void pop(){
myStack.pop();
}
}
class MyStack{
private List list=new ArrayList();
synchronized public void push(){
try {
if(list.size()==1){
this.wait();
}
list.add("anyString="+Math.random());
this.notify();
System.out.println("push="+list.size());
}catch (InterruptedException e) {
e.printStackTrace();
}
}
synchronized public String pop(){
String returnValue="";
try {
if(list.size()==0){
System.out.println("pop操作中的:"+Thread.currentThread().getName()+" 线程呈wait状态");
this.wait();
}
returnValue=list.get(0).toString();
list.remove(0);
this.notify();
System.out.println("pop="+list.size());
}catch (InterruptedException e) {
e.printStackTrace();
}
return returnValue;
}
}
出现的结果:
pop操作中的:Thread-3 线程呈wait状态
push=1
pop=0
pop操作中的:Thread-3 线程呈wait状态
push=1
pop=0
pop操作中的:Thread-3 线程呈wait状态
push=1
pop=0
pop操作中的:Thread-3 线程呈wait状态
push=1
pop=0
push=1
pop=0
pop操作中的:Thread-4 线程呈wait状态
pop操作中的:Thread-2 线程呈wait状态
pop操作中的:Thread-1 线程呈wait状态
pop操作中的:Thread-3 线程呈wait状态
push=1
pop=0
pop操作中的:Thread-4 线程呈wait状态
Exception in thread "Thread-2" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.rangeCheck(ArrayList.java:635)
at java.util.ArrayList.get(ArrayList.java:411)
at com.grgbanking.MyStack.pop(Run2.java:119)
at com.grgbanking.C1.pop(Run2.java:91)
at com.grgbanking.C_Thread1.run(Run2.java:74)
wait/notify一生产多消费导致有溢出问题,因为使用了
if(){
this.wait();
}
因为notify唤醒是随机唤醒,不一定唤醒到异类,有可能唤醒到同类,所以导致消费者消费多次,同时因为使用if()语句,导致只会判断一次list.size()是否等于1,直接执行下面的语句,导致list没有数据却被移除,最终就溢出了。
解决方法:使用while(),例如:
生产者:
while(list.size()==1){
this.wait();
}
消费者:
while(list.size()==0){
System.out.println("pop操作中的:"+Thread.currentThread().getName()+" 线程呈wait状态");
this.wait();
}