单例模式是最常用到的设计模式之一,介绍单例模式的书籍一般都会提到 饿汉式
和 懒汉式
这两种实现方式。
先来两个线程安全的既可用的饿汉式:
public class SingleObject { //利用static特性,创建一个实例 private static SingleObject instance = new SingleObject(); //让构造函数私有化 private SingleObject(){} //对外暴露获取实例的方法 public static SingleObject getInstance(){ return instance; } public void showMessage(){ System.out.println("this is a singletonDemo!"); } }
public class Singleton { //同上边的一样,改为静态代码块制造实例 private static Singleton instance; static { instance = new Singleton(); } private Singleton() {} public static Singleton getInstance() { return instance; } }
再来个单线程可用的线程不安全的懒汉式:
public class Singleton { private static Singleton singleton; private Singleton() {} public static Singleton getInstance() {
if (singleton == null) {//多线程环境下,前边线程此处判断没执行完,后边线程跟进来,会导致制造多个实例,失去单例模式的意义 singleton = new Singleton(); } return singleton; } }
上边懒汉式线程不安全,那就改造一下,为懒汉式加个锁:可以用但是不推荐使用
public class Singleton { private static Singleton singleton; private Singleton() {} //效率太低了,每个线程在想获得类的实例时候,执行getInstance()方法都要进行同步。 public static synchronized Singleton getInstance() { if (singleton == null) { singleton = new Singleton(); } return singleton; } }
接下来演示一个错误的不可用的懒汉式改造,目的就是为了线程安全和效率。
public class Singleton { private static Singleton singleton; private Singleton() {} public static Singleton getInstance() { if (singleton == null) {
//多线程判断为空都进来了,在这儿排着队new实例,好比自欺欺人。 synchronized (Singleton.class) { singleton = new Singleton(); } } return singleton; } }
抛砖引玉,引出来的双检索模式:推荐使用。
public class Singleton { //关键字valatile:解决可见性,防止重排序,无法保证原子性。 private static volatile Singleton singleton; private Singleton() {} public static Singleton getInstance() { if (singleton == null) {//valatile的可见性,此处表现为提高效率 synchronized (Singleton.class) { if (singleton == null) { //valatile的可见性,保证此处判断实时性,线程安全性,只会创建一次实例。 singleton = new Singleton(); } } } return singleton; } }
比饿汉式多了懒加载特性的静态内部类创建单例模式:推荐使用
public class Singleton { private Singleton() {} //静态内部类不同于静态成员和代码块,不会在主类加载的时候立即加载,而是在调用的时候第一次加载,即懒加载 private static class SingletonInstance {
//TODO 内外部类的关系 private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return SingletonInstance.INSTANCE; } }
最后来一个高大上的根据枚举特性实现单例模式,就睡觉啦!
public enum Singleton { INSTANCE; public void whateverMethod() { system.out.println("枚举模式好,但是用的少。我最喜欢的"); }
public static void main(String[] args) {
SingletonEnum.INSTANCE.whateverMethod();
}
}