单例模式双重校验锁_滴滴面试官:如何实现一个线程安全的单例模式
單例模式作為最常見的設(shè)計模式,有很多實(shí)現(xiàn)方式,今天介紹一下單例模式相關(guān)的內(nèi)容。
什么是單例模式
從字面上理解,單例模式需要確保一個類只有一個對象。比如線程池、緩存、日志對象、打印機(jī)驅(qū)動對象、顯卡驅(qū)動對象等,這些類的對象往往只需要一個實(shí)例就可以。如果一個類的對象需要被頻繁創(chuàng)建,那么也會需要頻繁GC,單例模式就可以解決這樣的問題。
單例模式的實(shí)現(xiàn)方式
單例模式的實(shí)現(xiàn)方式非常多,但總體上可以分為兩類:餓漢式和懶漢式。餓漢式是在類加載過程中就創(chuàng)建對象的方式,而懶漢式是需要使用時才會去創(chuàng)建對象的方式,這兩種方式各有特點(diǎn)。餓漢式存在的問題是如果要創(chuàng)建的對象占用的空間非常大,且使用頻率非常低,那么這種方式是非常不劃算的。而懶漢式有可能會遇到并發(fā)問題,這就要求我們需要考慮對創(chuàng)建對象的過程進(jìn)行加鎖。不管是餓漢式還是懶漢式,創(chuàng)建的對象一般都得使用static關(guān)鍵字進(jìn)行修飾。
餓漢式單例
public class Singleton {private static Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance() {return instance;} }上面的餓漢式單例在類加載時創(chuàng)建了一個對象,然后創(chuàng)建了一個private修飾的構(gòu)造方法防止通過構(gòu)造方法創(chuàng)建對象。
懶漢式單例(非線程安全版)
public class Singleton {private static Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;} }上面這種單例方式的創(chuàng)建我們可以很容易看出當(dāng)需要使用這個對象時才會去創(chuàng)建,滿足懶漢式的要求。但是這種創(chuàng)建單例的方式是有缺陷的,當(dāng)多個線程同時獲取對象,在判斷對象是否為空的地方,如果兩個線程同時到達(dá),那么就會同時進(jìn)入這個條件中,創(chuàng)建多個對象。下面提出一些線程安全的懶漢式單例。
懶漢式單例(synchronized修飾的線程安全版)
public class Singleton {private static Singleton instance;private Singleton() {}public static synchronized Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;} }基于上面的非線程安全版本,我們在getInstance()方法上加上了synchronized鎖,就變成了線程安全的版本。但是這種直接在方法上加鎖的方式其實(shí)對并發(fā)的效率影響是很大的,盡管在JDK6中對synchronized做了很大優(yōu)化,但是仍然不能滿足我們對高并發(fā)的要求,下面介紹一下更加高效的雙重校驗鎖版。
懶漢式單例(雙重校驗鎖版)
public class Singleton {private static volatile Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {synchronized(Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;} }我們又基于前面的非線程安全的版本實(shí)現(xiàn)了這個雙重校驗鎖版的懶漢式單例,如果多個線程同時在外層判斷對象為空時,開始搶占鎖資源,搶到的線程創(chuàng)建對象,其他線程就不再需要創(chuàng)建線程了。這種方式的優(yōu)點(diǎn)在于只有第一次搶奪資源的時候需要進(jìn)行同步,后續(xù)的并發(fā)都會判斷對象不為空,直接返回對象。
懶漢式單例(靜態(tài)內(nèi)部類版)
public class Singleton {//靜態(tài)內(nèi)部類private static class SingletonHandler {private static Singleton instance = new Singleton();}private Singleton() {}public static Singleton getInstance() {return SingletonHandler.instance;} }該方式依然是懶漢式單例,只不過利用靜態(tài)內(nèi)部類實(shí)現(xiàn),同樣也是線程安全的。
餓漢式單例(枚舉版)
public class EnumSingleton {private EnumSingleton() {}public static EnumSingleton getInstance(){return Singleton.singletonFactory.getInstance();}private enum Singleton {singletonFactory;private EnumSingleton instance;private Singleton() { //枚舉類的構(gòu)造方法在類加載時被實(shí)例化instance = new EnumSingleton();}public EnumSingleton getInstance() {return instance;}} }上面是利用枚舉創(chuàng)建單例對象的方法,利用枚舉類加載時會實(shí)例化構(gòu)造方法的特點(diǎn)進(jìn)行單例模式的實(shí)現(xiàn),是一種比較推薦使用的方法。
總結(jié)
以上是生活随笔為你收集整理的单例模式双重校验锁_滴滴面试官:如何实现一个线程安全的单例模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: python整数类型提供了4种进制表示_
 - 下一篇: 英雄联盟发布最新处罚公示:23628个违