为什么我的制作人消费者陷入僵局(或活锁)?

时间:2017-11-01 15:10:46

标签: java multithreading concurrency

我正在尝试使用重入锁来实现典型的生产者使用者。 生产者线程打印偶数和消费者线程打印奇数。 这是我的代码,但由于某种原因它是死锁 可运行的任务

public class EvenPrinterRunnable  implements Runnable {
    SharedBuffer buf;
    public EvenPrinterRunnable(SharedBuffer buf) {
        this.buf = buf;

        Thread.currentThread().setName("Even Runnable");
    }

    @Override
    public void run() {

        for(int i = 0; i < 10; i++) {
            buf.printEven();
        }

    }
}

public class OddPrinterRunnable implements Runnable {
    SharedBuffer buf;
    public OddPrinterRunnable(SharedBuffer buf){
        this.buf = buf;
        Thread.currentThread().setName("ODD Runnable");
    }

    @Override
    public void run(){
        for(int i = 0; i < 10; i++){
            buf.printOdd();
        }
    }
}

共享缓冲区

public class SharedBuffer {
    Lock lock = new ReentrantLock();

    Condition evenNotPrinted = lock.newCondition();
    Condition oddNotPrinted  = lock.newCondition();

    int currentNumber = 0;

    public void printEven() {
        System.out.println("from even");
        try {
            lock.lock();
            try {
                oddNotPrinted.await();
            }
            catch(InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(" being printed by thread " + "" + Thread.currentThread().getName() + " "+ currentNumber);
            currentNumber++;
            evenNotPrinted.signalAll();
        }
        finally {
            lock.unlock();
        }
    }

    public void printOdd() {
        System.out.println("from odd");
        try {
            lock.lock();
            try {
                evenNotPrinted.await();
            }
            catch(InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(" being printed by thread " + "" + Thread.currentThread().getName() + " "+ currentNumber);
            currentNumber++;
            oddNotPrinted.signalAll();
        }
        finally {
            lock.unlock();
        }
    }
}

驱动程序类

public class OddEvenDriver {
    public static void main(String[] args) {

        //using runnables with lock buffer

        SharedBuffer buf1 = new SharedBuffer();
        EvenPrinterRunnable epr = new EvenPrinterRunnable(buf1);
        OddPrinterRunnable opr = new OddPrinterRunnable(buf1);

        ExecutorService es = Executors.newFixedThreadPool(2);
        es.submit(opr);
        es.submit(epr);
        es.shutdown();
    }
}

正在输出

from even
from odd

from odd
from even

这意味着每个线程都在获取锁定,然后等待条件evenNotPrinted和oddNotPrinted,并且由于在调用信号之前没有任何一个可以继续进行,所以我的问题是,我应该在开始时发出每个条件的信号。方法本身? 我在这里缺少什么

1 个答案:

答案 0 :(得分:2)

  

所以我的问题是,我应该在方法本身的开头发出每个条件的信号吗?

没有。那不行。条件变量不记得先前在线程调用condition.await()时发出信号。除非某些其他线程已在等待信号,否则condition.signal()condition.signalAll()函数根本不会执行任何操作。

条件变量是一种低级同步机制,旨在以非常特定的方式用于实现队列和信号量以及其他更高级别的同步对象。 Guarded Blocks tutorial详细解释了它。 (注意:该教程讨论了object.wait()object.notify()以及synchronized块,但这些概念都直接映射到LockCondition个对象。)

您的基本问题是您的两个线程彼此之间不能完全对称。其中一个必须先 。你的main()线程必须唤醒其中一个,或者用一个参数说“你是第一个”来构造一个。