核心作用
:保证一个类只有一个实例,并且提供一个访问该实例的全局访问点
常见场景:
标题Windows的任务管理器
Windows的回收站
项目中,读取配置文件的类,一般也只有一个对象,没有必要每次都去new新对象读取
网站的计时器也会采用单例,保证同步
数据库连接池的设计一般也是单例模式
在Servlet编程中,每个Servlet也是单例
在Spring中,每个Bean默认就是单例
…
优点:
由于单例模式只生成一个实例,减少了系统性能的开销
单例模式可以在系统设置全局的访问点,优化共享资源访问
常见五种单例模式实现方法
饿汉式(线程安全,调用效率高,不能延时加载)
懒汉式(线程安全,调用效率不高,可以延时加载)
DCL懒汉式(由于JVM底层内部模型的原因,偶尔会出现问题,不推荐使用)
饿汉式改进:静态内部类式(线程安全,调用效率高,可以延时加载)
枚举单例:(线程安全,调用效率高,不能延时加载)
1.饿汉式(线程安全,调用效率高,不能延时加载)
public class Danli {
//私有化构造器
private Danli() {}
//类初始化的时候就立即生成一个单例
private static Danli instance = new Danli();
//获取单例的方法,没有synchronized,效率高!
public static Danli getInstance(){
return instance;
}
}
2.懒汉式(线程安全,调用效率不高,可以延时加载)
public class Danli2 {
//私有化构造器
private Danli2() {}
//类初始化的时候,不立即加载该对象
private static Danli2 instance;
//获取单例的方法,有synchronized,效率不高!
public static synchronized Danli2 getInstance(){
if(instance==null)
instance = new Danli2();
return instance;
}
}
3.DCL懒汉式(由于JVM底层内部模型的原因,偶尔会出现问题,不推荐使用)
public class Danli3 {
//私有化构造器
private Danli3() {}
//类初始化的时候,不立即加载该对象,volatile保证创建过程的原子性
private volatile static Danli3 instance;
//获取单例的方法,有synchronized,效率不高!
public static synchronized Danli3 getInstance(){
if(instance==null){
synchronized (Danli3.class){
if(instance==null)
instance = new Danli3();
}
}
return instance;
}
}
4.饿汉式改进:静态内部类式(线程安全,调用效率高,可以延时加载)
package com.hzj.pojo;
//饿汉式(线程安全,调用效率高,不能延时加载)
public class Danli3 {
//私有化构造器
private Danli3() {}
//静态内部类,final保证instance只有一个
private static class InnerClass{
private static final Danli3 instance = new Danli3();
}
public static synchronized Danli3 getInstance(){
return InnerClass.instance;
}
}
注:但仍然可以通过反射的方式来破坏单例
5.枚举单例:(线程安全,调用效率高,不能延时加载)
class Test{
public static void main(String[] args) throws Exception {
Danli3 instance = Danli3.getInstance();
Constructor<Danli3> declaredConstructor = Danli3.class.getDeclaredConstructor(null);
//将权限破坏
declaredConstructor.setAccessible(true);
Danli3 instance2 = declaredConstructor.newInstance();
System.out.println(instance==instance2);//false,说明instance2是新的对象,单例模式被破坏
}
}
public enum Danli {
INSTANCE;
public Danli getInstance(){
return INSTANCE;
}
}
Constructor.class newInstance方法源码天然屏蔽了Enum对象
public T newInstance(Object... initargs) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
if (!this.override) {
Class<?> caller = Reflection.getCallerClass();
this.checkAccess(caller, this.clazz, this.clazz, this.modifiers);
}
if ((this.clazz.getModifiers() & 16384) != 0) {
//反射源码中,不能new一个枚举对象
throw new IllegalArgumentException("Cannot reflectively create enum objects");
} else {
ConstructorAccessor ca = this.constructorAccessor;
if (ca == null) {
ca = this.acquireConstructorAccessor();
}
T inst = ca.newInstance(initargs);
return inst;
}
}