单例模式是一种我们平时在代码开发中使用的一种常用设计模式,通过单例模式创建的类在当前进程中只有一个实例。
1. 饿汉式
在类加载的时候初始化静态实例,由JVM保证线程的安全性。
public class Singleton01 {
private Singleton01() {
}
private static final Singleton01 instance = new Singleton01();
public static Singleton01 getInstance() {
return instance;
}
}
2. 懒汉式(线程不安全)
在调用获取静态实例方法的时候才创建对象,如果是多线程的情况下会出现线程安全问题。
public class Singleton02 {
private Singleton02() {
}
private static Singleton02 instance;
public static Singleton02 getInstance() {
if (instance == null) {
instance = new Singleton02();
}
return instance;
}
}
3. 懒汉式(线程安全)
使用synchronized锁保证线程安全。
public class Singleton03 {
private Singleton03() {
}
private static Singleton03 instance;
public static synchronized Singleton03 getInstance() {
if (instance == null) {
instance = new Singleton03();
}
return instance;
}
}
4.双重检查
使用synchronized锁方法上保证线程安全,锁的粒度相对来说还是比较大的,这里我们优化成锁具体的代码块来减小锁的范围。
- volatile 保证instance变量的可见性和屏蔽指令重排序
- 在new Singleton04() 的时候可以分为下面三个步骤:1. 分配内存空间 2.初始化 3.将instance指向分配的内存地址。由于编译器优化将2、3步骤重排序,在高并发的情况下可能会有线程拿到还没有实例化的instance对象,从而造成了线程安全问题,所以这里我们用volatile 禁止指令重排序,保证所有线程拿到的都是完整的instance实例。
public class Singleton04 {
private Singleton04() {
}
private static volatile Singleton04 instance;
public static Singleton04 getInstance() {
//第一次检查,如果instance不为空直接返回实例
if (instance == null) {
synchronized (Singleton04.class) {
//有线程抢到锁后再次检查是否为空
if (instance == null) {
instance = new Singleton04();
}
}
}
return instance;
}
}
5.静态内部类
由JVM保证线程安全,在加载内部类的时候创建单例对象。
public class Singleton05 {
private Singleton05() {
}
public static class SingletonInner {
private static Singleton05 instance = new Singleton05();
}
public static Singleton05 getInstance() {
return SingletonInner.instance;
}
}
6.枚举方式
使用枚举方式实现起来简单,枚举实例的创建也是线程安全的。
public enum Singleton06 {
INSTANCE;
public static Singleton06 getInstance() {
return INSTANCE;
}
}