java - Java并发-避免并发修改具有相同ID的对象的数据结构
问题描述
对于以下情况,正确的结构是什么:
假设我们有一个库存系统(域并不是很重要,它只是一个示例)并且每个操作都很慢(例如联系外部系统)。
- 它处理约 50 个仓库 (WH)。
- 我可以将库存从一个 WH 转移到另一个。
- 我要保证最终库存是正确的
我在想的是我可以处理不会影响相同 WH 的并行请求。例如:
- 将 20 个项目从 WH 1 移动到 3 的请求
- 将 15 个项目从 2 移动到 5 的移动请求(可以与前一个并行处理)
- 将 5 个项目从 3 移动到 6 的请求来了(它应该等待第一个请求完成后再继续)。
我正在考虑一个线程安全映射,其中包含我当前正在处理的仓库的所有 id。
有更好的吗?
解决方案
lock
我建议,您为每个对象引入一个变量Warehouse
以及一个唯一的整数。您可以使用 anAtomicInteger
来确保每个创建的仓库都有其唯一编号
public class Warehouse {
private static final AtomicInteger numberProvider = new AtomicInteger(0);
private final int number;
private final Lock lock = new ReentrantLock();
// ...
public Warehouse(...) {
this.number = numberProvider.incrementAndGet();
...
}
// ... (getter for number and lock and other methods)
}
这样您就可以始终以“正确”的顺序锁定两个仓库(例如,先锁定较低的数字,然后锁定较高的数字;向后解锁)。这将保证您不会遇到死锁。
public void moveStock(Warehouse from, Warehouse to, int nof) {
List<Lock> locks = Stream.of(from, to)
.sorted(Comparator.comparingInt(Warehouse::getNumber))
.map(Warehouse::getLock)
.collect(Collectors.toList());
for(int i=0;i<locks.size();++i) {
locks.get(i).lock();
}
try {
from.substractStock(nof);
to.addStock(nof);
} finally {
for(int i=locks.size()-1;i>=0;i--) {
locks.get(i).unlock();
}
}
}
推荐阅读
- spfx - 如何覆盖 Kendo React 样式?
- spring - 带有 Jakarta Bean 验证框架的 Spring 应用程序
- node.js - 有没有办法解决 EPERM: operation not allowed, copyfile
- typescript - 如何使用来自@reduxjs/toolkit 的 WritableDraft 键入辅助函数参数?
- amazon-web-services - 如何恢复因任何病毒而丢失的 AWS .pem 文件和 putty 密钥
- sql - 选择日期时间和值,当 value != LAG(value)
- c# - MVVM 绑定 ComboBox 的 SelectedIndex,Combobox 使用了 ControlTemplate,绑定不起作用
- delphi - 错误 [dcc32 致命错误] F2084 内部错误:AV06028036(05FB0000)-R2CD489B0-0
- powershell - Windows Defender 不断阻止 PowerShell 导入模块
- python - 使用两个列表但使用函数的中位数