核心作用
-保证一个类只有一个实例,并且提供一个访问该实例的全局访问点,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置,产生其他依赖对象时,则可以通过在应用启动时产生一个单例对象,然后长时间存在内存中
常见应用场景
1.Windows的任务管理器,只会开启一个窗口
2.Windows的回收站,在系统运行中,回收站只会维护着仅有的一个实例
3.项目中,读取配置文件的类,一般也是只有一个对象,没有必要每次使用配置文件数据
4.网站的计数器,一般也是采用单例模式,不然同步很难
5.应用程序的日志应用,一般都是单例模式实现,用一个实例去操纵,不然内容不好追加
6.数据库连接池的设计也是单例模式
7.操作系统的文件系统也是单例模式实现的
8.在Spring中每个Bean都是单例,这样有利于Spring容器管理
9.在Servlet编程中,每个Servlet也是单例的
10.在SpringMVC框架中,控制器对象也是单例
五种单例实现方式
饿汉式(线程安全,调用效率不高,不能延时加载)
懒汉式(线程安全,调用效率不高,能延时加载)
双重检测锁式(由于JVM底层,偶尔会出问题)
静态内部类式(线程安全,调用效率高,能延时加载)
枚举单例(线程安全,调用效率高,不能延时加载)
饿汉式
private state A a=new a(); //提前创建好对象
private A(){} //私有化构造器
public static A getInstance(){
return a; //创建公共方法来返回实例
}
懒汉式
private state A a; //提前创建好对象引用
private A(){} //私有化构造器
public static A getInstance(){
if(a == null){
return new A(); //创建公共方法来返回实例
}
return a;
}
双重检测锁式
private static A a=null;
private A(){}
public static A getInstance(){
if(a == null){
A a1;
synchronized(A.class){
a1=a;
if(a1 == null){
synchronized(A.class){
if(a1 == null){
a1 == new A();
}
}
a = a1;
}
}
}
return a;
}
静态内部类式
private A(){}
private static class Aclass{
public static final A a=new A();
}
public static A getInstance(){
return Aclass.*斜体样式*a;
}
枚举单例
public enum A{
INSTANCE;
public static void main(String[] args) {
System.out.println(A.INSTANCE==A.INSTANCE);
}
}
缺陷
可以通过反射来获取当前对象来创造实例(可以在构造器里判断,手动刨出异常)
也可以反序列化实现对象创建,定义一个readSesolve()方法实现回调
如何选择哪种单例
当对象占用资源少,不需要延时加载
枚举式好于饿汉式
当对象占用资源大,需要延时加载
静态内部类好于懒汉式