设计模式之---单例模式

单例模式(Singleton),保证一个类仅有一个实例,并提供一个访问它的全局访问点

在这里将从以下几方面介绍

  • 实现方式
  • 各种实现方式的优缺点
  • 总结

实现方式

  1. 饿汉单例模式
//private的构造函数用于避免外界直接使用new来实例化对象
private SingletonSample() {}
private static final SingletonSample INSTANCE = new SingletonSample();
public static SingletonSample newIntent() {
        return INSTANCE;
}
  1. 懒汉单例模式
//private的构造函数用于避免外界直接使用new来实例化对象
private SingletonSample() {}
private static SingletonSample instance_b;
public static synchronized SingletonSample getInstanceB() {
    if (instance_b == null) {
            instance_b = new SingletonSample();
    }
    return instance_b;
}
  1. 双重校验锁
//private的构造函数用于避免外界直接使用new来实例化对象
private SingletonSample() {}
private static SingletonSample instance_c;
public static SingletonSample getInstanceC() {
   if (instance_c == null) {
        synchronized (SingletonSample.class) {
           instance_c = new SingletonSample();
           }
    }
   return instance_c; }
  1. 静态内部类
//private的构造函数用于避免外界直接使用new来实例化对象
private SingletonSample() {}
public static SingletonSample getInstanceD() {
    return SingleHolder.instance_d;
}
private static class SingleHolder {
    private static final SingletonSample instance_d = new SingletonSample();
}
  1. 枚举
public enum SingletonSamples {
    INSTANCE;
    public void toPlayMusic() {
        }
}
public static void main(String[] args) {
    SingletonSamples.INSTANCE.toPlayMusic();
}

以上实现方式的优缺点

实现方式 优点 缺点
饿汉 在类加载的同时已经创建好一个静态对象 不具备lazyloading
懒汉 资源利用率高,具备很好的lazy loading 多数情况下可能并不需要同步
双重校验锁 资源利用率高, 由于java内存模型一些原因偶尔失败,不过在jdk1.5开始这个问题已经解决,由于volatile关键字屏蔽了虚拟机中一些必要的代码优化,所以运行效率并不是很高,因此建议没有特别的需要不要使用。双重检验锁方式的单例不建议大量使用,根据情况决定
静态内部类 资源利用率高,线程安全 -----
枚举 线程安全, 调用效率高(从Java1.5开始支持;无偿提供序列化机制,绝对防止多次实例化,即使在面对复杂的序列化或者反射攻击的时候) -----

总结

根据以上的优缺点比较,对于单例模式,我们更多的应该使用静态内部类和单元素枚举实现单例模式,Effective Java作者Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象,个人认为可能是jdk1.5引入的枚举,这种方式在我们的工作中用的并不是很多.

需要注意以下两个问题

  1. 如果Singleton实现了java.io.Serializable接口,那么它就能够进行序列化和反序列化,当它在返序列化的时候会产生新的对象,解决方法如下:
 private Object readResolve() throws ObjectStreamException {   
    return INSTANCE;   
 }  
  1. 如何防止反射获取多个对象
private SingletonSamples() {
    if (INSTANCE != null) {
        throw new RuntimeException(); 
    }
}

你可能感兴趣的:(设计模式之---单例模式)