为什么生产者-消费者代码不起作用?

Why Producer-Consumer code is not working?

我正在尝试在信号量的帮助下编写解决生产者-消费者问题的代码。 下面是我写的代码,执行时产生一个数字就卡住了。

我检查了两个信号量的分配,看起来没问题。 调用获取和释放方法的顺序看起来也是正确的。

public class Q {
    int n;
    Semaphore consumerSem = new Semaphore(0);
    Semaphore producerSem = new Semaphore(1);

    synchronized void get(){
        try {
            consumerSem.acquire();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Got Data : " + n);
        producerSem.release();
    }

    synchronized void put(int n){
        try {
            producerSem.acquire();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Putting Data : " + n);
        this.n=n;
        consumerSem.release();
    }
}

 public class Producer implements Runnable{
   Q q;

    Producer(Q q){
        this.q = q;
    }

    @Override
    public void run() {
        for (int i=0; i<20;i++){
            q.put(i);
        }
    }
}

public class Consumer implements Runnable{
    Q q;

    Consumer(Q q){
        this.q = q;
    }


    @Override
    public void run() {
           for (int i =0;i<20;i++){
               q.get();
           }
    }
}

public class PCRun {

    public static void main(String[] args) {
        Q q = new Q();
        new Thread(new Producer(q),"Producer").start();
        new Thread(new Consumer(q),"Consumer").start();
    }
}

您已取得 getput synchronized。因此生产者进入,锁定 q,使用 producerSem 的一个许可并在下一个 put 调用时阻塞。不幸的是,q 仍然被生产者锁定,因此消费者将无法输入 get。要解决此问题,请删除两个 synchronizeds.

现在要同步对 n 的访问,仅使用 synchronized 其中 n 被访问,而不是用于整个方法。

    int n;
    final Semaphore consumerSem = new Semaphore(0);
    final Semaphore producerSem = new Semaphore(1);

    void get() {
        try {
            consumerSem.acquire();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized (this) {
            System.out.println("Got Data : " + n);
        }
        producerSem.release();
    }

    void put(int n) {
        try {
            producerSem.acquire();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized (this) { // invariant print + write, atomic
            System.out.println("Putting Data : " + n);
            this.n = n;
        }
        consumerSem.release();
    }

不要使用 2 个信号量,而只使用 1 个。n 的值最终将在 2 个线程之间共享,因此它是唯一需要同步的东西,因为信号量本质上是 thread-safe。

    public static class Q {

        int n;

        Semaphore available = new Semaphore(0);

        void get() throws InterruptedException {
            available.acquire();
            synchronized (this) {
                System.out.printf("Get %s\n", n));
            }
        }

        void put(int n){
            available.release();
            synchronized (this) {
                System.out.printf("Put %s\n", n);
                this.n = n;
            }
        }
    }