【问题标题】:Producer/Consumer using Semaphore; getting deadlock使用信号量的生产者/消费者;陷入僵局
【发布时间】:2012-04-04 22:14:02
【问题描述】:

根据http://en.wikipedia.org/wiki/Producer-consumer_problem我想用信号量模拟P/C问题。我陷入僵局,我不知道是什么问题。

public static void main(String[] args) {
        CustomBlockingQueue blockingQueue = new CustomBlockingQueue();
        new Thread(new Producer(blockingQueue)).start();
        new Thread(new Consumer(blockingQueue)).start();
    }
}

@SuppressWarnings("serial")
class CustomBlockingQueue extends LinkedList<Object> {
    private static final int MAX_SIZE = 10;

    private Semaphore mutex = new Semaphore(1);
    private Semaphore fillCount = new Semaphore(0);
    private Semaphore emptyCount = new Semaphore(MAX_SIZE);

    @Override
    public boolean offer(Object e) {
        try {
            mutex.acquire();
        } catch (InterruptedException e2) {
            e2.printStackTrace();
        }
        boolean result = super.offer(e);
        System.out.println("offer " + size());
        try {
            fillCount.release();
            emptyCount.acquire();
            mutex.release();
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
        return result;
    }

    @Override
    public Object poll() {
        try {
            mutex.acquire();
        } catch (InterruptedException e2) {
            e2.printStackTrace();
        }
        Object result = super.poll();
        System.out.println("poll  " + size());
        try {
            emptyCount.release();
            fillCount.acquire();
            mutex.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return result;
    }
}

class Producer implements Runnable {
    private CustomBlockingQueue blockingQueue;
    private Random random = new Random();

    public Producer(CustomBlockingQueue blockingQueue) {
        this.blockingQueue = blockingQueue;
    }

    @Override
    public void run() {
        while (!Thread.currentThread().isInterrupted()) {
            try {
                TimeUnit.SECONDS.sleep(random.nextInt(2));
                blockingQueue.offer(new Object());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Consumer implements Runnable {
    private CustomBlockingQueue blockingQueue;
    private Random random = new Random();

    public Consumer(CustomBlockingQueue blockingQueue) {
        this.blockingQueue = blockingQueue;
    }

    @Override
    public void run() {
        while (!Thread.currentThread().isInterrupted()) {
            try {
                TimeUnit.SECONDS.sleep(random.nextInt(4));
                blockingQueue.poll();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

使用信号量

信号量解决了丢失唤醒呼叫的问题。在下面的解决方案中,我们使用了两个信号量,fillCount 和 emptyCount,来解决这个问题。 fillCount 是缓冲区中要读取的项目数,emptyCount 是缓冲区中可以写入项目的可用空间数。当新项目被放入缓冲区时,fillCount 会增加,而 emptyCount 会减少。如果生产者尝试在其值为 0 时减少 emptyCount,则生产者将进入睡眠状态。下次消费一个项目时,emptyCount 会增加,生产者会醒来。消费者的工作方式类似。

【问题讨论】:

  • 省心:使用线程安全队列。
  • 同意 - 这一切都在图书馆中为您实现 - 无需费力!
  • 我想自己使用信号量来解决这个问题
  • 顺便说一句 @ASD,我建议在 finally {} 块中进行 .release() 调用。

标签: java multithreading mutex semaphore


【解决方案1】:

您的锁定顺序错误:

需要报价:

        emptyCount.acquire();
        mutex.acquire();
        doModification();
        mutex.release();
        fillCount.release();

民意调查需要类似的更改:

        fillCount.acquire();
        mutex.acquire();
        doModification();
        mutex.release();
        emptyCount.release();

在您的实现中,您在等待信号量的同时持有互斥量,这会导致问题,因为其他线程可能正在等待互斥量以释放信号量。

【讨论】:

  • +1 你必须努力把这个顺序弄错 - 信号量 P-C 队列从 60 年代就开始在教室里教授,并且有几十个例子。
【解决方案2】:

您可以考虑使用 BlockingQueue 代替它来处理互斥锁并等待您的情况。

另一方面,我有一个旧页面,它演示了生产者/消费者竞争条件(与虚假中断相反)。但是我的实现不使用信号量,所以我不确定它会帮助你:

http://256stuff.com/gray/docs/misc/producer_consumer_race_conditions/

【讨论】:

  • 我知道 BlockingQueue,但我希望自己使用有意的信号量来解决这个问题。
  • 图@ASD。以为我会指出这一点。我还添加了指向我的生产者/消费者页面的链接,仅供参考。
  • 感谢您的回复,但我已经通过这种方式解决了这个问题(但与您有点不同)。
猜你喜欢
  • 2019-08-19
  • 2023-04-01
  • 2018-07-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多