我们晦涩的操作系统课本也讲过 生产者-消费者问题,不过是由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.youkuaiyun.com/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
。。。 。。。