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

问题描述

我正在尝试通过信号量来编写生产者-消费者问题的解决方案。 下面是我编写的代码,在执行时会产生一个数字而卡住。

我已经检查了信号量的分配,看起来还不错。 调用获取和释放方法的顺序看起来也正确。

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。要解决此问题,请同时删除两个synchronized

现在要在n上同步访问,仅在访问{em> 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个线程之间共享,因此它是唯一需要同步的东西,因为信号量本质上是线程安全的。

    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;
            }
        }
    }

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...