Java 并发 - 避免同时修改具有相同 ID 的对象的数据结构

对于以下情况,正确的结构是什么:

假设我们有一个库存系统(域并不重要,这只是一个例子)并且每个操作都很慢(例如联系外部系统)。

  • 它处理 ~ 50 个仓库 (WH)。

  • 我可以将库存从一个仓库转移到另一个仓库。

  • 我要保证最终库存是正确的

我在想的是,我可以并行处理不影响同一个 WH 的请求。例如:

  1. 请求将 20 件物品从仓库 1 移动到仓库 3

  2. 将 15 个项目从 2 移动到 5 的请求移动(可以与上一个并行处理)

  3. 请求将 5 个项目从 3 移动到 6(它应该等待第一个请求完成后再继续)。

我在考虑一个线程安全的映射,其中包含我当前正在处理的仓库的所有 ID。

有更好的东西吗?


12345678_0001
浏览 131回答 2
2回答

阿波罗的战车

我建议您lock为每个Warehouse对象引入一个变量以及一个唯一的整数。您可以使用 anAtomicInteger来确保每个创建的仓库都有其唯一编号public class Warehouse {&nbsp; &nbsp; private static final AtomicInteger numberProvider = new AtomicInteger(0);&nbsp; &nbsp; private final int number;&nbsp; &nbsp; private final Lock lock = new ReentrantLock();&nbsp; &nbsp; // ...&nbsp; &nbsp; public Warehouse(...) {&nbsp; &nbsp; &nbsp; &nbsp; this.number = numberProvider.incrementAndGet();&nbsp; &nbsp; &nbsp; &nbsp; ...&nbsp; &nbsp; }&nbsp; &nbsp; // ... (getter for number and lock and other methods)}这样您就可以始终以“正确”的顺序锁定两个仓库(例如,先锁定较低的数字,然后锁定较高的数字;向后解锁)。这将保证您不会遇到死锁。public void moveStock(Warehouse from, Warehouse to, int nof) {&nbsp; &nbsp; List<Lock> locks = Stream.of(from, to)&nbsp; &nbsp; &nbsp; &nbsp; .sorted(Comparator.comparingInt(Warehouse::getNumber))&nbsp; &nbsp; &nbsp; &nbsp; .map(Warehouse::getLock)&nbsp; &nbsp; &nbsp; &nbsp; .collect(Collectors.toList());&nbsp; &nbsp; for(int i=0;i<locks.size();++i) {&nbsp; &nbsp; &nbsp; &nbsp; locks.get(i).lock();&nbsp; &nbsp; }&nbsp; &nbsp; try {&nbsp; &nbsp; &nbsp; &nbsp; from.substractStock(nof);&nbsp; &nbsp; &nbsp; &nbsp; to.addStock(nof);&nbsp; &nbsp; } finally {&nbsp; &nbsp; &nbsp; &nbsp; for(int i=locks.size()-1;i>=0;i--) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; locks.get(i).unlock();&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}

温温酱

集合将是您正在寻找的数据结构。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java