单例模式(8种方式):整个软件系统中只存在一个对象实例;如hibernate的sessionfactory,充当数据源的代理并负责创建Session。由于SF不是轻量级的对象,一个项目通常只需要一个sessionfactory。JDK Runtime getRuntime() 是单例模式的饿汉式-静态常量方式创建。
使用场景:需要频繁销毁和创建、创建对象耗时/耗资源过多的工具类对象,重量级对象,频繁访问数据库或文件的对象(比如数据源、sessionfactory)
饿汉式-静态常量: 在类装载classloader时就完成了实例化,避免了线程同步的问题;可用
1.过程:
- a.构造器私有化;
- b.类的内部创建私有final静态对象
- c.向外暴露静态公共方法,返回对象实例
class A{
private final static A ins = new A();
private A(){};
public static A getInstance(){return ins;}
}
2.缺点:可能造成内存浪费;达不到lazy loading的效果。
饿汉式-静态代码块:同上,可用
1.过程:
- a.构造器私有化;
- b.类的内部声明私有静态对象变量
- c.静态代码块中初始化对象
- d.向外暴露静态公共方法,返回对象实例
class A {
private static A ins;
private A(){};
static{ ins = new A();}
public static A getInstance(){return ins;}
}
2.缺点: 同上;
懒汉式-线程不安全:单线程下可实现懒加载;
1.过程:
- a.构造器私有化;
- b.类的内部声明私有静态对象变量
- c.向外暴露静态公共方法,对象为空时创建对象,返回对象实例
Class A{ private static A ins ; private A(){}; public static A getInstance(){
if(ins == null){ins = new A(); return ins;}
}}
2.缺点:多个线程执行if null 判断时,线程不安全,实际开发禁止使用
懒汉式-同步方法:线程安全
1.过程:
- a.构造器私有化;
- b.类的内部声明私有静态对象变量
- c.向外暴露静态公共singleton方法,对象为空时创建对象,返回对象实例
class A{
private static A ins;
private A(){};
public static synchronized A getInstance(){
If(ins==null){ins = new A(); return ins;}}
}
2.缺点:效率低,实例化代码只需执行一次而不是每次调用都同步,之后获得实例只需直接调用return方法,实际开发不推荐使用;
懒汉式-同步代码块:不能实现线程安全
1.过程:
- a.构造器私有化;
- b.类的内部声明私有静态对象变量
- c.向外暴露静态公共方法,对象为空时,同步代码块只包含创建对象语句,返回对象实例
Class A{ private static A ins; private A(){};
public static A getInstance(){
If(ins==null){ synchronized(A.class) {ins = new A();}
return ins;}
}}
2.缺点:if语句判空仍然存在多线程不安全,无意义
双重检查锁:volatile 修饰的变量一发生改变就立即将值更新到主存, 同步代码块保证多线程环境;实现懒加载效果;
- 1.过程:
- a.构造器私有化;
- b.类的内部声明私有静态对象并用volatile修饰
- c.向外暴露静态公共方法,对象为空时,同步代码块只包含创建对象语句并且再次判空,返回对象实例
class A{
private final static volatile A ins;
private A(){};
public static A getInstance(){
if(ins==null){
synchronized(A.class) {
if(ins == null) {ins = new A();}
}
return ins;
}}
}
2.缺点:无。实际开发推荐使用
静态内部类:外部类装载时,不会导致静态内部类装载;getInstance方法调用时才开始装载内部类且只装载一次;静态属性只会在第一次加载类时初始化,类的初始化本身也是线程安全的:
- a.构造器私有化;
- b.内部类的内部创建私有final静态外部类对象
- c.外部类向外暴露静态synchronized公共方法,返回内部类对象实例
class A{ private A(){};
class B{ private final static A INS= new A();}
public static synchronized A getInstance(){return B.INS;}
}
2.缺点:无,推荐使用。
枚举类:实现单例,避免多线程问题,防止反序列化重新创建对象
1.过程:
- a.新建Enum类,且只声明一个对象属性;
- Enum A{ INSTANCE}
- b. 调用 A.INSTANCE 获取单例
2.缺点:无推荐使用