多线程安全中有个概念叫:临界区,意思是有一段代码,它只能被一个线程调用,这段代码就叫临界区。
在单例模式中,我们常常会判断当前类的实例是否已经存在了, 如果已存在那就返回当前的实例,如果不存在就创建一个。
传统操作下,可以使用条件语句判断,但是多线程下就不行了,为了保证当多个线程调用单例模式代码时,能准确的进行单列判断,我们需要使用dispatch_once来操作,下面是一个完整的单例类:
import UIKit struct MyStruct { //存储型的 类型属性(使用static关键字) static var instalnce: MySingle? static var myT:dispatch_once_t = 0 } class MySingle: NSObject { override init(){ super.init() NSLog("init") } //不是单例模式。每次调用都会init一次 static var alwaysInstance:MySingle = MySingle() //单列模式。初始化init只会运行一次,使用dispatch_once可以保证多个线程调用时,可以是线程安全的,保证有且只有一次实例化调用 //计算型的 类型属性(在类中,定义计算型的类型属性,用class关键字,存储型的类型属性用static关键字) class var onceInstance:MySingle{ //保证里面的代码只能运行一次,如果有三个线程过来调用,其中一个已经运行过了,那么其他2个线程不会运行了 dispatch_once(&MyStruct.myT){ MyStruct.instalnce = MySingle() } return MyStruct.instalnce! } }
在MySingle类中,用到了计算型的类属性,它隐式的包含了一个getter,返回当前类的实例。dispatch_once方法包裹的代码,在整个程序的生命周期内,只会被运行一次!多线程情况下,就能保证单例的效果了!
下面是调用的Demo程序,放在一个Button按钮的点击事件中:
@IBAction func btnClick(sender: AnyObject) { dispatch_async(dispatch_queue_create("com.thread", DISPATCH_QUEUE_CONCURRENT)){ NSLog("once:%@",MySingle.onceInstance) } dispatch_async(dispatch_queue_create("com.thread2", DISPATCH_QUEUE_CONCURRENT)){ NSLog("once:%@",MySingle.onceInstance) } }
点击Button后,会有两个2线程产生,都去调用单例类,获取类的实例对象,结果是:
2015-05-24 15:32:32.383 ThreadSafeDemo[1484:824008] init 2015-05-24 15:32:32.385 ThreadSafeDemo[1484:824010] once:<ThreadSafeDemo.MySingle: 0x7fc74a77a050> 2015-05-24 15:32:32.385 ThreadSafeDemo[1484:824008] once:<ThreadSafeDemo.MySingle: 0x7fc74a77a050>
可以看到虽然2个线程显示调用了2次,但单例类只会被init一次,而2个线程获得的实例对象的内存地址也是一样的。
单例模式的线程安全解决了!