我们晦涩的操作系统课本也讲过 生产者-消费者问题,不过是由Pascal写的用来解决 进程 同步的,不幸的是我并没学过Pascal。考试时大家都是用C语言写的,但是我极其怀疑这些应试程序段能不能拿到项目中应用。
课本上的算法是有信号量机制实现的(不要问我什么是信号量,课本上没讲)。声明一个int变量mutex(信号量),调用wait() signal()方法 。
wait(mutex); // if(mutex==0) { 阻塞当前进程; } else ( mutex--; }
signal(mutex); // mutex++; 唤醒wait进程
Java中似乎没有类似的方法,java中线程同步是由Object的方法wait() notify() / notifyAll() 实现的。这些方法必须在同步块(Critical Section 关键字synchronized)中。
我们知道synchronized (Object o) 是拿走对象o所拥有的唯一的钥匙(具体见我的另外一篇博客http://blog.csdn.net/nyzhl/archive/2007/05/19/1617014.aspx),
而o.wait()的作用就是阻塞当前线程并且释放对象o的钥匙
o.notify()/notifyAll()的作用是唤醒对象o wait阻塞的线程,重新竞争o的钥匙。
Thead.sleep()也是阻塞当前线程,但不释放钥匙
下面是我的程序源代码,3个生产者Alice,Bob,Lucy他们向只能放一个产品的容器里放产品 2个消费者James,Charlie。他们从容器里拿产品
* Coding by ZhaoHongliang.
**/
public class ProducerConsumer ... {
public static void main(String[] args) ...{
Container container = new Container();
Producer Alice = new Producer("Alice",container);
Thread produceThread1 = new Thread(Alice);
produceThread1.start();
Producer Bob = new Producer("Bob",container);
Thread produceThread2 = new Thread(Bob);
produceThread2.start();
Producer Lucy = new Producer("Lucy",container);
Thread produceThread3 = new Thread(Lucy);
produceThread3.start();
Consumer James = new Consumer("James",container);
Thread consumeThread1 = new Thread(James);
consumeThread1.start();
Consumer Charlie = new Consumer("Charlie",container);
Thread consumeThread2 = new Thread(Charlie);
consumeThread2.start();
}
}
/**/ /* 生产者 */
class Producer implements Runnable ... {
private String name;
private Container container = null;
//Constructor
public Producer(String producerName,Container container) ...{
this.name = producerName;
this.container = container;
}
//Override abstract methoed of Interface Runnable.
public void run() ...{
while(true) ...{
synchronized(this.container) ...{
while(!this.container.isEmpty()) ...{
try ...{
this.container.wait();
}
catch (InterruptedException e) ...{
e.printStackTrace();
}
}
Product pushedProduct = new Product(this.name);
container.push(pushedProduct);
try ...{
Thread.sleep((int)(Math.random()*2000));
}
catch (InterruptedException e) ...{
e.printStackTrace();
}
this.container.notifyAll();
}
}
}
}
/**/ /* 消费者 */
class Consumer implements Runnable ... {
private String name;
private Container container = null;
//Constructor
public Consumer(String consumerName,Container container) ...{
this.name = consumerName;
this.container = container;
}
//Override abstract methoed of Interface Runnable.
public void run() ...{
while(true) ...{
synchronized (this.container) ...{
while(this.container.isEmpty()) ...{
try ...{
this.container.wait();
}
catch (InterruptedException e) ...{
e.printStackTrace();
}
}
Product popedProduct = container.pop(name);
try ...{
Thread.sleep((int)(Math.random()*1000));
}
catch (InterruptedException e) ...{
e.printStackTrace();
}
this.container.notifyAll();
}
}
}
}
/**/ /* 产品 */
class Product ... {
private static int id = 0;
//Constructor
private String producerName;
public Product(String producerName) ...{
this.producerName = producerName;
this.id ++;
}
//Override method of Class Object.
public String toString() ...{
return "Product No."+id+"; Made by "+producerName;
}
}
/**/ /* 容器 只允许放一个产品 */
class Container ... {
private Product container = null;
//Test if the container is empty.
public boolean isEmpty() ...{
if (this.container==null) ...{
return true;
}
else ...{
return false;
}
}
public synchronized void push(Product product) ...{
if (this.isEmpty()) ...{
this.container = product;
System.out.println("Pushed: "+product);
}
else ...{
throw new RuntimeException("Can't push! The container is full.");
}
}
public synchronized Product pop(String consumerName) ...{
if (!this.isEmpty()) ...{
Product temp = this.container;
this.container = null;
System.out.println(consumerName+" poped: "+temp);
return temp;
}
else ...{
throw new RuntimeException("Can't pop! The container is empty.");
}
}
}
运行结果(死循环)
Pushed: Product No.1; Made by Alice
Charlie poped: Product No.1; Made by Alice
Pushed: Product No.2; Made by Lucy
James poped: Product No.2; Made by Lucy
Pushed: Product No.3; Made by Alice
Charlie poped: Product No.3; Made by Alice
Pushed: Product No.4; Made by Bob
James poped: Product No.4; Made by Bob
Pushed: Product No.5; Made by Alice
Charlie poped: Product No.5; Made by Alice
Pushed: Product No.6; Made by Lucy
James poped: Product No.6; Made by Lucy
Pushed: Product No.7; Made by Alice
Charlie poped: Product No.7; Made by Alice
Pushed: Product No.8; Made by Bob
James poped: Product No.8; Made by Bob
Pushed: Product No.9; Made by Alice
Charlie poped: Product No.9; Made by Alice
Pushed: Product No.10; Made by Lucy
James poped: Product No.10; Made by Lucy
。。。 。。。