首页 > 解决方案 > 多生产者和消费者多线程 Java 未按预期工作

问题描述

我正在研究 Java 的生产者-消费者问题的多个生产者和消费者用例。代码在github 上。相同的实现适用于单个生产者消费者用例,但对于多生产者消费者用例表现得怪异。

我对输出有一些疑问:

一开始,所有生产者和一个消费者都有锁:

Producer t1 has lock
t5 produced 1, integerQueue: [1]
Producer t5 notifiedAll
  1. 我认为所有线程都应该争夺锁,并且最多应该有一个线程拥有所有时间的锁?所有生产者都共享锁吗?生产者线程 t1 持有锁时,消费者线程 t5 是如何获得锁的?

运行一段时间后,又出现了一个奇怪的现象:

Producer t5 has lock
t5 produced 10, integerQueue: [8, 9, 10]
Producer t5 notifiedAll

Producer t5 has lock
t5 produced 11, integerQueue: [8, 9, 10, 11]
Producer t5 notifiedAll

Consumer t8 has lock
t8 consumed 8, integerQueue: [9, 10, 11]
Consumer t8 notified All

Consumer t8 has lock
t8 consumed 9, integerQueue: [10, 11]
Consumer t8 notified All
  1. 似乎除了一个生产者和消费者之外的所有线程都已死亡,而这两个线程正在相互切换锁。为什么会这样?所有其他生产者和消费者发生了什么?

任何帮助是极大的赞赏。

标签: javamultithreadinglockingproducer-consumer

解决方案


您正在使用Producer5可运行的单个实例并将其多次提交给执行服务。

    Producer5 producer = new Producer5(queue, maxCapacity);
    pool.execute(producer);
    pool.execute(producer);
    pool.execute(producer);
    pool.execute(producer);
    pool.execute(producer);

因此,您threadName在该单个Producer5实例中的字段将被覆盖多次并且没有用(它将不再打印出实际运行的线程的名称,此外,它需要volatile被多个线程正确更新 -对于一些正确的定义)。

  System.out.println(String.format("\nProducer %s has lock",
    threadName // this will be the name of the last thread that entered `run`, 
              // they all share the same instance 
  )); 

如果它包含可变状态,请不要重复使用相同的Runnable实例。为每个执行线程创建一个单独的实例。


生产者线程 t1 持有锁时,消费者线程 t5 是如何获得锁的?

它仍然是线程 t1 运行此代码,但同时该threadName字段已由线程 t5 更新。高度误导的输出。

似乎除了一个生产者和消费者之外的所有线程都已死亡,而这两个线程正在相互切换锁。

线程都还活着,但只有两个threadName字段存在,线程一直在轮流更新(在run方法的顶部),最终确定了一些值。所有线程现在只打印该值。


推荐阅读