python多執行緒安全的單例模式
常用的軟體設計模式有23種,單例模式便是其中的一種。那麼在面向過程的語言中,我們常常用到全域性變數。其實單例模式和全域性變數在某種意義上來說近似。譬如我們要讀取某些配置檔案,有一個專門的類來封裝好了,但是如果不用單例模式,會造成程式例項化很多配置檔案類的物件,這樣的話會造成極大的混亂。再有就是在軟體協作開發之中,向上層提供介面的時候,最好也是用單例模式。那麼總的來說,單例模式就是面向物件程式設計的一種設計模式,單例模式保證了在程式執行中該類只例項化一次,並且提供了一個全域性訪問點。
那麼怎麼實現呢?程式碼如下:
import threading def synchronized(func): func.__lock__ = threading.Lock() def lock_func(*args, **kwargs): with func.__lock__: return func(*args, **kwargs) return lock_func class Singleton(object): instance = None @synchronized def __new__(cls, *args, **kwargs): """ :type kwargs: object """ if cls.instance is None: cls.instance = super().__new__(cls) return cls.instance def __init__(self, num): self.a = num + 5 def printf(self): print(self.a) a = Singleton(3) print(id(a)) b = Singleton(4) print(id(b))
下面分析一下上段程式碼,看不懂裝飾器的去我上一篇博文去看。這裡我們先忽略裝飾器,先看類,可以看出這裡我們先定義了一個類屬性instance,接著我們重寫了父類的__new__方法,這個方法就是我們在例項化一個物件時最先呼叫的一個方法。和其他靜態語言不一樣,其他靜態語言,直接呼叫了構造方法,一般情況下初始化的程式也寫在構造方法之中。而python例項化一個物件和初始化是分開的。__new__是類方法,__init__是例項方法,也就是說,__init__是在物件已經建立完成之後,才執行。
在python3中,呼叫父類的方法是用super()來呼叫。所以我們這裡的思路就是,還是用父類的方法去創造,但是我們要加一個判斷,就是說,當這個物件也就是類屬性並不為空的時候,我們就不在例項化,而是返回一個已經例項化的類屬性。
那麼這裡思考一個問題,如果就這樣可以嗎,答案是可以的,但是這種不具備通用性,多執行緒的時候依然會造成例項化出幾物件。所以再做專案時,一定要考慮這種情況。所以我們這裡通過鎖來進行保護,保證多執行緒的情況下同一時刻只有一個執行緒訪問,這就保證了單例模式的安全。
怎麼驗證呢,程式碼也有體現,id方法是內建方法,作用是列印物件的引用地址。執行結果如下:
可以看出是成功的。