1. 定义
一个类仅有一个实例,并且自行实例化,向整个系统提供。
关键点:
- 仅有一个实例
- 自己创建该实例
- 能够给调用者提供仅有的实例
2. 单例的实现方式
单例实现从以下几个方面来对比
- 是否能够在使用时加载?
- 线程是否安全?
- 是否易用、易理解?
2.1 饿汉式
类加载时创建自身实例,线程安全。
/**
* 饿汉式
* 1. 不能在使用时才加载:如果该单例较耗资源,那么性能问题会比较突出
* 2. 线程安全
* 3. 易用、易理解
* Created by Administrator on 2017/10/10.
*/
public class SingleInstance {
// 初始化时自动创建自身的实例
private static SingleInstance instance = new SingleInstance();
// 私有构造方法
private SingleInstance(){}
// 简单工厂模式
public static SingleInstance getInstance(){
return instance;
}
}
2.2 懒汉式
在需要使用时才去创建自身实例,属于懒加载,但是线程不安全。
/**
* 懒汉式
* 1. 懒加载
* 2. 线程不安全,不能用在多线程中
* 3. 易用、易理解
* Created by Administrator on 2017/10/10.
*/
public class SingleInstance {
private static SingleInstance instance;
// 私有构造方法
private SingleInstance(){}
public static SingleInstance getInstance(){
// 延迟加载
if (instance == null){
instance = new SingleInstance();
}
return instance;
}
}
2.2.1 懒汉式进阶(synchronized)
在方法上加同步锁
/**
* synchronized进阶
* 1. 懒加载
* 2. 线程安全,但是性能较低
* 3. 易用、易理解
*/
public synchronized static SingleInstance getInstance(){
// 延迟加载
if (instance == null){
instance = new SingleInstance();
}
return instance;
}
2.2.2 懒汉式进阶(DCLSingleInstance:双重检查锁定)
在懒汉式的基础上
- 去掉方法上的同步锁
synchronized
- 在非空判断中加同步锁,保证性能
- 在同步代码中再进行非空判断,进行第二重检查保证不会创建出第二个对象。
- 给instance加上volatile修饰符(高并发时使用需要):volatile关键字能禁止指令重排序,比如线程1创建了实例,intance被修改时会被强制写到主存,其他线程也能实时获取到该值。请参考:volatile参考
/**
* DCL懒加载
* 1. 懒加载
* 2. 线程安全,性能较高
* 3. 易用、易理解
* Created by Administrator on 2017/10/10.
*/
public class SingleInstance {
private volatile static SingleInstance instance;
// 私有构造方法
private SingleInstance(){}
public static SingleInstance getInstance(){
// 延迟加载
if (instance == null){
// 第一重锁定
synchronized (SingleInstance.class){
//第二重锁定
if (instance == null){
instance = new SingleInstance();
}
}
}
return instance;
}
}
2.2.3 懒汉式进阶(静态内部类)
- 私有构造方法
- 在静态内部类中声明一个静态变量,并创建单例对象
- 在提供单例的静态方法中调用返回静态内部类中创建的单例对象
/**
* 静态内部类
* 1. 懒加载
* 2. 线程安全,性能好
* 3. 易用、易理解
* Created by Administrator on 2017/10/10.
*/
public class SingleInstance {
// 私有构造方法
private SingleInstance(){}
private static class SingleInner{
// 在静态内部类中创建单例的对象
private static SingleInstance instance = new SingleInstance();
}
// 在调用该方法时,才会初始化instance
public static SingleInstance getInstance(){
return SingleInner.instance;
}
}
3. 懒汉式和饿汉式
- 懒汉式:类一加载,单例就已经初始化完成。
- 饿汉式:只有在使用时才去创建单例的对象。
3.1 线程安全
判断线程是否安全:有没有可能创建多个instance?
- 懒汉式是线程安全的
- 饿汉式需要不同的处理才能保证线程安全。
3.2 性能
假如单例需要占用的内存较多,那么要优先使用可以懒加载的懒汉式单例。
说明:
单例还有枚举方式,由于用的较少,此处不再赘述。