使用Lock in Java的制作人和消费者

时间:2015-10-08 21:15:44

标签: java multithreading

我从here获得了示例。但他们只是逐个实施这个例子。平均第一个产生的整数然后混淆并编程停止。

以下是原始示例:

class ProducerConsumerImpl {
    // producer consumer problem data
    private static final int CAPACITY = 10;
    private final Queue queue = new LinkedList<>();
    private final Random theRandom = new Random();

    // lock and condition variables
    private final Lock aLock = new ReentrantLock();
    private final Condition bufferNotFull = aLock.newCondition();
    private final Condition bufferNotEmpty = aLock.newCondition();

    public void put() throws InterruptedException {
        aLock.lock();
        try {
            while (queue.size() == CAPACITY) {
                System.out.println(Thread.currentThread().getName()
                        + " : Buffer is full, waiting");
                bufferNotEmpty.await();
            }

            int number = theRandom.nextInt();
            boolean isAdded = queue.offer(number);
            if (isAdded) {
                System.out.printf("%s added %d into queue %n", Thread
                        .currentThread().getName(), number);

                // signal consumer thread that, buffer has element now
                System.out.println(Thread.currentThread().getName()
                        + " : Signalling that buffer is no more empty now");
                bufferNotFull.signalAll();
            }
        } finally {
            aLock.unlock();
        }
    }

    public void get() throws InterruptedException {
        aLock.lock();
        try {
            while (queue.size() == 0) {
                System.out.println(Thread.currentThread().getName()
                        + " : Buffer is empty, waiting");
                bufferNotFull.await();
            }

            Integer value = queue.poll();
            if (value != null) {
                System.out.printf("%s consumed %d from queue %n", Thread
                        .currentThread().getName(), value);

                // signal producer thread that, buffer may be empty now
                System.out.println(Thread.currentThread().getName()
                        + " : Signalling that buffer may be empty now");
                bufferNotEmpty.signalAll();
            }

        } finally {
            aLock.unlock();
        }
    }
}

之后我修改代码并使其工作,如, 前10个生成,然后10个消耗,循环运行直到程序终止。 这是我修改过的代码:

class ProducerConsumerImpl {
    // producer consumer problem data
    private static final int CAPACITY = 10;
    private final Queue<Integer> queue = new LinkedList<>();
    private final Random theRandom = new Random();

    // lock and condition variables
    private final Lock aLock = new ReentrantLock();
    private final Condition bufferNotFull = aLock.newCondition();
    private final Condition bufferNotEmpty = aLock.newCondition();

    public void put() throws InterruptedException {
        aLock.lock();
        try {
            while(true){
                while (queue.size() == CAPACITY) {
                    System.out.println(Thread.currentThread().getName()
                            + " : Buffer is full, waiting");

                    bufferNotEmpty.await();
                }

                int number = theRandom.nextInt();
                boolean isAdded = queue.offer(number);
                if (isAdded) {
                    System.out.printf("%s added %d into queue %n", Thread
                            .currentThread().getName(), number);
                }
               bufferNotFull.signalAll();
            }

        } finally {
            aLock.unlock();
        }
    }

    public void get() throws InterruptedException {
        aLock.lock();
        try {
            while(true){
                while (queue.size() == 0) {
                    System.out.println(Thread.currentThread().getName()
                            + " : Buffer is empty, waiting");
                    bufferNotFull.await();
                }

                Integer value = (Integer)queue.poll();
                if (value != null) {
                    System.out.printf("%s consumed %d from queue %n", Thread
                            .currentThread().getName(), value);
                }
                bufferNotEmpty.signalAll();
            }

        } finally {
            aLock.unlock();
        }
    }
}

修改它的工作正常后,产生10个随机整数,然后一次又一次地消耗这些整数,直到程序存在/终止。但由于我不是并发的主人/专家。

所以我想问一下我的修改过的代码有什么问题吗?

我在bufferNotFull.signalAll();bufferNotEmpty.signalAll();展示位置感到有问题,因为每次都可以通知等待线程。

如果有问题那我怎么解决?或者如果一切正常,那么请清除bufferNotFull.signalAll(); and bufferNotEmpty.signalAll(); placement, because that could notify waiting thread each time.混乱。

注意:这只是获取和设置代码。(生产和消费)

修改代码的输出:

PRODUCER added 1062016967 into queue 
PRODUCER added 1204607478 into queue 
PRODUCER added 1865840177 into queue 
PRODUCER added -1279321362 into queue 
PRODUCER added -190570442 into queue 
PRODUCER added -1344361101 into queue 
PRODUCER added 609239106 into queue 
PRODUCER added -1480451794 into queue 
PRODUCER added 1905208395 into queue 
PRODUCER added -420578734 into queue 
PRODUCER : Buffer is full, waiting
CONSUMER consumed 1062016967 from queue 
CONSUMER consumed 1204607478 from queue 
CONSUMER consumed 1865840177 from queue 
CONSUMER consumed -1279321362 from queue 
CONSUMER consumed -190570442 from queue 
CONSUMER consumed -1344361101 from queue 
CONSUMER consumed 609239106 from queue 
CONSUMER consumed -1480451794 from queue 
CONSUMER consumed 1905208395 from queue 
CONSUMER consumed -420578734 from queue 
CONSUMER : Buffer is empty, waiting
PRODUCER added 1917580670 into queue 
so on.........

被修改 在考虑了性能后,我决定在put语句之前添加if getsignalall();方法中的条件。 (我认为它可以提高性能甚至0.000000Something)但是中断await();可能是deadlock();任何帮助?

对于制片人:

if(queue.size() == CAPACITY){
bufferNotFull.signalAll();
}

对于消费者:

if(queue.size() == 0){
bufferNotEmpty.signalAll();
}

1 个答案:

答案 0 :(得分:1)

修改后的代码没问题。

关于在不需要时调用.singnalAll()调用可能的性能优化:仅当条件从false更改为true 时,发出信号就足够了

对于制作人,您可以使用:

if(isAdded && queue.size() == 1) {
    /*
     * Element has been *actually added* *into empty queue*
     * (previously .size() = 0), thus *queue become non-empty*.
     */
    bufferNotFull.signalAll();
}

对于消费者,您可以使用:

if(value && queue.size() == CAPACITY - 1) {
    /*
     * Element has been *actually consumed* *from full queue*
     * (previousely .size() = CAPACITY), thus *queue become non full*.
     */
    bufferNotEmpty.signalAll();
}

注意,这样你就不会消除对服务员不必要的通知(例如,消费者只能等待空队列的元素,因此只添加第一个元素就会唤醒它)。相反,当明确知道没有线程等待它时(例如,消费者不能在非空队列中等待),您将消除对.notifyAll()的调用。