创建型设计模式的一种

【DP】定义

保证一个类仅有一个实例,并提供一个访问他的全局访问点。

使用场景

  1. 需要全局唯一,并维护某个全局变量
  2. 避免对象重复创建,减少内存空间占用

实现

懒汉模式—非线程安全

1
2
3
4
5
6
7
8
9
10
public class Singleton {
private Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}

核心是:instance和构造方法要私有,getInstance方法要是静态的。

懒汉模式(使用Double-Check Locking)—线程安全

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Singleton {
private Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized(Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}

核心是: 两次判空和synchronized的同步。

两次判空的目的是:当instance存在时,就直接返回。当instance为null时,如果有两个线程同时调用getInstance()方法,他们都会通过第一个if判断,然后会进入加锁的临界区,第一个线程进入后,执行完instance已经有值了,然后第二个线程进入临界区,如果没有第二个if语句,会导致instance会被重新实例化,导致instance不是单例了。

懒汉模式(静态内部类)—线程安全

1
2
3
4
5
6
7
8
9
public class Singleton {
private static class LazyLoader {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton() {}
public static final Singleton getInstance() {
return LazyLoader.INSTANCE;
}
}

核心是: LazyLoader必须是private和static修饰,保证只有Singleton调用。

这种方式是懒加载模式,只有调用

1
2
3
4
5
6
7
8
9
10

#### 饿汉模式---线程安全
```Java
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}

在类初始化的时候就会初始化instance对象,由于又是final类型的,所以instance不会改变,保证内存中只有一个对象存在。

注意事项

  1. 尽量使用线程安全的方式实现
  2. Double-check Locking在使用中依然有问题,原因是在new Singleton()时jvm对字节码的重排序操作。修改方法是给instance增加volatile修饰符,volatile会增加内存屏障,防止重排序。具体可以看传统单例模式双重检查锁存在的问题.