【问题标题】:Producer Consumer Misunderstanding in Threading线程中的生产者消费者误解
【发布时间】:2016-11-20 09:57:10
【问题描述】:

我希望 ProducerThread 产生最多 10 个随机值,然后期望 ConsumerThread 使用 Queue 的这些值。某处 Producer 不止一次地生成添加值。我有一个概念,当我们在一个对象上调用 notify 时,该 Thread 将释放锁定并为期待更新的 Thread 提供机会。

这是代码,请纠正我的理解。

public class ProducerThread extends Thread {

    Queue<Integer> values;

    ProducerThread(Queue<Integer> values) {
        this.values = values;
    }

    public void run() {
        while(true) {
            synchronized(values) {
                double totalValues = Math.random()*10;
                System.out.println("Going to populate total values:" + totalValues);

                for (int i = 1; i <= totalValues; i++) {
                    values.add(i);
                    System.out.println("Value updated: " + i);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                values.notify();
            }
        }
    }

}



public class ConsumerThread extends Thread {
    Queue<Integer> values;

    ConsumerThread(Queue<Integer> values) {
        this.values = values;
    }

    @Override
    public void run() {
        while(true) {
            synchronized (values) {

                try {
                    // Consumer Thread waits until values are populated by Producer Thread
                    if(values.isEmpty()) {
                        values.wait();
                    }

                    Iterator<Integer> iterateValues = values.iterator();
                    System.out.println("Going to consume values: " + values.size());
                    while (iterateValues.hasNext()) {
                        Integer removedValue = iterateValues.next();
                        System.out.println("Value deleted: " + removedValue);
                    }
                    values.clear();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
}


public class Test {
    public static void main(String[] args) {
        Queue<Integer> values = new LinkedList<Integer>();
        ProducerThread producer = new ProducerThread(values);
        ConsumerThread consumer = new ConsumerThread(values);

        consumer.start();
        producer.start();

    }
}

【问题讨论】:

  • 我刚刚运行了它,它正在做我读到的它应该做的事情。您能否准确说明您的期望?也许是样本输出?
  • @JoeC 我希望可能的输出为:生产者设置随机值 8,然后一旦生产者完成,它应该从 1 到 8 个值填充队列,消费者将清除所有 8 个值。然后生产者再次将随机值设置为 5,并将队列从 1 填充到 5,然后轮到消费者。
  • 你不会找到任何现成的解决方案来让两个(或更多)线程轮流,因为这不是线程的用途。一组线程可以轮流做的任何事情都可以通过单个线程更有效地完成。如果这是一项家庭作业,并且您必须让线程轮流进行,那么我将为每个线程创建一个java.util.concurrent.SynchronousQueue。每个线程在其队列中等待接收“令牌”(对象)。当它得到令牌后,它会做一些工作,然后将令牌放入下一个线程的队列中,然后再次返回等待。

标签: java multithreading producer-consumer


【解决方案1】:

啊哈!你遇到了可怕的比赛条件!

在notify 在你的ProducerThread 中返回后,立即表示线程仍然有锁。被notify 唤醒的ConsumerThread 将看到锁不可用,并等待它变为可用。

然后ProducerThread 放弃锁定,然后它将与ConsumerThread 竞争以取回锁定(ProducerThread 通过重新进入synchronized 块,ConsumerThread 通过意味着必须从wait返回)。不能保证哪一个会赢。

如果您希望您的 ProducerThread 在生产更多物品之前等待物品被消耗,您应该考虑针对该场景进行另一个等待/通知。

编辑:这张图片可能有助于更清楚地解释事情。

【讨论】:

  • 它通过使用另一个等待和通知来工作,但为什么 ProducerThread 再次进入竞争获取锁。似乎在通知 ProducerThread 时只松开锁但不通知正在等待的线程。我看不到等待/通知机制在这里工作。请纠正我。
  • 两件事。首先,notify 实际上并没有放弃锁。它只通知另一个线程(在这种情况下为ConsumerThread)它正在等待的任何事情现在已经发生了。其次,ConsumerThread 必须在从wait 返回之前重新获取锁。如果ProducerThread 首先再次获得锁(通过返回循环顶部并重新进入synchronized 块),则ConsumerThread 仍然被阻止。
  • 我在我的答案中添加了一个图表,以防它有助于澄清事情。
猜你喜欢
  • 1970-01-01
  • 2018-09-24
  • 2017-02-01
  • 2012-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-10
  • 1970-01-01
相关资源
最近更新 更多