如何多线程创建一个延迟加载的属性?

时间:2016-01-27 20:58:18

标签: objective-c multithreading grand-central-dispatch

 - (NSHashTable *)pollers
 {
    if (!_pollers) {
        dispatch_sync(self.serialQueue, ^{
            _pollers = [NSHashTable weakObjectsHashTable];
        });
    }

    return _pollers;
 }

pollers是单例上的非原子属性。在单例中还有一些其他方法,其中将对象添加到轮询器中,并且我使用@synchronized作为其添加([self.pollers addObject:____])。

无论如何......我对上面的代码有疑问。如果2个线程同时调用此函数,则它们都可以通过if (!_pollers)代码,然后两个代码将在我们的自定义serialQueue上同步调度_pollers = [NSHashTable weakObjectsHashTable];代码。所以我们实际上会运行两次代码。

有更好的方法吗?

2 个答案:

答案 0 :(得分:0)

像这样使用dispatch_once

static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
  dispatch_sync(self.serialQueue, ^{
    _pollers = [NSHashTable weakObjectsHashTable];
  });
});
return pollers;

答案 1 :(得分:0)

只需要一个dispatch_once功能

您的串行队列现在是冗余的,因为dispatch_once将确保仅调用一次块(即使从多个线程同时调用)contrary to what pds says

The documentation clearly states that:

  

如果从多个线程同时调用[dispatch_once],此函数将同步等待,直到块完成。

您的if声明也是多余的as pointed out by Josh

因此您只想:

- (NSHashTable *)pollers
 {
    static dispatch_once_t t;
    dispatch_once(&t, ^{
        _pollers = [NSHashTable weakObjectsHashTable];
    });

    return _pollers;
}

值得注意的是,您需要一个线程安全的单例sharedInstance实现,以使其具有防弹性能。您可以使用dispatch_once以相同的方式执行此操作。例如:

static singleton* sharedInstance;

+(instancetype) sharedInstance {
    static dispatch_once_t t;
    dispatch_once(&t, ^{
        sharedInstance = [[self alloc] init];
    });

    return sharedInstance;
}