IOS多线程安全-单例模式的应用

By | 2015年5月24日

多线程安全中有个概念叫:临界区,意思是有一段代码,它只能被一个线程调用,这段代码就叫临界区。

在单例模式中,我们常常会判断当前类的实例是否已经存在了, 如果已存在那就返回当前的实例,如果不存在就创建一个。

传统操作下,可以使用条件语句判断,但是多线程下就不行了,为了保证当多个线程调用单例模式代码时,能准确的进行单列判断,我们需要使用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个线程获得的实例对象的内存地址也是一样的。

单例模式的线程安全解决了!