在上一篇文章咱們給出了單例的設計模式,直接給出了線程安全的實現方法。單例的實現有多種方法,以下面: javascript
class SwiftSingleton { class var shared: SwiftSingleton { if !Inner.instance { Inner.instance = SwiftSingleton() } return Inner.instance! } struct Inner { static var instance: SwiftSingleton? } }這段代碼的實現,在shared中進行條件判斷,若是Inner.instance.爲空就生成一個實例,這段代碼很簡單看出當線程同時訪問SwiftSingleton.shared方法時,會有以下問題出現,線程A判斷Inner.instance爲空,進入if語句後當即切換到線程B執行,線程B也進行判斷,因爲線程A只是進入了if語句,這行代碼
Inner.instance = SwiftSingleton()並無執行,這時Inner.instance仍是爲空,純種B也進行了if語句,這種狀況下就會建立多個實例,沒有保證明例的惟一性。上面的理論分析基本上任何一篇文章都會講的,也不能理解,關鍵問題,如何測試上面的理論是否正確呢?
其實要實現上面的例子不是很難,建立N個線程,讓他同時訪問SwiftSingleton.shared的方法,而後將所返回值保存最後比較引用。原理很正確,可是建立線程的過程也是極爲耗時的,如今的電腦執行速度又很是快,模擬具備不穩定性。如何才能最大的程序測試上面的安全性呢?這裏咱們能夠考慮一個現實的問題,假設找1000人經過一段100米的賽道,咱們想要更多的人同時去衝刺終點,越多越好。若是你找一我的,告訴他去跑100米,而後再找一下,這種確定同時到達終點的概率很底。怎麼辦才能讓更多的人在同一時刻到達終點呢?問題很簡單,讓這1000人有一個同一塊兒跑點,讓他們都準備好了,隨着一聲令下,一塊兒奔跑。回到技術問題,咱們想要更多的線程訪問SwiftSingleton.shared方法,只要先準備好全部的線程,而後發一個信號,讓他們同時去訪問這個方法就能夠了。 java
實現代碼以下: 設計模式
class SwiftSingletonTest: XCTestCase { let condition = NSCondition() let mainCondition = NSCondition() let singleton: NSMutableArray = NSMutableArray() let threadNumbers = 1000 var count = 0 func testSingletonThreadSafe() { for index in 0...threadNumbers { NSThread.detachNewThreadSelector("startNewThread", toTarget: self, withObject: nil) } condition.broadcast() mainCondition.lock() mainCondition.wait() mainCondition.unlock() checkOnlyOne() } func startNewThread() { condition.lock() condition.wait() condition.unlock() let temp = SwiftSingleton.shared count++ singleton.addObject(temp) if count >= threadNumbers { mainCondition.signal() } } func checkOnlyOne () { let one = singleton[0] as SwiftSingleton for temp : AnyObject in singleton { let newTemp = temp as SwiftSingleton if(newTemp !== one) { XCTFail("singleton error!"); break; } } } }
這段代碼主要使用了NSCondition進行同步,其中NSCondition分爲兩組,condition主要負責除主線程外的線程,在for語句中會建立並啓動N(threadNumbers)個線程,每一個線程啓動後都會去執行startNewThread方法,執行到語句 安全
condition.wait()會掛起當前線程,當全部線程都建立並啓動完時,主線程會執行
condition.broadcast()來通知掛起的N個線程繼承執行,此時主線程調了
mainCondition.wait()主線和進入持起狀態,此處將主線程掛起是爲了在全部線程執行完,依次檢查取得引用的惟一性。
if count >= threadNumbers { mainCondition.signal() }當全部線程執行完時,通知主線程開始檢查引用 ,執行結果以下:
從上面執行結果能夠看出,這種單例並不能保證惟一性。上面用到了NSMutableArray類,網上說是線程不安全的,這裏用的Swift語言,這麼多線程一塊兒操做暫沒有發現異常...... 多線程
class SwiftSingleton { class var shared: SwiftSingleton { return Inner.instance } struct Inner { static let instance: SwiftSingleton = SwiftSingleton() } }
static let instance: SwiftSingleton = SwiftSingleton()首次訪問Inner.instance時纔會建立SwiftSingleton,此處的延遲加載由Swift語言原生提供
class SwiftSingleton { class var shared: SwiftSingleton { dispatch_once(&Inner.token) { Inner.instance = SwiftSingleton() } return Inner.instance! } struct Inner { static var instance: SwiftSingleton? static var token: dispatch_once_t = 0 } }