我必须使用BlockingQueue解决生产-消费者问题。我希望它是1个元素队列。因此解决方案必须是:
生产%1消耗%1生产%2消耗%2生产%3消耗%3
但它确实是:
生产1生产2消费1消费2生产3生产4等等。
我目前使用的SynchronizedQueue是这样的:
class Producent extends Thread {
private final BlockingQueue<Integer> blockingQueue;
public Producent(BlockingQueue<Integer> blockingQueue) {
this.blockingQueue = blockingQueue;
}
@Override
public void run() {
for (int i = 0; i < 100; ++i) {
try {
System.out.println("PRODUCE: " + i);
blockingQueue.put(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Konsument extends Thread {
private final BlockingQueue<Integer> blockingQueue;
public Konsument(BlockingQueue<Integer> blockingQueue) {
this.blockingQueue = blockingQueue;
}
public void run() {
for (int i = 0; i < 100; ++i) {
try {
consume(blockingQueue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void consume(int number) {
System.out.println("CONSUME: " + number);
}
}
public class PKmon {
public static void main(String[] args) {
BlockingQueue<Integer> blockingQueue = new SynchronousQueue<>();
Thread producent = new Producent(blockingQueue);
Thread konsument = new Konsument(blockingQueue);
producent.start();
konsument.start();
}
}我做错了什么?我还尝试了ArrayBlockingQueue和LinkedBlockingQueue。
发布于 2021-05-08 01:18:58
上下文切换可以在任何地方发生,在这里它们可以防止日志消息被及时写入。假设你的消费者从队列中取出了一些东西,这通知了另一个线程,它可以在消费者执行println之前把一些东西放进去。上下文切换落在队列take之后和println之前。这些方法调用是否是同一语句的一部分并不重要,当队列的方法调用完成时,队列将放弃其锁。
但是您会说,“是的,但是另一个线程也会导致通知,这不是应该导致另一个上下文切换吗?”上下文切换不是强制的,它们取决于操作系统,它可以使用线程,也可以不使用线程。它可能决定要最大限度地减少交换机的数量。
对于生产者来说,println是第一位的。但是你不需要通知上下文切换,它可以在任何时候发生。
您可以尝试让两个线程在循环内的共享队列上进行同步:
for (int i = 0; i < 100; i++) {
synchronized (blockingQueue) {
consume(blockingQueue.take());
}
}(我只显示了一个线程,但两个线程都需要更改才能获得相同的锁。)
这将确保println反映队列中最近发生的事情。
https://stackoverflow.com/questions/67439052
复制相似问题