单例模式实现
一.实现双重校验锁
public class Singleton { private volatile static Singleton singleton; private Singleton (){} public static Singleton getSingleton() { if (singleton == null) { synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; } }特点:通过关键字synchronized保证高并发下,初始化对象为单例。缺点性能较差,对象属性需要volatile进行修饰防止编译期间指令重排序,导致返回对象为null。
二.通过类加载机制
public class Singleton { private static Singleton instance = new Singleton(); private Singleton (){} public static Singleton getInstance() { return instance; } } 或 public class Singleton { private Singleton instance = null; static { instance = new Singleton(); } private Singleton (){} public static Singleton getInstance() { return this.instance; } }特点:饿汉模式,ClassLoader的loadClass方法在加载类的时候使用了synchronized关键字。也正是因为这样, 除非loadClass被重写,这个方法默认在整个装载过程中都是同步的(线程安全的),保证方法调用前已被初始化一次。
三.利用内部类
public class Singleton { private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } private Singleton (){} public static final Singleton getInstance() { return SingletonHolder.INSTANCE; } }特点:使用静态内部类,借助了classloader来实现了线程安全,这与饿汉模式有着异曲同工之妙,但是他有兼顾了懒汉模式的lazy-loading功能,相比较之下,有很大优势。
四.利用枚举
public enum Singleton { INSTANCE; public void whateverMethod() { } }特点:解决通过反序列化导致单例破坏,代码简洁。
五.通过CAS
public class Singleton { private static final AtomicReference<Singleton> INSTANCE = new AtomicReference<Singleton>(); private Singleton() {} public static Singleton getInstance() { for (;;) { Singleton singleton = INSTANCE.get(); if (null != singleton) { return singleton; } singleton = new Singleton(); if (INSTANCE.compareAndSet(null, singleton)) { return singleton; } } } }特点:不通过锁的机制。
问题:单例的破坏
public class Test { public static void main(String[] args) throws FileNotFoundException, ClassNotFoundException { // 获取单例对象 Eagersingleton instance = Eagersingleton.getInstance(); // 通过反序列化读取对象 Eagersingleton instance2 = null; try { ObjectOutputStream oossStream = new ObjectOutputStream( new FileOutputStream("D:/EagersingletonTest.txt")); // 通过序列化把对象写到文件中 oossStream.writeObject(instance); oossStream.flush(); oossStream.close(); // 读取文件的对象 ObjectInputStream ois = new ObjectInputStream(new FileInputStream( "D:/EagersingletonTest.txt")); instance2 = (Eagersingleton) ois.readObject(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(instance); System.out.println(instance2); } } /** * @Descrption * @ClassName Eagersingleton * @Author qiu_lijun * @Date 2019/5/23 17:53 * @Version 1.0 */ public class Eagersingleton implements Serializable { private static final long serialVersionUID = 888L; private static Eagersingleton m_instance = new Eagersingleton();// 初始化时已经自行实例化 // 私有默认构造方法 private Eagersingleton() { } // 静态工厂方法 public static Eagersingleton getInstance() { return m_instance; } /* public Object readResolve() { return m_instance; }*/ }在调用readObject方法中,会利用反射回去对象实例。假如为在类中定义readResolve方法,就会返回一个新的对象。导致单例模式被破坏。解决方法重写readResolve方法。