利用 java.util.concurrent.Semaphore 实现生产者-消费者问题

JDK1.5 添加了一个新的多线程同步包 : java.util.concurrent.*。利用其中的 Semaphore 类我们可以

用 JAVA 比较简单的实现生产者-消费者问题,比之前单纯用 synchronized/notify/wait 要简单很多。

本文模拟 2 个生产者和 3 个消费者并发执行的情况,使用两个 Semaphore 分别控制缓冲区的满和空。

共享缓冲区的同步操作仍然用 synchronized 操作。

下面是源代码:

 

代码
package com.zxn.test.threading;

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,这是因为消费者比

生产者多一个的缘故。

posted @ 2010-06-28 23:14  coding_rabbit  阅读(1011)  评论(0编辑  收藏  举报