這就是傳說中的單例模式忆畅!O(∩_∩)O
一個某一類對象。
它只有唯一的一個對象實(shí)例尸执。
它有什么用?
因?yàn)橛行┠K必須保持唯一性缓醋,比如說線程池如失、緩存和注冊器等。
可不可以用全局變量來代替單例模式送粱?
單例模式是一種能夠確保創(chuàng)建唯一一個對象的途徑和方法褪贵。
你可以用全局變量來代替它,但是它的意義在于“確笨苟恚”二字脆丁。
它有啥優(yōu)點(diǎn)?
單例模式的作用在于它能夠在你想創(chuàng)建對象的時候創(chuàng)建动雹,即槽卫,你可以把握創(chuàng)建的時機(jī)。
而如果使用全局變量胰蝠,那么它只能在程序開始創(chuàng)建歼培,并在程序結(jié)束時釋放,它不是受你控制的茸塞。如果該全局變量十分占用資源躲庄,那么最好整個應(yīng)用自始至終都在使用它,否則全局變量的方法對系統(tǒng)不必要的開銷就非常大钾虐。
一個簡單的單例模式
P185展示了一個簡單的單例模式的基本構(gòu)成噪窘。另外,我寫了一篇跟Java有關(guān)的單例模式的博客效扫。
Singleton Pattern defined
它確保類有唯一一個實(shí)例倔监,并且提供了一個全局性的訪問點(diǎn)直砂。
P189展示了單例模式類圖的設(shè)計(jì)。
多線程環(huán)境下的單例模式
在多線程環(huán)境下各線程是獨(dú)立的丐枉,每個線程都可能擁有自己的單例哆键,那么從進(jìn)程的角度看一個進(jìn)程就可能有多個單例,那么這個就不是單例而是多例了嘛瘦锹!
其實(shí)主要要解決的就是多線程的互斥訪問籍嘹,針對JAVA語言的特性,作者建議在獲取實(shí)例的方法上加上synchronized關(guān)鍵字弯院,如P192所示的那樣辱士。這個很好理解,就是線程間的同步听绳,即各線程的公共資源颂碘。
但是這個synchronized是有代價的,這是因?yàn)橛玫絪ynchronized只是創(chuàng)建實(shí)例的那一刻椅挣,從那以后就用不著synchronized了头岔,但是你還需要為synchronized付出代價。
那有沒有其他的解決辦法呢鼠证?
- 如果getInstance()對你的應(yīng)用影響不大峡竣,那它可以什么都不做。因?yàn)橥綍管浖谋憩F(xiàn)力降低100個因子量九,所以對于面向高速傳輸?shù)拇a來說饥瓷,你就不要同步了饿凛。
- 轉(zhuǎn)向馬上要被創(chuàng)建的實(shí)例而不是那些不緩不慢的實(shí)例瘪阁。P193顯示了創(chuàng)建緊急單例實(shí)例的代碼臭蚁,這種途徑依賴于JVM,它能保證實(shí)例在所有線程訪問它之前被創(chuàng)建肌似。
- 使用雙重鎖來減少getInstance()的同步费就。先檢查實(shí)例是否被創(chuàng)建了,如果沒有川队,那就同步受楼,這可以是getInstance()只同步一次,如P194代碼所示呼寸。volatile能夠防止編譯器自作主張地優(yōu)化艳汽。
其他
單例模式的類一般不能繼承,也不建議被繼承对雪。
不要濫用單例模式河狐,它應(yīng)該是少而精的。
濫用全局變量會污染命名空間。
多類裝載器會導(dǎo)致多個實(shí)例而并非單例馋艺,所以要慎用栅干。