Singleton(单例模式)

场景:没有必要new多个示例类的类,即保证内存中只有一个实例,我们就可以使用单例模式;例如xxxManager等等。

  • 饿汉式代码
1
2
3
4
5
6
7
8
9
10
11
12
public class M1 {
private static final M1 INSTANCE = new M1();

private M1() {}
public static M1 getInstance() { return INSTANCE; }

// 业务代码
public void m() {
System.out.println("mmmm");
}

}

优点:简单高效,JVM保证线程安全

缺点:不管用到该类与否,类装载时完成实例化

  • 懒汉式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class M2 {
private static M2 INSTANCE;

private M2() {
}

public static M2 getInstance() {
if (INSTANCE == null) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
INSTANCE = new M2();
}
return INSTANCE;
}
// 业务代码
public void m(){
System.out.println("mmmm");
}
}

优点:解决了饿汉式单例模式的类装载问题

缺点:多线程下很不安全,这个更严重

1
2
3
4
5
6
7
8
9
10
// 验证多线程下不安全的代码
public class Main {
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(()->{
System.out.println(M2.getInstance().hashCode());
}).start();
}
}
}
  • 改良版的懒汉式

    • 全局上锁
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
     public class M3 {
    private static M3 INSTANCE;

    private M3() {
    }

    //可以解决线程安全问题,但是效率降低
    public static synchronized M3 getInstance() {
    if (INSTANCE == null) {
    try {
    Thread.sleep(1);
    } catch (InterruptedException e) {
    throw new RuntimeException(e);
    }
    INSTANCE = new M3();
    }
    return INSTANCE;
    }
    public void m(){
    System.out.println("mmmm");
    }
    }
    • 局部上锁(单次判断无法解决,2次判断可以解决)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public static M3 getInstance() {
    //双重检查 ---- 必须是双重检查
    if (INSTANCE == null) {
    synchronized (M3.class) {
    if (INSTANCE == null) {
    try {
    Thread.sleep(1);
    } catch (InterruptedException e) {
    throw new RuntimeException(e);
    }
    INSTANCE = new M3();
    }
    }
    }
    return INSTANCE;
    }
  • 静态内部类

1
2
3
4
5
6
7
8
9
10
11
12
public class M4 {
private M4(){}
private static class M4Holder{
private static final M4 INSTANCE = new M4();
}
public static M4 getInstance(){
return M4Holder.INSTANCE;
}
public void m(){
System.out.println("mmmm");
}
}

该方法实现的单例模式下,解决了饿汉式和懒汉式的所有缺点(比较完美的写法)

  • 枚举类
1
2
3
4
5
6
7
public enum M5 {
INSTANCE;

public void m(){
System.out.println("mmmm");
}
}

最完美的实现方法,不可以被反序列化