单例模式是一种比较常见的设计模式,在很多Manager 以及 Factory类中广泛使用。
下面我们来介绍一下几种常见的写法:
一、饿汉式
/**
1. 单例模式之一
2. 饿汉式
*/
public class Singleton {
//1.确保构造方法私有化,外界无法通过new 创建对象
private Singleton(){
}
//2.静态私有化的创建 类的对象,类加载时就创建对象(饿汉式)
private static final Singleton INSTANCE = new Singleton();
//3.public 的通过getInstance()获取实例
public static Singleton getInstance(){
return INSTANCE;
}
}
- 确保构造方法私有化,外界无法通过new 创建对象
- 静态私有化的创建 类的对象,类加载时就创建对象(饿汉式)
- 通过getInstance()获取实例
- 是线程安全的
二、懒汉式
/**
1. 单例模式之二
2. 懒汉式
*/
class SingletonLazy {
//1.确保构造方法私有化,外界无法通过new 创建对象
private SingletonLazy(){
}
//2.静态私有化的创建 类的对象 ,初始化类的时候不创建
private static volatile SingletonLazy INSTANCE ;
/**
* 3.public 的通过getInstance()获取实例
*/
public static SingletonLazy getInstance(){
//此处可省略,但是此处判断可以有效减少剩余线程访问
if(INSTANCE == null){
//枷锁保证不重复创建
synchronized (SingletonLazy.class){
//双重校验
if(INSTANCE == null){
INSTANCE = new SingletonLazy();
}
}
}
return INSTANCE;
}
}
- 静态私有化的创建 类的对象 ,初始化类的时候不创建
- 需要使用volatile 关键字避免jit环境指令重排。
- getInstance()方法获取实例的时候,需要进行双重校验,以及加锁控制,保证在多线程情况下是不会重复创建对象。
三、静态内部类版(懒汉式之二)
/**
* 单例模式之三
* 懒汉式
*/
public class Singleton2 {
/**
* 1.确保构造方法私有化,外界无法通过new 创建对象
*/
private Singleton2(){
}
/**
* 2.通过静态内部类的方式 创建Singleton2
* jvm在初始化Singleton2 的时候不会初始化静态内部类
* 只有调用方法的时候才会加载
*/
private static class SingletonHolder {
private final static Singleton2 INSTANCE = new Singleton2();
}
/**
* 3.public 的通过getInstance()获取实例
*/
public static Singleton2 getInstance(){
return SingletonHolder.INSTANCE;
}
}
- 由于jvm在类加载的时候只会初始化一次,且不会初始化静态内部类。
- 调用getInstance方法时候才会去,初始化静态内部类,并返回类的实例。
- 线程安全由jvm保证。
注意:单例模式是可以通过反射进行破坏的。反射可以获取到私有private 的构造器创建对象。
除非使用枚举方法创建单例模式,枚举是没有构造器的,无法通过反射创建对象。