我有一个标准的生产者消费者问题。生产者将数据放入消费者接受的堆栈(缓冲区)中。 问题是,当生产者结束生产数据时,消费者并没有死亡(并不总是)。
我希望在制作人结束他的for
循环
for(int i = 0; i < 10; i++){
try{
// sleep((int)(Math.random() * 1));
}catch(Exception e){e.printStackTrace();}
b.put((int) (Math.random()* 10));
System.out.println("i = " + i);
}
b.stop();
然后我致电b.stop()
,将running
中的Buffer
字段更改为false并notifiesAll()
结束然后我得到:
i = 9 // number of iteration this is 10th iteration
Consumer 2.: no data to take. I wait. Memory: 0
Consumer 1.: no data to take. I wait. Memory: 0
Consumer 3.: no data to take. I wait. Memory: 0
他们应该死了,所以我做了方法stop()但它没有用。
代码正在运行,请检查
import java.util.Stack;
public class Buffer {
private static int SIZE = 4;
private int i;//number of elements in buffer
public Stack<Integer> stack;
private volatile boolean running;
public Buffer() {
stack = new Stack<>();
running = true;
i = 0;
}
synchronized public void put(int val){
while (i >= SIZE) {
try {
System.out.println("Buffer full, producer waits");
wait();
} catch (InterruptedException exc) {
exc.printStackTrace();
}
}
stack.push(val);//txt = s;
i++;
System.out.println("Producer inserted " + val + " memory: " + i);
if(i - 1 == 0)
notifyAll();
System.out.println(stack);
}
public synchronized Integer get(Consumer c) {
while (i == 0) {
try {
System.out.println(c + ": no data to take. I wait. Memory: " + i);
wait();
} catch (InterruptedException exc) {
exc.printStackTrace();
}
}
if(running){
int data = stack.pop();
i--;
System.out.println(c+ ": I took: " + data +" memory: " + i);
System.out.println(stack);
if(i + 1 == SIZE){//if the buffer was full so the producer is waiting
notifyAll();
System.out.println(c + "I notified producer about it");
}
return data;}
else
return null;
}
public boolean isEmpty(){
return i == 0;
}
public synchronized void stop(){//I THOUGH THIS WOULD FIX IT~!!!!!!!!!!!!!!
running = false;
notifyAll();
}
public boolean isRunning(){
return running;
}
}
public class Producer extends Thread {
private Buffer b;
public Producer(Buffer b) {
this.b = b;
}
public void run(){
for(int i = 0; i < 10; i++){
try{
// sleep((int)(Math.random() * 1));
}catch(Exception e){e.printStackTrace();}
b.put((int) (Math.random()* 10));
System.out.println("i = " + i);
}
b.stop();
}
}
public class Consumer extends Thread {
Buffer b;
int nr;
static int NR = 0;
public Consumer(Buffer b) {
this.b = b;
nr = ++NR;
}
public void run() {
Integer i = b.get(this);
while (i != null) {
System.out.println(nr + " I received : " + i);
i = b.get(this);
}
System.out.println("Consumer " + nr + " is dead");
}
public String toString() {
return "Consumer " + nr + ".";
}
}
public class Main {
public static void main(String[] args) {
Buffer b = new Buffer();
Producer p = new Producer(b);
Consumer c1 = new Consumer(b);
Consumer c2 = new Consumer(b);
Consumer c3 = new Consumer(b);
p.start();
c1.start();c2.start();c3.start();
}
}
答案 0 :(得分:2)
当缓冲区为空时,消费者开始等待。当它被通知时,它会检查缓冲区是否为空,如果它仍为空,则再次开始等待。如果running
标志已设置为false,则不应再次开始等待:
while (i == 0 && running) {
...
答案 1 :(得分:0)
对run()
的{{1}}进行了一次小修改:
Consumer
答案 2 :(得分:0)
您的实施存在重大缺陷。变量i的修改不是线程安全的,这意味着您可以获得无法解释的结果。它可能导致竞争条件。
答案 3 :(得分:0)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace ThreadsConsolApp
{
public sealed class ProducerConsumer
{
const int MagicNumber = 30; // Indicates how many times to bounce between ping and pong threads
private Object m_lock = new Object(); // Lock to protect counter increment
private Queue<int> m_queue = new Queue<int>();
// Ctor
public ProducerConsumer()
{
}
public void admin()
{
int i = 0;
lock (m_lock)
{
while (i <= MagicNumber)
{
Monitor.Wait(m_lock); //wait
Console.WriteLine("Controller = Produced " + i + " , Consumeed " + i);
Monitor.Pulse(m_lock); //release
i++;
}
}
}
// Ping
public void Producer()
{
int counter = 0;
lock (m_lock) // Allows only one thread at a time inside m_lock
{
while (counter <= MagicNumber)
{
Thread.Sleep(500); // Get data chunks from some source
Monitor.Wait(m_lock); // Wait if the thread is busy. 'wait' will hold
//this loop until something else pulses it to release the wait.
Console.WriteLine("producer {0}", counter);
m_queue.Enqueue(counter);//entring in queue
Monitor.Pulse(m_lock); // Releases consumer thread
counter++;
}
}
}
public void Consumer()
{
lock (m_lock) // Allows only one thread at a time inside m_lock
{
Monitor.Pulse(m_lock);
while (Monitor.Wait(m_lock,1000)) // Wait in the loop while producer is busy. Exit when producer times-out. 1000 = 1 second; ...
//app will hang without this time-out value
{
int data = m_queue.Dequeue();//dispatch from queue
Console.WriteLine("consumer {0}", data);
Monitor.Pulse(m_lock); // Release consumer
Console.WriteLine("=====================");
}
}
}
}
class Program
{
static void Main(string[] args)
{
ProducerConsumer app = new ProducerConsumer();
// Create 2 threads
Thread t_producer = new Thread(new ThreadStart(app.Producer));
Thread t_consumer = new Thread(new ThreadStart(app.Consumer));
Thread t_admin = new Thread(new ThreadStart(app.admin));
// Start threads
t_admin.Start();
t_producer.Start();
t_consumer.Start();
// Waith for the threads to complete
t_admin.Join();
t_producer.Join();
t_consumer.Join();
Console.WriteLine("\nPress any key to complete the program.\n");
Console.ReadKey(false);
}
}
}