@synchronized和dispatch_once的区别

时间:2018-11-28

今天在项目中看到了

static FuDaoManager * __instance__ = nil;

+ (instancetype)sharedInstance {
    @synchronized (__instance__) {
        if (!__instance__) {
            __instance__ = [[self alloc] init];
            [__instance__ loadData];
        }
    }
    return __instance__;
}

这种单例的创建方式,以前没有这么写过,因为从直觉上觉得@synchronized 是需要加锁的,这是需要消耗性能的,应该是使用diapatch_once吧,但是项目中确实是这么写的。本着不能靠揣测的原则,查阅相关资料进行学习才是最有效的学习方式,于是找到了一篇博客,这里直接上结论,有兴趣的同学可以直接进入学习。

性能差异

上面的这些写法大家应该都很熟悉,既然两种方式都能实现,我们来看看两者的性能差异,这里简单写了个测试的demo,使用两个方法分单线程跟多线程(采用dispatch_apply方式,性能相对较高)去访问一个单例对象一百万次,对比这期间的耗时,从iPod跟5s测试得到如下的结果

//ipod,主线程
    SingletonTest[4285:446820] synchronized time cost:2.202945s
    SingletonTest[4285:446820] dispatch_once time cost:0.761034s
    
    //5s,主线程
    SingletonTest[5372:2394430] synchronized time cost:0.466293s
    SingletonTest[5372:2394430] dispatch_once time cost:0.070822s

    //ipod,多线程
    SingletonTest[4315:448499] synchronized time cost:3.385109s
    SingletonTest[4315:448499] dispatch_once time cost:0.908009s
    
    //5s,多线程
    SingletonTest[5391:2399069] synchronized time cost:0.507504s
    SingletonTest[5391:2399069] dispatch_once time cost:0.169934s

总结

通过上面的分析,我们知道@synchronized采用的是递归互斥锁来实现线程安全,而dispatch_once的内部则使用了很多原子操作来替代锁,以及通过信号量来实现线程同步,而且有很多针对处理器优化的地方,甚至在if判断语句上也做了优化(逼格有点高),使得其效率有很大的提升,虽然其源码很短,但里面包含的东西却很多,所以苹果也推荐使用dispatch_once来创建单例。通过这个简短的dispatch_once,你也可以清楚为什么GCD的性能会这么高了,感兴趣可以再去看看libdispatch的其它源码。

具体博文链接放在这https://www.jianshu.com/p/ef3f77c8b320

你可能感兴趣的:(@synchronized和dispatch_once的区别)