线程——单例模式
首先我們要了解單例模式,那么什么是單例模式
單例模式:如果一個類在程序中值存在一個實例 通過一定的編程手段來進行限制,防止不小心在代碼中創(chuàng)建了多個實例
單例模式的實現(xiàn)有二種方式一種是餓漢模式另一種是懶漢模式 下面我介紹給大家
餓漢方式
餓漢方式顧名思義就是餓了的人吃飯,只要是能吃的都會直接吃 ,這里對應(yīng)到代碼就是不管這個對象能不能用到先創(chuàng)建了這個對象在說 下面是代碼的實現(xiàn)
getInstance 得到的類內(nèi)部的靜態(tài)成員
靜態(tài)成員是和類相關(guān)的(在類對象中),每個類只有一個類對象
此時調(diào)用getInstance 得到的實例其實是同一個對象
只要類一被加載就會進行實例化 就會給對象分配內(nèi)存
懶漢方式
當類加載的時候,不會創(chuàng)建實例,直到第一次使用這個實例了再創(chuàng)建
要比餓漢模式 更加常用 效率高
如果這個對象沒有被使用那么,也就不會被涉及到內(nèi)存分配,也就節(jié)省了不必要開銷
餓漢模式中不管是否用到這個實例,都會分配內(nèi)存(分配內(nèi)存操作可能會分配很大的內(nèi)存,非常消耗時間)
那么在多線程編程的時候單例模型是否安全的,如果不安全應(yīng)該如何來改進
餓漢模式
實例的創(chuàng)建是在Singleton 類被加載的時候進行的,類被加載的時機只有一次(JVM內(nèi)部控制的)此時就和多線程無關(guān)了
如果多個線程調(diào)用getInstance,此時不涉及到多線程同時修改通一個變量,此時也不會有安全問題
懶漢模式
當多個線程同時調(diào)用getInstance的時候,有可能會多個線程同時修改,也就存在線程安全問題
本質(zhì)上還是多個線程修改同一個變量進行修改 并且修改的變量不是原子的
修改操作分為好幾步
1.獲取instance的值
2先判定instance非空
3.非空就new對象
4.把new得到的結(jié)果寫回到instance
當instance 為空時 因為是搶占式執(zhí)行 ,所以會很多的同時獲取到instance 為空時 就會創(chuàng)建很多個對象
存在線程安全問題
那么我們應(yīng)該怎么樣去解決線程安全問題呢?
沒錯還是加鎖。下面就是懶漢模式的進階版本
當實例被創(chuàng)建之前,多線程調(diào)用getInstance ,就會進入第一個if,從而觸發(fā)鎖操作,這個鎖操作就能保證線程安全,獲取鎖完畢之后,第二個if 就能保證最終的new值執(zhí)行一次
如果實例已經(jīng)被創(chuàng)建之后,多線程調(diào)用getInstance,第一個if進不去,也就不會觸發(fā)鎖操作(提升了性能,此時也沒有線程安全問題),直接返回instance ,也避免了不必要的鎖開銷
那么這個版本的懶漢模式是否就是線程安全的呢?
不一定,當?shù)谝粋€線程獲取到鎖的時候,其他線程就會快速讀取instance的值,編譯器可能會進行優(yōu)化,第二次讀到的內(nèi)容不一定是從內(nèi)存中重新讀取的,也可能直接使用第一次讀到的結(jié)果。
所以它會再去new一個對象,也就不符合單例模式了
那么怎么解決尼 ,可以使用volatile關(guān)鍵字 代碼如下
總結(jié)
- 上一篇: HALCON示例程序circles.hd
- 下一篇: 1.Python数据类型、方法