我有一个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
方法遍历集合running
的同时从另一个线程调用该方法,则该方法仍为false
。因此,该对象将不会添加到api。
问题:我如何保证集合中的所有对象和添加了addObject
的对象将被完全添加到api中一次?
我的想法:
addObject
方法(或将两个方法都设为synchronized
,这会略微降低性能)答案 0 :(得分:1)
问题:我如何保证集合中的所有对象以及使用addObject添加的对象将一次准确地添加到api?
在这里您必须小心,因为它接近ole "double check locking bug"。
如果我了解您的问题,您想这样做:
const RoleSchema = new mongoose.Schema({
name: String,
type: String,
permissions: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Permission'
}],
createdAt: {
type: Date,
default: Date.now
}
});
RoleSchema.statics = {
get(id) {
// const _id = mongoose.Types.ObjectId.fromString(id);
return this.findById(id)
// .populate('permissions')
.exec()
.then((role) => {
if (role) {
return role;
}
const err = new APIError('No such role exists!', httpStatus.NOT_FOUND);
return Promise.reject(err);
});
},
list({ skip = 0, limit = 50 } = {}) {
return this.find()
.populate('permissions')
.sort({ createdAt: -1 })
.skip(+skip)
.limit(+limit)
.exec();
}
};
module.exports = mongoose.model('Role', RoleSchema);
之前对进入集合{em>中的Cast to ObjectId failed for value "ADD_USER" at path "_id" for model "Permission"
的对象进行排队。addObject(...)
时,对集合中的对象调用API方法。start()
start()
的所有对象上仅调用一次该方法。令人困惑的是,您的API调用也被命名为start()
。我认为这与您的代码示例中的addObject(...)
方法不同。我将在下面将其重命名为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);
}
}
}
}
。像这样:
ConcurrentHashMap
这非常复杂,并且可能不会更快,具体取决于您的哈希图的大小和其他因素。