• 饿汉式
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class Mgr01 {
    private static final Mgr01 INSTANCE = new Mgr01();
    private Mgr01(){}
    private static Mgr01 getInstance(){return INSTANCE;}
    public void m(){
    System.out.println("m");
    }
    public static void main(String[] args) {
    Mgr01 m1 = Mgr01.getInstance();
    Mgr01 m2 = Mgr01.getInstance();
    System.out.println(m1 == m2);
    }
    }

    类加载到内存后就实例化一个单例 , JVM 保证线程安全
    缺点: 不管是否用到,类装载时就完成实例化 (通常问题不大,写法简单)

  • 懒汉式
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    public class Mgr02 {
    private volatile static Mgr02 INSTANCE;
    private Mgr02(){};
    /**
    * 可以使用线程锁的方式(synchronized 修饰此方法)解决,但是性能会下降
    * @return
    */
    public static Mgr02 getInstance(){
    if (INSTANCE == null) {
    // 或者在此处加锁,解决线程安全问题
    synchronized (Mgr02.class){
    if (INSTANCE == null ){
    INSTANCE = new Mgr02();
    }
    }
    }
    return INSTANCE;
    }
    public void m(){
    System.out.println("m");
    }

    public static void main(String[] args) {
    for (int i = 0; i < 100; i++) {
    new Thread(()->{
    // 同一个类的 不同对象,它的 hashCode 是不同的
    System.out.println(Mgr02.getInstance().hashCode());
    }).start();
    }
    }
    }

    为了保证线程安全,写法相对饿汉式麻烦,但是只有在使用时才会实例化

  • 静态内部类
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public class Mgr03 {
    private Mgr03(){}
    private static class Mgr03Holder {
    private static final Mgr03 INSTANCE = new Mgr03();
    }
    public static Mgr03 getInstance() {
    return Mgr03Holder.INSTANCE;
    }
    public static void main(String[] args) {
    for (int i = 0; i < 100; i++) {
    new Thread(()->{
    // 同一个类的 不同对象,它的 hashCode 是不同的
    System.out.println(Mgr03.getInstance().hashCode());
    }).start();
    }
    }
    }

    与饿汉式类似,都是由 JVM 保证线程安全,但静态内部类是延迟加载

  • 枚举
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public enum  Mgr04 {
    //枚举单例
    INSTANCE;
    public void m(){
    System.out.println("m");
    }
    public static void main(String[] args) {
    for (int i = 0; i < 100; i++) {
    new Thread(()->{
    // 同一个类的 不同对象,它的 hashCode 是不同的
    System.out.println(Mgr04.INSTANCE.hashCode());
    }).start();
    }
    }
    }

    枚举单例,解决线程同步,解决反序列化(不能通过反射拿到多个实例,枚举没有构造方法)