Java多线程——使用wait!notify实现生产者!消费者模式

93 阅读3分钟

场景描述:

生产者/消费者模式是进程与线程学习中相当经典的问题,在本文中场景设置如下:

有一个仓库(Repository),有若干个生产者(Producer)和若干个消费者(Consumer),生产者可以生产产品(Procuct)并存入(push)仓库,消费者可以从仓库取出(pop)并消费产品。

我希望通过使用synchronize锁机制与wait()/notifyAll()或notify()方法实现,代码如下。但实际测试中发现,当使用notify方法时,线程仅会通知最近使用的线程,时间一长就会变成仅有两个线程在实际运行。而使用notifyAll()方法时,仓库实际产品最大数量仅是创建的生产者的最大数量,却不能达到自己预先定义的最大数量,此处暂未想通。目测估计是我的线程唤醒方法调用的位置或者调用的方式有问题,正在努力解决中。



实现代码:

import java.util.ArrayList;

/**

  • 多生产者多消费者单仓库的生产者消费者模式
  • @author breezefaith

*/ class Product{ private int productId;

public Product(int productId) {
	super();
	this.productId = productId;
}

@Override
public String toString() {
	return "Product["+productId+"]";
}

}

class Repository{ private int maxSize; private ArrayList<Product> list;

public Repository(int maxSize) {
	super();
	this.maxSize = maxSize;
	list=new ArrayList&lt;&gt;(maxSize);
}
public void setMaxSize(int maxSize) {
	if(maxSize&lt;=list.size()) {
		System.err.println(&quot;New size is smaller than the original.&quot;);
		return;
	}
	ArrayList&lt;Product&gt; newList=new ArrayList&lt;&gt;(maxSize);
	newList.addAll(list);
	list=newList;
}
public int getMaxSize() {
	return maxSize;
}
public int getCurrentSize() {
	return list.size();
}
public void push(Product product) {
	list.add(product);
}
public Product pop() {
	return list.remove(0);
}

}

class Producer extends Thread{ private Repository repository; private static int productId; public Producer(Repository repository) { super(); this.repository = repository; }

public Product produce() {
	Product product=new Product(productId++);
	System.out.println(&quot;生产者 &quot;+Thread.currentThread().getName()+&quot; 生产了产品 &quot;+product+&quot;,剩余:&quot;+(repository.getCurrentSize()+1));
	return product;
}

@Override
public void run() {
	synchronized (repository) {
		try {
			while(true) {
				Thread.sleep(1000);
				if(repository.getCurrentSize()&lt;repository.getMaxSize()) {
					repository.push(produce());
				}else {
					System.err.println(&quot;Producer &quot;+Thread.currentThread().getName()+&quot; want to produce a product, but repository is full.&quot;);
				}
				repository.notifyAll();
				repository.wait();
			}
		}catch(InterruptedException e) {
			e.printStackTrace();
		}
	}
}

}

class Consumer extends Thread{ private Repository repository;

public Consumer(Repository repository) {
	super();
	this.repository = repository;
}

public Product consume() {
	Product product=repository.pop();
	System.out.println(&quot;消费者 &quot;+Thread.currentThread().getName()+&quot; 消费了产品 &quot;+product+&quot;,剩余:&quot;+repository.getCurrentSize());
	return product;
}

@Override
public void run() {
	synchronized (repository) {
		try {
			while(true) {
				Thread.sleep(1000);
				if(repository.getCurrentSize()&gt;0) {
					consume();
				}else {
					System.err.println(&quot;Consumer &quot;+Thread.currentThread().getName()+&quot; consume a product, but repository is empty.&quot;);
				}
				repository.notifyAll();
				repository.wait();
			}
		}catch(InterruptedException e) {
			e.printStackTrace();
		}
	}
}

}

public class Run {

public static void main(String[] args) {
	Repository repository=new Repository(3);
	Producer p1=new Producer(repository),
			p2=new Producer(repository),
			p3=new Producer(repository);
	p1.setName(&quot;p1&quot;);
	p2.setName(&quot;p2&quot;);
	p3.setName(&quot;p3&quot;);
	
	Consumer c1=new Consumer(repository),
			c2=new Consumer(repository);
	c1.setName(&quot;c1&quot;);
	c2.setName(&quot;c2&quot;);
	
	p1.start();
	p2.start();
	p3.start();
	c1.start();
	c2.start();
}

}



测试结果:

生产者 p1 生产了产品 Product[0],剩余:1
消费者 c1 消费了产品 Product[0],剩余:0
Consumer c2 consume a product, but repository is empty.
生产者 p3 生产了产品 Product[1],剩余:1
生产者 p2 生产了产品 Product[2],剩余:2
生产者 p3 生产了产品 Product[3],剩余:3
消费者 c2 消费了产品 Product[1],剩余:2
消费者 c1 消费了产品 Product[2],剩余:1
生产者 p1 生产了产品 Product[4],剩余:2
消费者 c1 消费了产品 Product[3],剩余:1
消费者 c2 消费了产品 Product[4],剩余:0
生产者 p3 生产了产品 Product[5],剩余:1
生产者 p2 生产了产品 Product[6],剩余:2
生产者 p3 生产了产品 Product[7],剩余:3
消费者 c2 消费了产品 Product[5],剩余:2
消费者 c1 消费了产品 Product[6],剩余:1
生产者 p1 生产了产品 Product[8],剩余:2