單例模式

我平常再寫單例模式時經常用這兩種方法:

方法一:

public class SingletonDome {
	//私有的構造方法是創建單例的基礎
	private SingletonDome(){
		System.out.println("singletonDome create");
	}
	private static SingletonDome singleton = new SingletonDome();
	
	public static SingletonDome getInstance(){
		return singleton;
	}
}

方法二:

public class SingletonDome {
	private SingletonDome(){
		System.out.println("singletonDome create");
	}
	private static SingletonDome singleton = null;
	
	public static synchronized SingletonDome getInstance(){
		if(singleton==null){
			singleton = new SingletonDome();
		}
		return singleton;
	}
}

第一種方法,在 JVM 加載單例類時,單例對象就會被建立,如果此時這個單例類在系統中還扮演其他角色,那麼在任何使用這個單例類的地方都會初始化這個單例變量,而不管是否會被用到。

   缺點不能延遲加載

第二種方法,當用戶第一次需要這個對象時才進創建,並時線程安全的,但是由於synchronized性能缺陷(之前我真沒什麼感覺..見測試用例)

public class LazySingleton implements Runnable{
	 private LazySingleton(){
	 System.out.println("LazySingleton is create");
	 }
	 private static LazySingleton instance = null;
	 public static synchronized LazySingleton getInstance(){
	 if(instance == null){
	 instance = new LazySingleton();
	 }
	 return instance;
	 }
	 public static void createString(){
	 System.out.println("create String");
	 }
	 
	 @Override
	 public void run() {
	 // TODO Auto-generated method stub
	 long beginTime = System.currentTimeMillis();
	 for(int i=0;i<1000000;i++){
	 LazySingleton.getInstance();
	 }
	 System.out.println(System.currentTimeMillis() - beginTime);
	 }
	 
	 public static void main(String[] args){
	 //LazySingleton.createString();
	 for(int i=0;i<5;i++){
	 new Thread(new LazySingleton()).start();
	 }
	 }

	}
打印:
LazySingleton is create
LazySingleton is create
LazySingleton is create
LazySingleton is create
LazySingleton is create
LazySingleton is create
290
593
585
598
603

今天發現兩種新的單例的寫法:

靜態內部類和枚舉

靜態內部類寫法:

public class SingletonDome {
 private SingletonDome(){
 System.out.println("singletonDome create");
 }
 private static class SingletonHolder{
 private static SingletonDome instance = new SingletonDome();
 }
 public static SingletonDome getInstance(){
 return SingletonHolder.instance;
 }
}

測試:

public class LazySingleton implements Runnable {
	private LazySingleton() {
		System.out.println("LazySingleton is create");
	}

	private static class SingletonHolder {
		private static LazySingleton instance = new LazySingleton();
	}

	public static LazySingleton getInstance() {
		return SingletonHolder.instance;
	}

	public static void createString() {
		System.out.println("create String");
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		long beginTime = System.currentTimeMillis();
		for (int i = 0; i < 1000000; i++) {
			LazySingleton.getInstance();
		}
		System.out.println(System.currentTimeMillis() - beginTime);
	}

	public static void main(String[] args) {
		// LazySingleton.createString();
		for (int i = 0; i < 5; i++) {
			new Thread(new LazySingleton()).start();
		}
	}

}
運行效果如下:
LazySingleton is create
LazySingleton is create
LazySingleton is create
LazySingleton is create
LazySingleton is create
LazySingleton is create
1
3
1
1
1

備註:

    當 SingletonDome 被加載時,其內部類並不會被初始化,故可以確保當 SingletonDome 類被載入 JVM 時,不會初始化單例類,

    而當 getInstance() 方法調用時,纔會加載 SingletonHolder,從而初始化 instance。

    同時,由於實例的建立是時在類加載時完成,故天生對多線程友好,getInstance() 方法也無需使用同步關鍵字。

枚舉方式:

public enum AnimalHelperSingleton {

    INSTANCE;

    private AnimalHelperSingleton(){

    }

    public Animal[] buildAnimalList(){
        final Animal[] animals = new Animal[10];

        animals[0] = new SimpleAnimal(Animal.AnimalClass.MAMMAL, 
                "Dog", true, Color.GRAY);
        animals[1] = new SimpleAnimal(Animal.AnimalClass.MAMMAL, 
                "Cat", true, Color.YELLOW);
        animals[2] = new SimpleAnimal(Animal.AnimalClass.AMPHIBIAN,
                "Frog", true, Color.GREEN);
        animals[3] = new SimpleAnimal(Animal.AnimalClass.BIRD,
                "Crow", true, Color.BLACK);
        animals[4] = new SimpleAnimal(Animal.AnimalClass.BIRD,
                "Cardinal", true, Color.RED);
        animals[5] = new SimpleAnimal(Animal.AnimalClass.ARTHROPOD,
                "Mantis", false, Color.GREEN);
        animals[6] = new SimpleAnimal(Animal.AnimalClass.ARTHROPOD,
                "Spider", false, Color.ORANGE);
        animals[7] = new SimpleAnimal(Animal.AnimalClass.MAMMAL, 
                "Tiger", true, Color.ORANGE);
        animals[8] = new SimpleAnimal(Animal.AnimalClass.MAMMAL, 
                "Bear", true, Color.BLACK);
        animals[9] = new SimpleAnimal(Animal.AnimalClass.BIRD, 
                "Owl", true, Color.BLACK);

        return animals;
    }

}
調用方式:Animal[] animals = AnimalHelperSingleton.INSTANCE.buildAnimalList();

優點:

1、 自由序列化;

2、 保證只有一個實例(即使使用反射機制也無法多次實例化一個枚舉量);

3、 線程安全;


話說寫單例用枚舉的很少哎,而且感覺不是那麼好理解。。。

單例--靜態內部類摘自:http://www.ibm.com/developerworks/cn/java/j-lo-Singleton/ 

單例--枚舉方式摘自:http://blog.csdn.net/horace20/article/details/37562513 

大家可以去看一下原文哦。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章