1.下面这个例子是工作中常见的单例模式...jdk1.5之后用volatile关键字禁止编译器重排序
package singleton; public class DoubleCheckSingleton { private volatile static DoubleCheckSingleton instance= null; private DoubleCheckSingleton(){} public static DoubleCheckSingleton getInstance(){ if(instance == null ) { synchronized(DoubleCheckSingleton.class) { if(instance==null) { instance = new DoubleCheckSingleton(); } } } return instance; } }
2.利用静态内部类生成单例,初始化单例在私有内部静态类中,其他线程无法看到初始化的编译器重排序。
package singleton; public class SingletonByHolder{ private SingletonByHolder(){}; public static SingletonByHolder getInstance(){ return SingletonHolder.instance; } private static class SingletonHolder { private static SingletonByHolder instance = new SingletonByHolder(); } }
3. 1和2的方法无法防止序列化和反序列化时生成不同的实例,如果单例类需要实现序列化的话,改成下面的方法可以预防(参考《Java程序性能优化》)
package singleton; import java.io.Serializable; public class SingletonByHolder implements Serializable{ private static final long serialVersionUID = 333332L; private SingletonByHolder(){}; public static SingletonByHolder instance; public static SingletonByHolder getInstance(){ instance = SingletonHolder.instance; return instance; } private static class SingletonHolder { private static SingletonByHolder instance = new SingletonByHolder(); } private Object readResolve(){ return instance; } }
测试类
package singleton; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class Test { public static void main(String[] args) throws IOException, ClassNotFoundException { SingletonByHolder instance = SingletonByHolder.getInstance(); FileOutputStream fo = new FileOutputStream("D:\serSingleton.txt"); ObjectOutputStream ob = new ObjectOutputStream(fo); ob.writeObject(instance); ob.flush(); ob.close(); fo.close(); FileInputStream fi = new FileInputStream("D:\serSingleton.txt"); ObjectInputStream oi = new ObjectInputStream(fi); SingletonByHolder instance2 = (SingletonByHolder) oi.readObject(); oi.close(); fi.close(); System.out.println(instance == instance2); } }
如果注释掉private Object readResolve()方法测试类打印false,反序列化后两个实例不是同一个;没注释掉的话打印true,反序列化后两个实例是同一个。