1 基本概念

1、定义

  • 保证一个类只有一个实例,并提供一个访问该实例的全局访问点。

2、使用场景

  • Windows的任务管理器、回收站。
  • 配置文件的读取类。
  • 网站的计数器。
  • 数据库连接池。
  • ……

3、优点

  • 减少系统性能开销。
  • 优化共享资源的访问。

4、实现方式

  • 饿汉式(线程安全,调用效率高,不能延时加载)。
  • 懒汉式(线程安全,调用效率不高,可以延时加载)。
  • DCL懒汉式(由于JVM底层内部模型原因,偶尔会出现问题,不建议使用)。
  • 静态内部类式(饿汉式改进,线程安全,调用效率高,可以延时加载)。
  • 枚举单例(线程安全,调用效率高,不能延时加载)。

2 实现方式

1 饿汉式

1、代码

package singleton;

/**
 * 饿汉式
 */
public class Singleton01 {
    // 1、私有化构造器
    private Singleton01() {
    }

    // 2、类初始化时,立即加载该对象
    private static Singleton01 instance = new Singleton01();

    // 3、提供获取该对象的方法
    public static Singleton01 getInstance() {
        return instance;
    }
}

2 懒汉式

1、代码

package singleton;

/**
 * 懒汉式
 */
public class Singleton02 {
    // 1、私有化构造器
    private Singleton02() {
    }

    // 2、类初始化的时候,不立即加载该对象
    private static Singleton02 instance;

    // 3、提供获取该对象的方法,使用synchronized,效率较低
    public static synchronized Singleton02 getInstance() {
        if (instance == null) {
            instance = new Singleton02();
        }
        return instance;
    }
}

3 DCL懒汉式

1、代码

package singleton;

/**
 * DCL懒汉式(双重检查锁)
 */
public class Singleton03 {
    // 1、私有化构造器
    private Singleton03() {
    }

    // 2、类初始化的时候,不立即加载该对象,volatile避免指令重排
    private volatile static Singleton03 instance;

    // 3、提供获取该对象的方法,效率提高了,但由于指令重排,可能出错
    public static Singleton03 getInstance() {
        if (instance == null) {
            synchronized (Singleton03.class) {
                if (instance == null) {
                    instance = new Singleton03();
                }
            }
        }
        return instance;
    }
}

4 静态内部类

1、代码

package singleton;

import java.lang.reflect.Constructor;

/**
 * 静态内部类
 */
public class Singleton04 {
    private static boolean flag = false;

    // 1、私有化构造器
    private Singleton04() {
        // 应对反射的方法:
        if (!flag) {
            flag = true;
        } else {
            throw new RuntimeException("不要试图用反射来破坏单例模式!");
        }
    }

    // 2、静态内部类存放对象
    private static class InnerClass {
        private static final Singleton04 INSTANCE = new Singleton04();
    }

    // 3、提供获取该对象的方法
    public static Singleton04 getInstance() {
        return InnerClass.INSTANCE;
    }

    public static void main(String[] args) throws Exception {
        // 反射会破坏该单例机制
        Singleton04 instance01 = Singleton04.getInstance();
        Constructor<Singleton04> declaredConstructor = Singleton04.class.getDeclaredConstructor();
        declaredConstructor.setAccessible(true);
        Singleton04 instance02 = declaredConstructor.newInstance();
        System.out.println(instance01 == instance02);   // false
    }
}

5 枚举

1、代码

package singleton;

public enum Singleton05 {
    INSTANCE;
}
  • 反射不能破坏。