【问题标题】:Producer Consumer synchronization Java weird behaviour生产者消费者同步Java怪异行为
【发布时间】:2014-05-06 02:46:03
【问题描述】:
import java.util.ArrayList;


public class Main {
public static void main(String[] args) {
    Producer producer = new Producer("Producer ");
    Consumer[] consumers = new Consumer[1];

    for (int i = 0; i < consumers.length; i++) {
        consumers[i] = new Consumer(producer,"Consumer " + i);
    }
    producer.start();
    for (int i = 0; i < consumers.length; i++) {

        consumers[i].start();
    }
}
}



class Producer extends Thread{

public ArrayList<Integer> buffer;
public int bufferSize = 20;
int fillCount = 0;
int emptyCount = bufferSize;
Integer item;

public Producer(String name) {
    super(name);
    buffer = new ArrayList<>(bufferSize);
}
public void run() {
    while(true) {
        System.out.println("Producing");
        item = new Integer(1000);
        downEmpty();
        addItemtoBuffer();
        increaseFill();

    }
}
private void addItemtoBuffer() {
    synchronized (buffer) {
        buffer.add(item);
        System.out.println("Produced " + getName() + fillCount + " " + emptyCount);
    }
}
private void downEmpty() {
    while(emptyCount <= 0) {
                    //Busy Waiting when buffer is full
        //System.out.println("EmptyCount " + emptyCount);
    }
    --emptyCount;

}
private void increaseFill() {
    ++fillCount;
}
}

class Consumer extends Thread{

private Producer producer;
private ArrayList<Integer> buffer;
public Consumer(Producer producer, String name) {
    super(name);
    this.producer = producer;
    buffer = producer.buffer;
}
public void run() {
    while(true) {
        downFill();
        consume();
        increaseEmpty();
    }
}
private void downFill() {

    while(producer.fillCount <= 0) {
                    //Busy Waiting when buffer is empty
        //System.out.println("fillCount" + producer.fillCount + " EmptyCount" + producer.emptyCount);
    }
    --producer.fillCount;

}
private void increaseEmpty() {
    ++producer.emptyCount;
}
private void consume() {
    synchronized (buffer) {
        buffer.remove(buffer.size()-1);
        System.out.println("Consumed");
    }


}
}

这是我对生产者消费者问题的解决方案。目前它只有 1 个生产者和 1 个消费者。我的问题是当我运行它时,Producer 会产生直到缓冲区已满并进入忙碌等待状态。消费者消费了一段时间,但停止让生产者完全填满缓冲区。此时 fillCount 为 20。

我不知道为什么消费者不会消费。如果 fillCount 小于或等于 0,它唯一的忙等待。另一种可能性是它正在等待同步块,但由于生产者正忙于等待,缓冲区必须是空闲的。 但还有一件更大的事情。如果我在忙碌的等待中取消注释系统输出,它就可以工作!虽然有点奇怪。

我需要帮助,我需要让它与任意数量的生产者和消费者合作。我的问题是为什么消费者不消费并且可能让它与多个消费者一起使用。

【问题讨论】:

  • 您如何确保对emptyCountfillCount 的访问是线程安全的?一个线程中的更改是否对另一个线程可见?您是否尝试过使用 AtomicInteger 代替?
  • 我最初有 emptyCount 和 fillCount 是 Integer 对象并同步它们,但我又回去了。将尝试 AtomicIntegers
  • 记住只同步 final 对对象的引用。在变化的参考上同步并没有你认为的那样;)

标签: java multithreading


【解决方案1】:

当你有一个 JIT 可以检测到线程没有变化的字段时,它可以内联它。这意味着,也许有一天会看到另一个线程更改的值,而不是可能会看到另一个线程的更改。

您可以使字段可变,这或多或少会起作用,但更好的解决方案是使用具有线程安全递增和递减的 AtomicInteger。

了解更多信息。 http://vanillajava.blogspot.co.uk/2012/01/demonstrating-when-volatile-is-required.html

【讨论】:

  • 谢谢现在它或多或少的工作。我也让多个生产者和消费者工作,但它并没有我想的那么顺利。就像一个进程一次对缓冲区执行 5 次以上的操作一样。我想这是我无法控制的事情
  • 由于您的消费者(和生产者)正忙于等待,当您的每个生产者/消费者有两个空闲的逻辑 CPU 时,您的解决方案将最有效。如果您没有那么多 CPU,那么您应该会遇到明显的延迟。更可扩展的解决方案是使用 BlockingQueue 或 Executor。
猜你喜欢
  • 1970-01-01
  • 2018-12-13
  • 1970-01-01
  • 1970-01-01
  • 2011-04-12
  • 2018-01-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多