在Objective-C中,与synchronized相当的关键字是什么?

5
什么是Objective-C中与Java synchronized相当的方法? 我想让我的单例方法变得安全,这样当它被两个不同的线程调用时,它们会依次使用它。
+(MyObject*) getSharedObject
{
     if(!singleton)
     {
          singleton = [[MyObject alloc] init];
     }
     return singleton;
}

重复的问题:如何在Objective-C中使用synchronized(同步)关键字进行锁定和解锁? - Aaron Saunders
1
不完全是重复,但确实是一个相关的问题。 - Joshua Weinberg
4个回答

10

Objective-C 有一个同步构造体

-(MyObject*) getSharedObject
{
@synchronized(something)
{
     if(!singleton)
     {
          singleton = [[MyObject alloc] init];
     }
     return singleton;
}
}

从同步块中返回会执行“正确”的操作


只需要进行一个小修复,我认为原帖作者想要使用静态方法。 - onmyway133

9

Joshua的回答是正确的,但需要您拥有一个要进行同步的对象。如果您不小心这样做,为单例进行同步可能会导致各种奇怪的竞态条件。单例的标准模式是在+initialize中使用dispatch_once进行初始化,它会做正确的事情:

static MyObject *singleton = nil;

+ (void)initialize {
  static dispatch_once_t pred;
  dispatch_once(&pred, ^{ singleton = [[MyObject alloc] init]; } );
}

- (MyObject&)getSharedObject
{
  return singleton;
}

2
在单例类上同步,就不会出现奇怪的竞态条件。 - JeremyP
1
这是苹果推荐的风格。 - eonil

8

为了同步单例创建,您应该使用单例类作为同步对象。这是我的常用模式:

+(MyObject*) singleton
{
    static MyObject* singleton = nil;
    @synchronized([MyObject class])
    {
         if(singleton == nil)
         {
             singleton = [[MyObject alloc] init];
         }
    }
    return singleton;
}

需要注意的几点:

  • 我将其设为了类方法。实际上,你不必这样做,它也可以作为实例方法工作。

  • 通常在类方法中引用类时,你会使用self(或者在实例方法中使用[self class])。然而,在这种情况下是错误的,因为子类会使用与MyObject类不同的对象进行同步。

  • 我将return语句放在了@synchronize块的外面。在块内部返回也是完全可以的,但是如果你这样做,你会得到一个虚假的clang静态分析器警告,说这个方法可能不会返回值。


编辑

上述模式早已过时。最好使用dispatch_once模式。

+(MyObject*) singleton
{
    static dispatch_once_t onceToken;
    static MyObject* singleton = nil;

    dispatch_once (&onceToken, ^{
        singleton = [[MyObject alloc] init];
    });
    return singleton;
}

2
静态的MyObject* singleton = nil; 这样做会将单例对象设置为nil,每次调用该方法时都会重新实例化它吗? - aryaxt
3
在Obj-C中,静态变量与C语言中的静态变量相同,这意味着该行代码仅会被初始化一次。 - Joshua Weinberg
你也可以使用 MyObject.class 替换 [MyObject class] - Todd Lehman
@ToddLehman 我不确定点符号表示法是否适用于类属性。无论如何,我一直不喜欢Objective-C中的点符号表示法。 - JeremyP
虽然我在评论这个相当古老的答案,但我要指出我不再使用这种模式,我现在使用dispatch_once - JeremyP
显示剩余3条评论

-1
我同意两个答案。但是如果想要按需实例化,我会选择Joshua的建议,并稍作修改,使用双重检查锁定机制:
if (!singleton)  
   @synchronized(something)  
      if (!singleton)  
         instantiate;

这样就可以避免对象实例化后的不必要锁定。


2
双重检查锁定可能涉及许多微妙的潜在竞态条件。我会避免使用它。 - JeremyP
我很感激你的反馈,JeremyP。我承认我之前并没有意识到这些问题。然而,我仍然认为值得花时间去理解这些问题,并且尽可能做到正确,特别是如果这段代码将会有高流量的话,知ingly添加一个可能的争议点是不好的。非常感谢! - fhj
1
不用担心投票问题。我们在这里互相学习。 - fhj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接