1. 程式人生 > >JAVA 與 MyCat(2) 單例模式

JAVA 與 MyCat(2) 單例模式

通過mycat來學習java了^^。

接前一篇:http://blog.csdn.net/john_chang11/article/details/78668667

MycatServer server = MycatServer.getInstance();

獲取MyCat例項,其實就是讀取配置檔案,並驗證正確性等。

MyCat例項必須全域性唯一,所以這裡涉及到JAVA的單例項模式,就是一個類只有唯一一個例項物件存在。先來看看mycat原始碼是怎麼做的:

public class MycatServer {
	private static final MycatServer INSTANCE = new MycatServer();
	
	public static final MycatServer getInstance() {
		return INSTANCE;
	}

	private MycatServer() {
		......
	}
}

首先,將構造方法定義成私有的,這樣外界不能再例項化該類。然後,提供一個公有的靜態方法,使外界只能通過該方法來獲取類例項,該方法返回一個型別為類本身的靜態屬性值,該屬性值在類載入時呼叫私有構造方法初始化。這就保障了,該類只有唯一一個例項物件的存在。

上面這種寫法是單例項建立的餓漢模式,執行緒安全,但浪費記憶體空間,不過mycat要執行MycatServer類是肯定要裝載的,所以原始碼裡這樣用也沒有問題。單例項模式的寫法還有別的寫法,一起看看。

1.懶漢,省記憶體空間,但執行緒不安全,不推薦使用

public class Singleton {
    private static Singleton instance=null;
    private Singleton(){
        
    }
    public static Singleton getInstance(){
        if(instance==null){
            instance=new Singleton();
        }
        return instance;
    }
}

使用時才初始化例項,所以省記憶體,但也影響了速度,而且執行緒不安全,只能在單執行緒環境下可行,不推薦使用。

2.懶漢,執行緒安全,但效率低,不推薦使用

public class Singleton {
    private static Singleton instance=null;
    private Singleton(){
        
    }
    public static synchronized Singleton getInstance(){
        if(instance==null){
            instance=new Singleton();
        }
        return instance;
    }
}
這種方式也是在使用時才初始化,省記憶體,但每次呼叫getInstance()方法時,都需要獲取同步鎖,非常耗時,也不推薦使用。

3.懶漢,雙重檢查鎖,依然有問題,不推薦使用

public class Singleton {
    private static Singleton instance=null;
    private Singleton(){
        
    }
    public static Singleton getInstance(){
        if(instance==null){
            synchronized(Singleton.class){
                if(instance==null){
                    instance=new Singleton();
                }
            }
        }
        return instance;
    }
}


4.餓漢,執行緒安全,效率高,但記憶體使用率低,推薦使用

public class Singleton {
    private static Singleton instance=new Singleton();
    private Singleton(){
        
    }
    public static Singleton getInstance(){
        return instance;
    }
}
這種方式,是利用JVM的機制:靜態例項的初始化是ClassLoader經由[ThreadSafe]來完成,所以是執行緒安全的。該方法去除的同步,且類載入時就建立例項,所以效率高。但由於是類載入時就建立例項,所以記憶體使用率低,不過既然使用該類一般就會初始化該類的一個例項,所以該仍然推薦使用。

5.靜態內部類,集所有優點於一身,推薦使用

public class Singleton {
    private Singleton(){
        
    }
    private static class SingletonHolder{
        private final static Singleton instance=new Singleton();
    }
    public static Singleton getInstance(){
        return SingletonHolder.instance;
    }
}
內部類不會隨主類載入而載入,只有在第一次使用時才會載入,而單例項又是內部類的靜態例項,所以用這種方式獲取單例項,即是lazy loading,節省記憶體,又是執行緒安全且不需要同步鎖的。所以用這種方式獲取單例項最好。不過,使用時才建立例項,會對第一次呼叫產生影響,所以這種方式與第4種方式,可以互補使用:如果單例項類一定需要初始化,就用第4種,如果不一定需要初始化,就用第5種。