单例模式:
单例模式是设计模式中使用最普遍的模式之一,是一种对象创建模式,用于生产一个对象的具体实例,塔可以确保系统中一个类只产生一个实例.那么在java中有什么好处呢? 接下来我们一起分析下
一:对于频繁使用的对象,可以省略创建对象所花费的时间,这对重量级对象是一笔系统开销.
二:由于new操作的次数减少,因而对系统内存的使用频率也会降低,减轻了GC的压力,多段GC停顿时间.
因此对于系统的关键组件被频繁使用对象,使用单例模式便可以有效地改善系统的性能,单例模式非常简单,只有单例类和使用者
我们看下单例模式实现代码
public class Singleton {
private Singleton() {
System.out.println("Singleton 创建");
}
private static Singleton instance = new Singleton();
private static Singleton getInsSingleton() {
return instance;
}
}
注意一下单例模式中必须要有一个 private访问级别的构造函数,这样才会保证单例不会被系统中其他代码内实例化,再就是instance 成员变量和getInstance()方法必须是静态的.
单例模式实现方式简单,并且可靠,但是无法对instance实例做延迟加载,如果单例的创建过程很慢,由于instance成员变量是静态的,因此在JVM加载单例类时,单例对象就会被建立,如果此时,这个单例类在系统中还扮演其他角色,那么在任何使用这个单例类的地方都会初始化这个单例变量,而不管是否会被用到,比如String工厂,用于创建一些字符串;
public class Singleton {
private Singleton() {
System.out.println("Singleton 创建");
}
private static Singleton instance = new Singleton();
private static Singleton getInsSingleton() {
return instance;
}
public static void createString() {
System.out.println("创建Sting 的 Singleton");
}
}
当执行Singleton.createString任务时,程序输出:
"Singleton 创建
创建Sting 的 Singleton"
大家可以看到,虽然此时没有使用单列类,单它还是被创建了出来,为了解决这个问题,提高系统在相关函数调用的反应速度,我们需要引入延迟加载机制.
public class LazySingleton {
private LazySingleton() {
System.out.println("Singleton 创建");
}
private static LazySingleton instance = null;
private static synchronized LazySingleton getInsSingleton() {
if(instance == null)
instance = new LazySingleton();
return instance;
}
}
我们对静态变量instance初始化赋值null,确保系统启动没有额外的负载,其次,在getInstance()工厂方法中,判断当前单例是否存在,如果存在返回,不存在创建;而且getInstance()方法必须是同步,不然在多线程环境下会出现第一条线程创建是还未赋值 第二条线程可能判断为null重新创建.
但是实现后我们发现在多线程环境中它的耗时远远大于第一个单例模式,接下来在对此进行改造
public class StaticSingleton {
private StaticSingleton() {
System.out.println("Singleton 创建");
}
private static class SingLetonHolder{
private static StaticSingleton instance = new StaticSingleton();
}
public static StaticSingleton getInstance() {
return SingLetonHolder.instance;
}
}
这个实现中,单例模式使用内部类来维护单例的实例,当StaticSingleton被加载时,其内部类并不会被初始化,可以确保StaticSingleton类被载入JVM时,不会初始化单例类,而getInstance()方法调用时才会加载SingLetonHolder,从而初始化instance.
同时由于实例的建立是在类加载时完成,所以对多线程友好,getInstance()方法不需要同步修饰,因此实现方法同时兼备以上俩种实现的优点.
其实还没有完,因为java中还有一种特殊情况,那就是反射机制强行调用单例类中的私有构造,生成多个单例.序列化与反序列化也会破坏单例,这俩种方式的解决办法后续更新!!!
期待ing!!!!