确保在多线程环境中迭代所有值

时间:2018-07-16 21:33:35

标签: java multithreading

我有一个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中一次?

我的想法:

  • 如果安装程序当前正在向api添加方法,请使用锁定并阻止addObject方法(或将两个方法都设为synchronized,这会略微降低性能)

1 个答案:

答案 0 :(得分:1)

  

问题:我如何保证集合中的所有对象以及使用addObject添加的对象将一次准确地添加到api?

在这里您必须小心,因为它接近ole "double check locking bug"

如果我了解您的问题,您想这样做:

  1. 在调用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"的对象进行排队。
  2. 然后在调用addObject(...)时,对集合中的对象调用API方法。
  3. 如果在调用start()
  4. 的过程中 添加了其他对象,则处理重叠
  5. 在传递给start()的所有对象上仅调用一次该方法。

令人困惑的是,您的API调用也被命名为start()。我认为这与您的代码示例中的addObject(...)方法不同。我将在下面将其重命名为addObject(),以表明它不会递归。

不幸的是,最简单的方法是在每个方法中都有一个addObject(...)块:

someApiMethod(...)

要使其更快,将需要很多复杂的代码。您可以做的一件事是使用synchronizedprivate 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

这非常复杂,并且可能不会更快,具体取决于您的哈希图的大小和其他因素。