JDK1.5 添加了一个新的多线程同步包 : java.util.concurrent.*。利用其中的 Semaphore 类我们可以
用 JAVA 比较简单的实现生产者-消费者问题,比之前单纯用 synchronized/notify/wait 要简单很多。
本文模拟 2 个生产者和 3 个消费者并发执行的情况,使用两个 Semaphore 分别控制缓冲区的满和空。
共享缓冲区的同步操作仍然用 synchronized 操作。
下面是源代码:
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Semaphore;
/*
* main program that tests the multiple producers and multiple consumers running in parallel.
*/
public class ProducerConsumer
{
// the shared buffer for both producers and consumers
// we suppose one product is a string.
public static List < String > sharedBuffer = new ArrayList < String > ();
// create 2 semaphores for the buffer full and buffer empty
// if buffer is full, all producers should wait;
// if buffer is empty, all consumers should wait.
public static Semaphore semaphoreBufFull = new Semaphore( 5 );
public static Semaphore semaphoreBufEmpty = new Semaphore( 0 );
public static void main(String[] args)
{
try
{
// create and start 2 producers thread
for ( int i = 0 ; i < 2 ; i ++ )
{
Producer producer = new Producer(i);
producer.start();
Thread.sleep( 1000 );
}
// wait for 5 seconds
Thread.sleep( 5000 );
// create and start 3 consumers thread
for ( int i = 0 ; i < 3 ; i ++ )
{
Consumer consumer = new Consumer(i);
consumer.start();
}
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/*
* This is the producer class that extends Thread.
*/
class Producer extends Thread
{
private int id;
public Producer( int id )
{
this .id = id;
}
public void run()
{
while ( true )
{
// create a new product
Calendar cal = Calendar.getInstance();
Random rand = new Random(cal.getTimeInMillis());
String product = " NewProduct " + rand.nextInt( 20 );
// try to acquire a semaphore if the buffer is not full
try
{
ProducerConsumer.semaphoreBufFull.acquire();
}
catch (InterruptedException e1)
{
// TODO Auto-generated catch block
e1.printStackTrace();
}
// this producer thread is accessing the shared buffer...
List < String > buffer = ProducerConsumer.sharedBuffer;
synchronized (buffer)
{
buffer.add( product );
System.out.println( " Producer " + id + " produced one new product: " + product + " ! Buffer size= " + buffer.size() + " ! " );
}
// now we have produced a new product, let's wake up any waiting consumers
ProducerConsumer.semaphoreBufEmpty.release();
try
{
Thread.sleep( 1000 );
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
/*
* This is the consumer class that extends Thread.
*/
class Consumer extends Thread
{
private int id;
public Consumer( int id )
{
this .id = id;
}
public void run()
{
String product = null ;
while ( true )
{
// try to acquire a semaphore if the buffer is not empty
try
{
ProducerConsumer.semaphoreBufEmpty.acquire();
}
catch (InterruptedException e1)
{
// TODO Auto-generated catch block
e1.printStackTrace();
}
// this consumer thread is accessing the shared buffer...
List < String > buffer = ProducerConsumer.sharedBuffer;
synchronized (buffer)
{
int count = buffer.size();
product = buffer.get( count - 1 );
buffer.remove( count - 1 );
System.out.println( " Consumer " + id + " consumed one product: " + product + " ! " );
}
// now we have consumed a product, let's wake up any waiting producers
ProducerConsumer.semaphoreBufFull.release();
try
{
Thread.sleep( 1000 );
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
运行该代码,将打印如下输出:
Producer 0 produced one new product:NewProduct 9! Buffer size=1!
Producer 1 produced one new product:NewProduct 13! Buffer size=2!
Producer 0 produced one new product:NewProduct 19! Buffer size=3!
Producer 1 produced one new product:NewProduct 5! Buffer size=4!
Producer 0 produced one new product:NewProduct 6! Buffer size=5!
Consumer 0 consumed one product:NewProduct 6!
Producer 1 produced one new product:NewProduct 15! Buffer size=5!
Consumer 1 consumed one product:NewProduct 15!
Producer 0 produced one new product:NewProduct 16! Buffer size=5!
Consumer 2 consumed one product:NewProduct 16!
Consumer 2 consumed one product:NewProduct 5!
Consumer 0 consumed one product:NewProduct 19!
Producer 0 produced one new product:NewProduct 9! Buffer size=3!
Producer 1 produced one new product:NewProduct 9! Buffer size=4!
Consumer 1 consumed one product:NewProduct 9!
Consumer 2 consumed one product:NewProduct 9!
Consumer 0 consumed one product:NewProduct 13!
Consumer 1 consumed one product:NewProduct 9!
Producer 1 produced one new product:NewProduct 19! Buffer size=1!
Producer 0 produced one new product:NewProduct 19! Buffer size=2!
Consumer 0 consumed one product:NewProduct 19!
Consumer 2 consumed one product:NewProduct 19!
Producer 0 produced one new product:NewProduct 14! Buffer size=1!
Producer 1 produced one new product:NewProduct 14! Buffer size=2!
Consumer 1 consumed one product:NewProduct 14!
Consumer 0 consumed one product:NewProduct 14!
Producer 1 produced one new product:NewProduct 2! Buffer size=1!
Consumer 1 consumed one product:NewProduct 2!
Producer 0 produced one new product:NewProduct 2! Buffer size=1!
Consumer 2 consumed one product:NewProduct 2!
Producer 1 produced one new product:NewProduct 14! Buffer size=1!
Consumer 1 consumed one product:NewProduct 14!
可以看出,程序开始时,两个生产者线程共生产了 5 个产品。之后 3 个消费者启动后,开始消费产品。
这5 个线程并发运行。一段时间之后,我们可以看到 buffer 的 size 趋向于 1,这是因为消费者比
生产者多一个的缘故。