根据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递减。如果生产者尝试在其值为零时减少emptyCount,则生产者将进入休眠状态。下次使用一个项目时,emptyCount会递增,生产者会被唤醒。消费者的工作方式类似。
答案 0 :(得分:2)
您可以考虑使用BlockingQueue
代替互斥锁并等待您。
除此之外,我还有一个旧页面,它展示了生产者/消费者的竞争条件(与虚假中断相反)。但我的实现不使用信号量,所以我不确定它会对你有所帮助:
http://256stuff.com/gray/docs/misc/producer_consumer_race_conditions/
答案 1 :(得分:2)
您的锁定顺序错误:
需要提供:
emptyCount.acquire();
mutex.acquire();
doModification();
mutex.release();
fillCount.release();
民意调查需要进行类似的更改:
fillCount.acquire();
mutex.acquire();
doModification();
mutex.release();
emptyCount.release();
在你的实现中,你正在等待信号量,同时持有导致问题的互斥锁,因为另一个线程可以等待互斥锁以释放信号量。