单例模式的核心作用是保证一个类只有一个实例,并且提供一个访问该实例的全局访问点
单例模式的优点:
- 由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决。
- 单例模式可以在系统设置全局的访问点,优化环境共享资源访问,例如可以设计一个单例类,负责所有数据表的映射处理。
常见的五种单例模式现实方式:
1、饿汉式(线程安全,调用效率高,但是不能延时加载)
2、懒汉式(线程安全,调用效率不高,但是可以延时加载)
3、双重检测锁式(由于JVM底层内部模型原因,偶尔会出现问题)
4、静态内部类式(线程安全,调用效率高,可以延时加载)
5、枚举单例(线程安全,调用效率高,不能延时加载)
1、饿汉式实现
/**
* 饿汉式单例模式
*/
public class SingletonHungry {
/*
* 静态成员变量,类初始化时,立即加载这个对象(没有延时加载),
* 加载类时,天然是线程安全的
*/
private static SingletonHungry instance = new SingletonHungry();
private SingletonHungry() {//私有化构造器
}
//方法没有同步,调用效率高
public static SingletonHungry getInstance() {
return instance;
}
}
/**
* 懒汉式单例模式
*/
public class SingletonLazy {
/*
* 静态成员变量,类初始化时,没有初始化这个对象(延时加载),
* 真正用的时候才加载
*/
private static SingletonLazy instance ;
private SingletonLazy() {//私有化构造器
}
//方法同步,调用效率低
public static synchronized SingletonLazy getInstance() {
if(instance == null){
instance = new SingletonLazy();
}
return instance;
}
}
3、 双重检测锁式实现
/**
*双重检测式单例模式
*/
public class SingletonDoubleCheckLock {
/*
* 静态成员变量,类初始化时,没有初始化这个对象(延时加载),
* 真正用的时候才加载
*/
private static SingletonDoubleCheckLock instance ;
private SingletonDoubleCheckLock() {//私有化构造器
}
//方法同步,调用效率低
public static SingletonDoubleCheckLock getInstance() {
if(instance == null){
/*
* 只有instance为null时才需要同步,就是第一次调用才需要同步,
* 以后都不需要同步了,效率比懒汉式高了
*/
SingletonDoubleCheckLock ins;
synchronized (SingletonDoubleCheckLock.class) {
ins = instance;
if(ins == null){
synchronized (SingletonDoubleCheckLock.class) {
if (ins == null) {
ins = new SingletonDoubleCheckLock();
}
}
instance = ins ;
}
}
}
return instance;
}
}
4、静态内部类式实现
/**
*静态内部类式单例模式
*类加载是线程安全的,兼备了并发高效调用和延迟加载的优势
*/
public class SingletonStaticClass {
private SingletonStaticClass() {//私有化构造器
}
public static SingletonStaticClass getInstance() {
return InnerClass.instance;
}
/*
* 静态的内部类
*/
private static class InnerClass {
/**
* instance是static final类型,保证了内存中只有一个实例存在,
* 而且只能被赋值一次,从而保证了线程安全
*/
private static final SingletonStaticClass instance = new SingletonStaticClass();
}
}
5、枚举单例实现
/**
*枚举式单例模式
*枚举本身就是单例模式,由于LVM从根本上提供保障,避免通过反射和反序列化的漏洞
*缺点是无法延时加载
*/
public enum SingletonEnum {
/**
* 定义一个枚举的元素,它就代表了Singleton的一个实例。
*/
INSTANCE;
/**
* 可以有自己的操作
*/
public static void singletonOperation() {
//功能处理
}
}