目标c中java的并发hashmap的等价物

时间:2013-11-19 09:51:15

标签: java ios concurrency nsmutabledictionary concurrenthashmap

我有一个NSMuableDictionary由并行线程访问,其中几个线程将枚举,几个线程将变异。但是我们无法实现这一点

  

“在枚举期间不能突变收集”

。想要使用NSLock,但是然后锁定字典直到枚举完成将导致性能降低。在java中我们有并发的hashmap,它足够聪明,可以照顾这个场景。有没有更好的想法在iOS中实现这一目标。请帮忙。

3 个答案:

答案 0 :(得分:6)

对Objective-C容器的读/写访问通常不是线程安全的。

您可以通过将容器与专用调度队列相关联,然后在该队列上执行所有读写访问来解决并发问题。队列可以是串行的也可以是并发的。

您可以在任何专用线程上调用以下方法。但是,我建议最终将您的实现切换到调度库。

在这里,我们创建一个串行队列:

dispatch_queue_t sync_queue = dispatch_queue_create("sync_queue", NULL);

可以异步进行写访问:

- (void) addItem:(id)item forKey:(NSString*)key {
    dispatch_async(sync_queue, ^{
        [self.dict setObject:item forKey:key];
    });
}

返回值的读访问必须是同步的:

- (id) itemForKey:(NSString*)key {
     __block id item;
     dispatch_sync(sync_queue, ^{
         item = [self.dict objectForKey:key];
     });
     return item;
}

您可以为任何任务定义类似的包装器:

- (void) iterate {
    dispatch_async(sync_queue, ^{
        for (id item in self.dict) {
            ...
        }
    });
}

使用并发队列:

dispatch_queue_t sync_queue = dispatch_queue_create("sync_queue", DISPATCH_QUEUE_CONCURRENT);

写入访问可以异步进行,需要一个障碍:

- (void) addItem:(id)item forKey:(NSString*)key {
    dispatch_barrier_async(sync_queue, ^{
        [self.dict setObject:item forKey:key];
    });
}

返回值的读访问必须是同步的,并且它不需要障碍。 基本上,同步和并发队列没有区别:

- (id) itemForKey:(NSString*)key {
     __block id item;
     dispatch_sync(sync_queue, ^{
         item = [self.dict objectForKey:key];
     });
     return item;
}

答案 1 :(得分:0)

在objective-c中没有等价物,但是你可以通过在临时数组中保存元素来避免诸如“在枚举时发生变化”之类的错误。有关详细信息,请参阅this答案。

答案 2 :(得分:0)

EDIT3:

这样做: Implementing concurrent read exclusive write model with GCD

可能仍有一些限制,但至少你会有更细粒度的访问和多个线程的并发读取。

结束编辑3:

在类中包含对字典的访问权限,并在访问方法中使用@synchronized(self){}。

EDIT2: 没关系。这不会给你你想要的。把答案留在这里作为反模式。

编辑:

像这样的东西

(在您的对象实现中)

- (void) setObjectSynchronized:(id) value forKey:(id) key {
  @synchronized(self) {
     [self.internalDictionary setObject:value forKey:key];
  }
}


- (void) objectForKeySynchronized:(id) key {
  @synchronized(self) {
     return [self.internalDictionary objectForKey:key];
  }
}