@synchronized和dispatch_once的区别
2018-11-28 本文已影响0人
编程_书恨少
时间: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的其它源码。