我是编程新手,过去只做过Python。我正在处理一个大学作业,涉及使用多线程概念在Java中实现生产者-消费者问题。在这种情况下,有两个生产者和一个消费者。生产者A以每5分钟1个的速率生成一个项目(仅作为示例),生产者B以每6分钟1个的速率生成一个项目。这些物品放在有限的架子上,只能容纳5个物品。
消费者每隔4分钟从货架上取走一件物品。当架子空时,消费者将无法操作,而当架子已满时,生产者将无法操作。
该程序应继续进行,直到每个生产者生产了10件商品,并且消费者消费了20件商品。
这是我到目前为止所做的:
class Buffer{
private int v;
private volatile boolean empty = true;
public synchronized void insert(int x) {
while(!empty) {
try {
wait();
}
catch(InterruptedException e) {
e.printStackTrace();
}
}
empty = false;
v = x;
notify();
}
public synchronized int remove() {
while(empty) {
try {
wait();
}
catch(InterruptedException e) {
e.printStackTrace();
}
}
empty = true;
return v;
}
}
上面的代码块是提到的架子的类。
下面的代码块是生产者类。我决定使用数组而不是LinkedList,因为不允许我们为此任务使用SynchronizedList。
class Producer extends Thread{
private int size;
private int[] queue;
private int queueSize;
public Producer(int[] queueln, int queueSizeln, String ThreadName) {
super(ThreadName);
this.queue = queueln;
this.queueSize = queueSizeln;
}
public void run() {
while(true) {
synchronized(queue) {
while(size == queueSize) {
System.out.println(Thread.currentThread().getName() + "Shelf is full: waiting...\n");
try {
queue.wait();
}
catch(InterruptedException e) {
e.printStackTrace();
}
}
//when queue is empty, produce one, add and notify
int pot = 1;
System.out.println(Thread.currentThread().getName() + " producing...: " + pot);
}
}
}
}
但是,我遇到了一个问题。由于Java不允许我追加到数组,因此我不知道如何继续执行代码。我最初计划将pot的值附加到:
int[] queue
可视化生产者生产该物品并将其放入货架。
非常感谢您的帮助!
如果要最大程度地减少使用库类,则可以轻松制作具有固定大小的数组的环形缓冲区。跟踪两个索引:下一个项目应插入的位置,下一个项目可以去除的位置https://en.wikipedia.org/wiki/Circular_buffer
环形缓冲区通常在高性能并发代码中使用,因此在本练习的上下文中使用它们是有意义的。您的“有限尺寸的架子”听起来像是环形缓冲区。
我会将队列移到Buffer类中。通过将队列封装到Buffer中,生产者和使用者不必同步,Buffer可以保护其内容免受并发访问,而访问它的线程也不必关心。
对于队列实现,只要Buffer防止对列表的并发访问,使用非线程安全列表实现就可以了。在这里,这意味着所有允许访问或修改列表的方法都必须使用同步保护。
您需要在添加和删除时都添加通知,以便唤醒在任一条件下等待的线程。
使用Java的内在锁的怪异之处在于,如果线程由于不同的原因在对象上等待,那么使用notify是有问题的,因为调度程序会选择要通知的线程,并且如果线程正在等待的条件不是准备好了,该通知将浪费掉。解决该问题的方法是使用notifyAll而不是notify。