在上一篇文章 单例模式(上)—-如何优雅地保证线程安全问题中,我们采取了懒汉式写法来写我们的单例模式,并且重点讲解了懒汉式中线程安全的问题。这篇我们来讲讲单例模式中的其他几种写法。
上篇文章中,方法和变量的声明都忘了加上“static”的声明,这里提醒一下。
懒汉式
懒汉式在上节我们已经讲过了,直接给出代码:
public class Singleton { private static volatile Singleton instance = null; private Singleton(){}; public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class){ if (instance == null) { instance = new Singleton(); } } } return instance; } } 懒汉式这种方式需要我们来自己加锁,保证线程安全的问题。
不过就算我们保证了线程安全,这种写法还是无法保证存在唯一一个对象实例。因为别人还是可以通过反射的方式来创建一个新的对象。我写个示例:
public class Singleton { public static void main(String[] args) throws Exception{ //获得构造器 Constructor<Singleton> c = Singleton.class.getDeclaredConstructor(); //把构造器设置为可访问 c.setAccessible(true); //创建两个实例对象 Singleton s1 = c.newInstance(); Singleton s2 = c.newInstance(); //比较下两个实例是否相等 System.out.println(s1 == s2); } } 打印结果:false。
所以懒汉式这种方式还是存在一些缺点的。
饿汉式
所谓饿汉式,就是一开始把对象实例创建出来,而不是等getInstance这个方法被调用才来创建对象。代码如下:
public class Singleton2 { private static Singleton2 instance = new Singleton2(); //私有构造器 private Singleton2(){}; public static Singleton2 getInstance() { return instance; } } 饿汉式与懒汉式相比,我们不用管线程安全的问题,代码看起来也比较简洁。
但是,由于对象一开始就被创建出来了,假如
