我平常再写单例模式时经常用这两种方法:
方法一:
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 createLazySingleton is createLazySingleton is createLazySingleton is createLazySingleton is createLazySingleton is create290593585598603
今天发现两种新的单例的写法:
静态内部类和枚举
静态内部类写法:
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 createLazySingleton is createLazySingleton is createLazySingleton is createLazySingleton is createLazySingleton is create13111
备注:
当 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
大家可以去看一下原文哦。