设计模式--单例模式singleton

来源:互联网 发布:你的网络被运营商劫持 编辑:程序博客网 时间:2024/05/18 00:01

应用场合:有些对象只需要一个,如古代皇帝,老婆(配置文件,工具类,线程池,缓存,日志等)
作用:保证整个应用程序中某个实例有且只有一个
类型:饿汉模式,懒汉模式
饿汉模式:

public class Singleton{    //1.修改默认的构造方法,不允许外部直接创建对象-->(但是还要有一个实例)在类的内部创建实例    private Singleton(){}    //2.创建类的唯一实例,还要考虑如何提供给外界->static     // Singleton s1 = Singleton.instance;    //为了安全,不允许外界直接访问成员变量->private    private static Singleton instance = new Singleton();    //3.提供一个用于获取实例的方法->public static    public static Singleton getInstance(){      return instance;    }}

当类加载时,就会创建一个实例,不管用于是否使用它(要早些吃饱)
懒汉模式:

public Singleton{  //1.将构造方法私有化,不允许外界直接创建对象  private Singleton(){}  //2.声明类的唯一实例,使用private static   private static Singleton instance;  //3.提供一个用于获取实例的方法,使用public static  public static Singleton getInstance(){  if(instance==null){   instance  = new Singleton();}     return instance;  }}

当类加载的时候,并没有去创建一个唯一实例
二者区别

  1. 饿汉模式加载类的时候比较慢,但运行时获取对象的速度比较快,线程安全
  2. 懒汉模式的特点是加载类时比较快,但运行时获取对象的速度比较慢,线程不安全

什么是线程安全
1.在多线程环境中,当各线程不共享数据的时候,那么一定是线程安全的。问题是这种情况并不多见,在多数情况下需要共享数据,这时就需要进行适当的同步控制了。
2.线程安全一般都涉及到synchronized 就是一段代码同时只能有一个线程来操作 不然中间过程可能会产生不可预制的结果
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的


懒汉式实现线程安全的三种方式

在getInstance方法上加同步【第1种】,在方法调用上加了同步,虽然线程安全了,但是每次都要同步,会影响性能,毕竟99%的情况下是不需要同步的,

public static synchronized Singleton getInstance() {           if (single == null) {                 single = new Singleton();           }            return single;  }  

双重检查锁定【第2种】,在getInstance中做了两次null检查,确保了只有第一次调用单例的时候才会做同步,这样也是线程安全的,同时避免了每次都同步的性能损耗

public static Singleton getInstance() {          if (singleton == null) {                synchronized (Singleton.class) {                   if (singleton == null) {                      singleton = new Singleton();                  }                }            }            return singleton;       }  

静态内部类【第3种】,利用了classloader的机制来保证初始化instance时只有一个线程,所以也是线程安全的,同时没有性能损耗,所以一般我倾向于使用这一种。

public class Singleton {        private static class LazyHolder {           private static final Singleton INSTANCE = new Singleton();        }        private Singleton (){}        public static final Singleton getInstance() {           return LazyHolder.INSTANCE;        }    }    

单例模式的优点

  • 在内存中只有一个对象,节省内存空间。
  • 避免频繁的创建销毁对象,可以提高性能。
  • 避免对共享资源的多重占用。
  • 可以全局访问
    适用场景
  • 需要频繁实例化然后销毁的对象。
  • 创建对象时耗时过多或者耗资源过多,但又经常用到的对象。
  • 有状态的工具类对象。
  • 频繁访问数据库或文件的对象。
  • 以及其他我没用过的所有要求只有一个对象的场景。

注意事项

  • 只能使用单例类提供的方法得到单例对象,不要使用反射,否则将会实例化一个新对象。
  • 不要做断开单例类对象与类中静态引用的危险操作。
  • 多线程使用单例使用共享资源时,注意线程安全问题。