1)简介 单例设计模式是一种创建设计模式,单例类只能有一个实例存在。 核心步骤:私有构造,自建实例,提供访问方法 2)实现代码 a.饿汉式 public class Singleton{ //自建实例,注意是静态变量以确保唯一,私有 private static Singleton instance = new Singleton(); //私有构造,防止其他地方创建对象 private Singleton(){} //提供访问单例的方法 public Singleton getInstance(){ return instance; } } 饿汉式优点是一加载类就创建实例,避免了线程安全问题,缺点是单例实例可能很久不使用,一直存在于内存有些浪费资源(不过现在内存貌似比较廉价,可以忽略这点吧) b.懒汉式 public class Singleton{ //声明变量,暂时不创建实例 private static Singleton instance; //私有构造,防止其他地方创建对象 private Singleton(){} //提供访问单例的方法 public Singleton getInstance(){ //判断是否为空,根据结果创建实例 if(instance == null){ instance = new Singleton(); } return instance; } } 这种懒汉式虽然节约了资源,但是存在线程安全问题:即一个线程判断为空后失去CPU执行权限,另一个线程又判断为空,两个线程最终都创建了一个实例。 懒汉式同步方法模式: public class Singleton{ //声明变量,暂时不创建实例 private static Singleton instance; //私有构造,防止其他地方创建对象 private Singleton(){} //提供访问单例的方法 public synchronized Singleton getInstance(){ //判断是否为空,根据结果创建实例 if(instance == null){ instance = new Singleton(); } return instance; } } 这种懒汉式当getInstance方法调用的次数少时可以,调用多的时候因为对整个方法都进行加锁,会影响性能。 懒汉式双检锁模式(DCL double-checked locking): public class Singleton{ //声明变量,暂时不创建实例 private static Singleton instance; //私有构造,防止其他地方创建对象 private Singleton(){} //提供访问单例的方法 public Singleton getInstance(){ //判断是否为空,根据结果创建实例 if(instance == null){ synchronized(Singleton.class){ if(instance == null){ instance = new Singleton(); } } } return instance; } } 这种懒汉式即线程安全,又不会因为同步创建对象影响性能 但是,如果单例对象需要进行序列化和反序列化操作,单例模式会被破坏掉,原因稍后说明 c.登记模式/静态内部类 public class Singleton{ //静态内部类持有实例 private static class SingletonHolder{ private static final Singleton INSTANCE = new Singleton(); } //私有构造 private Singleton(){} public static Singleton getInstance(){ return SingletonHolder.INSTANCE; } } 静态内部类模式利用内部类加载时创建单例实例,避免了线程安全问题,且类加载是在主动调用的时候加载,因此又具备lazy初始化的功能,另外单例实例是静态内部类的属性,反序列化时虽然通过反射创建了单例类的实例,但是通过getInstance获取实例的时候依然是原来的实例。 d、枚举 public enum Singleton{ INSTANCE; } 3)返序列化破坏单例的说明 序列化与反序列化代码: public static void main(String[] args) throws IOException, ClassNotFoundException { //Write Obj to file ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("test")); oos.writeObject(Singleton.getSingleton()); //Read Obj from file File file = new File("test"); ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file)); Singleton newInstance = (Singleton) ois.readObject(); //判断是否是同一个对象 System.out.println(newInstance == Singleton.getSingleton()); } 输出结果为false ObjectInputStream类的readObject 读取对象时返回的对象是调用 readOrdinaryObject 返回的对象, readOrdinaryObject 方法有下面一段代码,返回的是其中的obj Object obj; try { obj = desc.isInstantiable() ? desc.newInstance() : null; } catch (Exception ex) { throw (IOException) new InvalidClassException( desc.forClass().getName(), "unable to create instance").initCause(ex); } isInstantiable 方法为校验是否可以序列化,如果可以返回true,我们需要序列化,肯定返回true 故返回的对象实际为desc.newInstance()返回的对象,而desc为Class对象,显然最终返回的是通过反射新建的一个实例,已经不是原来的实例了。