设计模式 —— 单例模式

来源:互联网 发布:php 断点续传 编辑:程序博客网 时间:2024/06/06 10:40

概念:

Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,主要的包括三种:懒汉式、饿汉式、登记式、枚举式。
单例模式有以下特点:

  • 1、单例类只能有一个实例。
  • 2、单例类必须自己创建自己的唯一实例。
  • 3、单例类必须给所有其他对象提供这一实例。

优点:

  • 1、在内存中只有一个对象,节省内存空间。
  • 2、避免频繁的创建销毁对象,可以提高性能。
  • 3、避免对共享资源的多重占用。
  • 4、可以全局访问。

懒汉式单例

//懒汉式单例类.在第一次调用的时候实例化自己   public class Singleton {      private Singleton() {}      private static Singleton single=null;      //静态工厂方法       public static Singleton getInstance() {           if (single == null) {                 single = new Singleton();           }            return single;      }  }

Singleton 通过将构造方法限定为 private 避免了类在外部被实例化,在同一个虚拟机范围内,Singleton 的唯一实例只能通过 getInstance() 方法访问。

但是以上懒汉式单例的实现没有考虑线程安全问题,它是线程不安全的,并发环境下很可能出现多个Singleton实例,如果现在存在着线程A和B,代码执行情况是这个样子的,线程A执行到了 If(singleton == null) ,线程B执行到了 Singleton = new Singleton() ;线程B虽然实例化了一个 Singleton,但是对于线程A来说判断singleton还是未初始化的,所以线程A还会对singleton进行初始化。

第一次尝试

我们可以通过添加 Synchronized 关键词来解决同步问题:

public class Singleton {      private Singleton() {}      private static Singleton single=null;      //静态工厂方法       public static Singleton getInstance() {           if (single == null) {                 synchronized(Singleton.class){                single = new Singleton();               }         }            return single;      }  }

通过 Synchronized 关键词我们貌似成功的解决了多线程的问题,但是仔细想想还是不正确,因为A,B两个线程可能同时等待进入synchronized(Singleton.class) 这句话,而之后又不再判断一次single是否为null,那么还是会出现多个实例(因为AB均可以先后进入这个代码块)。因此,我们更好的解决办法是双重判断:

第二次尝试

public class Singleton {      private Singleton() {}      private static Singleton single=null;      //静态工厂方法       public static Singleton getInstance() {           if (single == null) {                 synchronized(Singleton.class){                 if(single == null){                    single = new Singleton();                   }             }         }            return single;      }  }

当然,我们也可以将 Synchronized 关键词放在public方法上,同样可以起到效果,只是锁定这个方法会带来较大的效率损失。

改进方法

//静态内部类,既实现了线程安全,又避免了同步带来的性能影响public class Singleton {        private static class LazyHolder {           private static final Singleton INSTANCE = new Singleton();        }        private Singleton (){}        public static final Singleton getInstance() {           return LazyHolder.INSTANCE;        }    }  
//枚举单例实现public class Singleton {    private static enum Singleton {        INSTANCE;        private Singleton single;        private Singleton(){            single = new Singleton();        }        private Singleton getInstance(){            return single;        }    }}

饿汉式单例

//饿汉式单例先自己new一个实例,在你需要的时候直接返给你public class Singleton{       private static final Singleton singleton = new Singleton();       private Singleton(){}       public static Singleton getInstance(){          return singleton;       }}
  • 优点是:写起来比较简单,而且不存在多线程同步问题,避免了 Synchronized 所造成的性能问题;
  • 缺点是:当类 SingletonTest 被加载的时候,会初始化 static 的 instance,静态变量被创建并分配内存空间,从这以后,这个static的instance对象便一直占着这段内存(即便你还没有用到这个实例),当类被卸载时,静态变量被摧毁,并释放所占有的内存,因此在某些特定条件下会耗费内存。

许可协议

  • 本文遵守创作共享 CC BY-NC-SA 3.0协议
  • 商业用途转载请联系 Chen.Jiayang [AT] foxmail.com
  • 个人主页 chenjiayang.me
原创粉丝点击