java - 保证在多线程环境中遍历所有值
问题描述
我有一个Set
任何类型的值,一个AtomicBoolean
指示该类提供的功能是否正在运行。
private Set<Object> set = new HashSet<>();
private AtomicBoolean running;
现在,我有两种方法,其中一种是将对象添加到集合中,另一种用作我的类的设置方法。
public void start() {
// ...
set.foreEach(someApi::addObject);
// ...
running.set(true);
}
public void addObject(Object o) {
set.add(o);
if(running.get()) {
someApi.addObject(o);
}
}
但是,该代码存在问题。如果在方法start
迭代时从另一个线程调用该方法,则 set running
is still false
. 因此,对象不会被添加到 api。
问题:我如何保证集合中的所有对象和添加的对象addObject
都将准确地添加到 api 中?
我的想法:
addObject
如果设置当前正在向 api 添加方法,则使用锁定并阻止该方法(或同时使用这两种方法synchronized
,这会稍微降低性能)
解决方案
问题:如何保证集合中的所有对象以及使用 addObject 添加的对象都将准确地添加到 api 中?
您必须在这里小心,因为这接近于 ole “双重检查锁定错误”。
如果我理解你的问题,你想:
addObject(...)
在调用. _ _start()
- 然后当
start()
被调用时,对集合中的对象调用 API 方法。 - 如果在调用期间添加了其他对象,则处理重叠
start()
- 在传递给的所有对象上调用该方法一次且仅一次
addObject(...)
。
令人困惑的是,您的 API 调用也被命名为addObject()
. 我认为这与addObject(...)
您的代码示例中的方法不同。我将在下面重命名它someApiMethod(...)
以表明它不会递归。
不幸的是,最简单的方法是synchronized
在每个方法中都有一个块:
private final Set<Object> set = new HashSet<>();
public void start() {
synchronized (set) {
set.forEach(someApi::someApiMethod);
}
}
public void addObject(Object obj) {
synchronized (set) {
if (set.add(obj)) {
someApi.addObject(obj);
}
}
}
}
为了使其更快,将需要更复杂的代码。您可以做的一件事是使用 aConcurrentHashMap
和 a AtomicBoolean running
。就像是:
private final ConcurrentMap<Object, Object> map = new ConcurrentHashMap<>();
private final Set<Object> beforeStart = new HashSet<>();
private final AtomicBoolean running = new AtomicBoolean();
public void start() {
synchronized (beforeStart) {
for (Object obj : beforeStart) {
doIfAbsent(obj);
}
running.set(true);
}
}
public void addObject(Object obj) {
if (running.get()) {
doIfAbsent(obj);
} else {
synchronized (beforeStart) {
// we have to test running again once we get the lock
if (running.get()) {
doIfAbsent(obj);
} else {
beforeStart.add(obj);
}
}
}
}
private void doIfAbsent(Object obj) {
if (map.putIfAbsent(obj, obj)) {
someApi.someApiMethod(obj);
}
}
这非常复杂,根据哈希图的大小和其他因素,它可能不会更快。
推荐阅读
- css - CSS - 软行换行到字符位置的缩进列表
- java - 创建 DefaultWsdl11Definition bean 时 XsdSchema 和 XsdSchemaCollection 之间的 JAXB 区别
- rust - 指定参数的生命周期持续到函数调用
- java - 设备方向更改后未加载新的布局资源文件
- .htaccess - Opencart 3 重定向 store-domain.com/catalog 到主页
- react-native - 我只能在我的反应组件内部解析我的 mapStateToProps 对象
- html - 为什么“flex-direction:row”不适用于这些图像?
- r - R中的条件概率
- java - 如何构建与 Verifone 或 Ingenico EMV 设备一起使用的桌面应用程序
- python - 跨熊猫数据框列应用函数