一、最简单的方式
public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } 这是最简单的方式。该方式适合于单线程运行,如果在多线程环境下,需要对该方法进行同步。由此引出第二个方法。 二、线程同步的方法public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } 该方法可以在多线程环境下运行。但是由于在每次调用时都需要进行同步,因此消耗了一定的代价。因为只需要 在第一次创建实例时需要进行同步,其他情况下是不必须的。由此引出第三个方法。 三、改进的线程同步的方法public static Singleton getInstance() { if (instance == null) { synchronized(Singleton.class) { instance = new Singleton(); } } return instance; } 该方法只需要在第一次创建实例时进行同步,减少了系统的开销。但是,当第二个线程进入synchronized同步块时, 没有检查实例是否为空,会存在线程安全问题。由此引出第四个方法,即双重检查锁定方法。 四、双重检查锁定方法public static Singleton getInstance() { if (instance == null) { synchronized(Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; }
该方法减少了线程同步引起的开销,同时不存在线程安全问题。根据Java的内存模型,应该将instance引用类型
声明为volatile,该双重检查锁定方法可以正常运行。
五、饿汉式方法public class Singleton
private static Singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance() {
return instance;
}
}
当类被加载时,静态变量instance会被初始化,此时类的私有构造函数会被调用,单例类的唯一实例将被创建。可确保
单例对象的唯一性。关于Java类的构造函数执行顺序,请参考另一篇文章《Java构造函数》。该方法的优点在于
无须考虑多线程访问问题,可以确保实例的唯一性。但是,由于在类被加载时就创建了类对象,无论该类是否会被使用,
都占用系统内存。
六、IoDH技术
IoDH,即Initializationon on Demand Holder的缩写。IoDH技术单例类中增加一个静态(static)内部类,在该内部类中创建
单例对象,再将该单例对象通过getInstance()方法返回给外部使用。
public class Singleton {
private Singleton() {
}
private static class HolderClass {
private final static Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return HolderClass.instance;
}
}
通过使用IoDH,既可以实现延迟加载,又可以保证线程安全,不影响系统性能,是一种最好的Java语言单例模式实现方式。
其缺点是与编程语言本身的特性相关,很多面向对象语言不支持IoDH。