如何使用信号量解决消费者/生产者任务

时间:2012-03-28 11:16:09

标签: java multithreading

我有一个SimpleProducerConsumer类来说明消费者/生产者问题(我不确定它是否正确)。

public class SimpleProducerConsumer {
    private Stack<Object> stack = new Stack<Object>();
    private static final int STACK_MAX_SIZE = 10;

    public static void main(String[] args) {
        SimpleProducerConsumer pc = new SimpleProducerConsumer();
        new Thread(pc.new Producer(), "p1").start();
        new Thread(pc.new Producer(), "p2").start();
        new Thread(pc.new Consumer(), "c1").start();
        new Thread(pc.new Consumer(), "c2").start();
        new Thread(pc.new Consumer(), "c3").start();
    }

    public synchronized void push(Object d) {
        while (stack.size() >= STACK_MAX_SIZE)
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        stack.push(new Object());
        System.out.println("push " + Thread.currentThread().getName() + "    " + stack.size());
        notify();
    }

    public synchronized Object pop() {
        while (stack.size() == 0)
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        stack.pop();
        System.out.println("pop  " + Thread.currentThread().getName() + "    " + stack.size());
        notify();
        return null;
    }

    class Consumer implements Runnable {
        @Override
        public void run() {
            while (true) {
                pop();
            }
        }
    }

    class Producer implements Runnable {
        @Override
        public void run() {
            while (true) {
                push(new Object());
            }
        }
    }
}

我发现了信号量here的简单实现。 (我知道有并发包) 如何更改代码以将java对象的监视器交换到我的自定义信号量? (用信号量说明C / P问题)

信号量:

class Semaphore {
    private int counter;

    public Semaphore() {
        this(0);
    }

    public Semaphore(int i) {
        if (i < 0)
            throw new IllegalArgumentException(i + " < 0");
        counter = i;
    }

    public synchronized void release() {
        if (counter == 0) {
            notify();
        }
        counter++;
    }

    public synchronized void acquire() throws InterruptedException {
        while (counter == 0) {
            wait();
        }
        counter--;
    }
}

2 个答案:

答案 0 :(得分:2)

首先,您应该修复测试应用。 sleep()调用是什么?我可以在'Producer','Consumer'测试线程中理解它们,但为什么它们在push / pop方法中呢?此外,测试线程传输一些对象,但没有检查每个被推送的对象是否恰好弹出一次。

基于信号量的生产者 - 消费者队列相当简单。仅基于信号量的有界队列需要三个,一个初始化为零以计算队列中的对象,另一个初始化为队列大小以计算空槽,另一个初始化为1以充当互斥锁并保护队列免受多次访问。只是谷歌的“制片人消费者”。

可以使用两个队列和一个具有int计数的消息类来完成测试。使用顺序计数创建大量对象并将它们推送到一个队列,然后启动一系列线程来对两个队列周围的对象进行混洗。当你停止线程时,(好的,你还需要一个终止bool),这两个队列应该包含所有原始对象 - 没有额外的,没有短缺,也没有重复。

答案 1 :(得分:1)

将消费者与生产者分离的一般想法是在中间插入具有良好定义的并发属性的队列。

Java为此提供了BlockingQueue接口。

您的生产者和消费者必须做的唯一事情是队列中的take()put()。这也为您提供了可扩展性的优势,因为您可以根据需要添加多个生产者/消费者。