java - 多生产者和消费者多线程 Java 未按预期工作
问题描述
我正在研究 Java 的生产者-消费者问题的多个生产者和消费者用例。代码在github 上。相同的实现适用于单个生产者消费者用例,但对于多生产者消费者用例表现得怪异。
我对输出有一些疑问:
一开始,所有生产者和一个消费者都有锁:
Producer t1 has lock
t5 produced 1, integerQueue: [1]
Producer t5 notifiedAll
- 我认为所有线程都应该争夺锁,并且最多应该有一个线程拥有所有时间的锁?所有生产者都共享锁吗?生产者线程 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
- 似乎除了一个生产者和消费者之外的所有线程都已死亡,而这两个线程正在相互切换锁。为什么会这样?所有其他生产者和消费者发生了什么?
任何帮助是极大的赞赏。
解决方案
您正在使用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
方法的顶部),最终确定了一些值。所有线程现在只打印该值。
推荐阅读
- c# - 突然出现异常“Word遇到问题”
- r - 在生成的表中插入总和列
- typescript - 使用 Lambda 层在 Lambda 函数之间共享接口/类型
- python - 函数未创建数据框
- windows - 从 WSL 运行 Windows API 函数
- azure - 通过公司 VPN 连接到 Azure 数据库
- google-chrome - 如何拥有两个完全不同的 chrome 进程组(具有不同的进程 ID)
- powershell - PowerShell - CURL 返回值和节点,而 Invoke-RestMethod 返回空节点
- postgresql - Postgresql如何将数组转换为数组?
- java - 从集合中读取并更新到 Mongodb 数据库中的另一个集合