单例设计模式是最常用的设计模式之一,它提供了一种在多线程情况下保证实例唯一性的解决方案,单例模式虽然简单,但实现方式却有很多。
采用单例模式,针对频繁使用的对象,可以省去new操作花费的时间,这对于哪些重量级对象而言,是可以省掉一笔非常可观的系统开销。
对于new操作的次数减少,系统内存的使用频率也会降低,这将减轻GC压力,缩短GC停顿时间。
因此,对于系统的关键组件和被频繁使用的对象,使用单例模式可以有效的改善系统的性能。
饿汉式指的是当类被加载的时候就实例化,并创建单例对象。如果类中的成员变量不多,且占用内存不大,这种方式也可以。如果类中的成员需要占用比较重的资源,就有点不妥。单例模式对象不能被继承,所以整个类用final修饰固化。
package designpaten;
public final class Singleton_Hungry {
private static Singleton_Hungry instance = new Singleton_Hungry();
//构造函数私有化,不允许其他类直接通过new的方式创建新对象
private Singleton_Hungry() {
}
public Singleton_Hungry getInstance() {
return instance;
}
}
所谓的懒汉式指的就是只有在使用的时候才开始构造对象,这样可以避免在类加载的时候就提前创建。但这里要加锁,不然在多线程环境下可能会创建多个对象。
package designpaten;
public final class Singleton_Lazy {
private static Singleton_Lazy instance = null;
//构造函数私有化,不允许其他类直接通过new的方式创建新对象
private Singleton_Lazy() {
}
public static synchronized Singleton_Lazy getInstance() {
if(instance == null) {
instance = new Singleton_Lazy();
}
return instance;
}
}
Dobule-check采用的也是一种同步机制,只不过是在首次初始化时加锁,之后就允许多个线程同时进行getInstance方法的调用来获得类的实例。
package designpaten;
public final class Singleton_DoubleCheck {
private static Singleton_DoubleCheck instance = null;
//构造函数私有化,不允许其他类直接通过new的方式创建新对象
private Singleton_DoubleCheck() {
}
public static Singleton_DoubleCheck getInstance() {
if(instance == null) {
synchronized(Singleton_DoubleCheck.class) {
if(instance == null) {
instance = new Singleton_DoubleCheck();
}
}
}
return instance;
}
}
Holder方式完全是借助了类加载的特点。将instance成员放到了静态内部类Holder之中,因此单例类的初始化过程并不会创建单例实例。只有Holder被主动引用的时候才会创建单例实例。
package designpaten;
public final class Singleton_InnerClass {
private static Singleton_InnerClass instance = null;
//构造函数私有化,不允许其他类直接通过new的方式创建新对象
private Singleton_InnerClass() {
}
private static class Holder{
private static Singleton_InnerClass instance = new Singleton_InnerClass();
}
public static Singleton_InnerClass getInstance() {
return Holder.instance;
}
}
枚举类型不允许被继承,同样是线程安全的且只能被实例化一次,但是枚举类型不能够懒加载。也是高效JAVA编程作者推荐的方法。在这种实现方式中,既可以避免多线程同步问题;还可以防止通过反射和反序列化来重新创建新的对象。 因为Java虚拟机会保证枚举对象的唯一性,因此每一个枚举类型和定义的枚举变量在JVM中都是唯一的。
package designpaten;
//枚举类本身就是final的,不允许被继承
public enum Singleton_Enum {
INSTANCE;
Singleton_Enum() {}
public static Singleton_Enum getInstance() {
return INSTANCE;
}
}
通过枚举定义单例,还有一种实现方式,就是将枚举类作为内部类来用。
public class SingleDemo {
private SingleDemo(){
}
public static enum Demo{
INSTANCE;
private SingleDemo instance = null;
private Demo() {
instance= new SingleDemo();
}
public SingleDemo create() {
System.out.println("hello");
return instance;
}
}
}