单例模式
保证一个类只有一个实例,并且提供一个访问该实例的全局访问点
例如:数据库连接吃,spring中的每个bean默认是单例的
饿汉式
线程安全,效率高,但是不能延时加载
饿汉式中,static会在类装载时初始化,所以不会涉及多个线程对象访问的问题。
但是,如果只是加载本类,而并不调用getInstance(),则会出现资源浪费
/**
* 饿汉式
*/
public class SingletonDemo1 {
//类初始化时,立刻加载这个对象。加载类时线程安全 (没有延迟加载)
private static SingletonDemo1 instance = new SingletonDemo1();
private SingletonDemo1(){
}
public static SingletonDemo1 getInstance(){
return instance;
}
}
懒汉式
线程安全,效率不高,但可以延时加载
真正用时才加载,但每次调用方法都要同步,并发效率低
/**
* 懒汉式
*/
public class SingletonDemo2 {
private static SingletonDemo2 instance;
private SingletonDemo2(){
}
public static synchronized SingletonDemo2 getInstance(){
if(instance == null){
instance = new SingletonDemo2();
}
return instance;
}
}
静态内部类
这是一种懒加载,线程安全,兼备并发调用和延时加载的问题
外部类没有static属性,则不会像饿汉式那样立即加载对象
只有真正调用getInstance(),才会加载静态内部类。
加载类时是线程安全的。
instance是static final类型,保证了内存中只有这样一个的实例存在,而且只能被赋值一次,从而保证了线程安全性
/**
* 静态内部类(懒加载)
*/
public class SingletonDemo3 {
private static class SingletonClassinstance{
private static final SingletonDemo3 instance = new SingletonDemo3();
}
public static SingletonDemo3 getInstance(){
return SingletonClassinstance.instance;
}
private SingletonDemo3(){}
}
枚举
优点:实现简单,枚举本身就是单例模式,避免通过反射和反序列化的漏洞
缺点:无延时加载
/**
* 枚举(没有延时加载)
*/
public enum SingletonDemo4 {
//这个枚举元素,本身就是单例对象
INSTANCE;
//添加自己的操作
public void singletonOperation(){
}
}
如何选用
单例对象占用资源少,延时加载:枚举式好于饿汉式
单例对象占用资源多,不需要延时加载:静态内部类好于懒汉式