2019独角兽企业重金招聘Python工程师标准>>>
1、单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例
2、饿汉式单例类
- 在这个类被加载时,静态变量instance会被初始化,此时类的私有构造子会被调用
- 饿汉式是典型的空间换时间
public class EagerSingleton {
private static EagerSingleton instance = new EagerSingleton();
/**
* 私有默认构造子
*/
private EagerSingleton(){}
/**
* 静态工厂方法
*/
public static EagerSingleton getInstance(){
return instance;
}
}
3、懒汉式单例类
- 对静态工厂方法使用了同步化,以处理多线程环境
- 懒汉式是典型的时间换空间
public class LazySingleton {
private static LazySingleton instance = null;
/**
* 私有默认构造子
*/
private LazySingleton(){}
/**
* 静态工厂方法
*/
public static synchronized LazySingleton getInstance(){
if(instance == null){
instance = new LazySingleton();
}
return instance;
}
}
4、双重检查加锁
- 既实现线程安全,又能够使性能不受很大的影响
- 被volatile修饰的变量的值,将不会被本地线程缓存
- 所有对该变量的读写都是直接操作共享内存,从而确保多个线程能正确的处理该变量
- 由于volatile关键字可能会屏蔽掉虚拟机中一些必要的代码优化,所以运行效率并不是很高
- 可以使用“双重检查加锁”机制来实现线程安全的单例,但并不建议大量采用,可以根据情况来选用
public class Singleton {
private volatile static Singleton instance = null;
private Singleton(){}
/**
* 双重锁的原因是,俩线程同时进入if 语句内部,一个获得锁执行,另一个阻塞,
* 如果不再判断下,一个创建完之后,另一个在创建一个
*/
public static Singleton getInstance(){
//先检查实例是否存在,如果不存在才进入下面的同步块
if(instance == null){
//同步块,线程安全的创建实例
synchronized (Singleton.class) {
//再次检查实例是否存在,如果不存在才真正的创建实例
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
5、Lazy initialization holder class模式
- 综合使用了Java的类级内部类和多线程缺省同步锁的知识,很巧妙地同时实现了延迟加载和线程安全
- 当getInstance方法第一次被调用的时候,它第一次读取SingletonHolder.instance,导致SingletonHolder类得到初始化
public class Singleton {
private Singleton(){}
/**
* 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例
* 没有绑定关系,而且只有被调用到时才会装载,从而实现了延迟加载。
*/
private static class SingletonHolder{
/**
* 静态初始化器,由JVM来保证线程安全
*/
private static Singleton instance = new Singleton();
}
public static Singleton getInstance(){
return SingletonHolder.instance;
}
}
类级内部类:
- 有static修饰的成员式内部类。如果没有static修饰的成员式内部类被称为对象级内部类
- 类级内部类相当于其外部类的static成分,它的对象与外部类对象间不存在依赖关系,因此可直接创建
- 对象级内部类的实例,是绑定在外部对象实例中的
- 类级内部类中,可以定义静态的方法,在静态方法中只能够引用外部类中的静态成员方法或者静态成员变量
- 类级内部类相当于其外部类的成员,只有在第一次被使用的时候才被会装载
多线程缺省同步锁:
- 在多线程开发中,为了解决并发问题,主要是通过使用synchronized来加互斥锁进行同步控制
- 在某些情况中,JVM已经隐含地为您执行了同步,这些情况下就不用自己再来进行同步控制
这些情况包括:
- 由静态初始化器(在静态字段上或static{}块中的初始化器)初始化数据时
- 访问final字段时
- 在创建线程之前创建对象时
- 线程可以看见它将要处理的对象时
6、单例与枚举
- 单元素的枚举类型已经成为实现Singleton的最佳方法
- 使用枚举来实现单实例控制会更加简洁,而且无偿地提供了序列化机制
- 由JVM从根本上提供保障,绝对防止多次实例化,是更简洁、高效、安全的实现单例的方式
/**
* 使用枚举的单例模式
*
* @see [相关类/方法](可选)
* @since [产品/模块版本] (可选)
*/
public class EnumSingleton{
private EnumSingleton(){}
public static EnumSingleton getInstance(){
return Singleton.INSTANCE.getInstance();
}
// 和类级内部类执行时机一致的
private static enum Singleton{
INSTANCE;
private EnumSingleton singleton;
//JVM会保证此方法绝对只调用一次
private Singleton(){
singleton = new EnumSingleton();
}
public EnumSingleton getInstance(){
return singleton;
}
}
}
- 枚举实例的创建默认就是线程安全的,你不需要担心双检锁问题
- JVM会保证enum不能被反射并且构造器方法只执行一次