我正在研究Java的生产者-消费者问题的多个生产者和消费者用例。代码在 github 上。相同的实现适用于单个生产者使用者用例,但对于多生产者使用者用例,行为很奇怪。
我对输出有一些疑问:
一开始,所有生产者和一个消费者都有锁:
Producer t1 has lock
t5 produced 1, integerQueue: [1]
Producer t5 notifiedAll
- 我认为所有线程都应该竞争锁,并且最多应该有一个线程拥有有史以来的锁?所有生产者都在共享锁吗?消费者线程 t5 是如何在生产者线程 t1 持有它时获得锁的?
运行一段时间后,又出现了一个奇怪的现象:
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
- 似乎除了一个生产者和消费者之外的所有线程都已经死亡,而这两个线程正在彼此之间切换锁。为什么会这样?所有其他生产者和消费者发生了什么?
任何帮助将不胜感激。
您正在使用可运行的Producer5
的单个实例,并将其多次提交到执行服务。
Producer5 producer = new Producer5(queue, maxCapacity);
pool.execute(producer);
pool.execute(producer);
pool.execute(producer);
pool.execute(producer);
pool.execute(producer);
因此,您在单个Producer5
实例中的threadName
字段将被多次覆盖并且没有用(它将不再打印出实际正在运行的线程的名称,此外,需要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
实例包含可变状态,请不要重复使用该实例。为每个执行线程创建一个单独的实例。
消费者线程 t5 是如何在生产者线程 t1 持有它时获得锁的?
运行此代码的仍然是线程 t1,但线程 t5 同时更新了threadName
字段。高度误导性的输出。
似乎除了一个生产者和消费者之外的所有线程都已经死亡,这两个线程正在彼此之间切换锁。
线程都还活着,但存在两个threadName
字段,线程轮流更新(在run
方法的顶部(,最终确定一些值。所有线程现在都只打印该值。