很多框架中,单例模式是一个非常常见的设计模式,创建单例模式也非常简单:

public class Singleton {

    // 1.构造器私有化,使得外部不能实例化(饿汉式-->不管用不用,都创建它)
    private Singleton() {
    }

    // 2.本类内部创建对象实例,不管用不用都创建,项目启动时即加载
    private final static Singleton instance = new Singleton();

    // 3.提供一个公有的静态方法,返回实例对象,供外部使用
    public static Singleton getInstance() {
        return instance;
    }
}

  上面的方法虽然简单,但是比较浪费资源,无论用或是不用,都会在项目启动时候创建。那么如何优雅的创建单例模式了?必须保证不使用的时候不创建,使用时才创建,而且还得线程安全。

方法一:(推荐使用)
  首先,利用静态内部类和非静态内部类一样,都是在被调用时才会被加载的特性,保证其什么时候使用,什么时候创建。其次,利用jvm会保证在多个线程同时初始化一个类时,只有一个线程去执行这个类的构造器,来保证线程安全。

public class Singleton {

    // 1.构造器私有化,外部不能实例化,且在类初始化时,jvm会保证只有在多个线程同时去初始化一个类时,只有一个线程去执行这个类的构造器
    private Singleton() {
    }

    // 2. 只有在使用的时候才会被加载,和普通内部类一样
    private static class NewSingleton {
        private static final Singleton INSTANCE = new Singleton();
    }

    // 3. 没有调用此方法时,不会加载上面的静态内部类
    public static Singleton getInSingleton() {
        return NewSingleton.INSTANCE;
    }
}

方法二:(加锁实现)
  首先,保证不用不创建,其次利用锁保证线程安全

public class Singleton {

    // 1.用volatile关键字,使得所有线程都能看到共享内存的最新状态。
    private static volatile Singleton instance;

    // 2.构造器私有化,外部不能实例化
    private Singleton() {
    }

    // 3.提供一个公有的静态方法,返回唯一的实例对象
    public static Singleton getInstance() {

        // 4.不为空肯定不需要进入
        if (instance == null) {
            
            //5.当两个线程同时进入,本句之上时,若没有下一步的判空操作,仍会依次实例化两个实例
            synchronized (Singleton.class) {
                
                //6.必须再次判空,不然锁生效,但单例不生效。
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

  方法二也是一个创建单例的好方法,但较一而言显得繁琐,且容易出错。