`

单例模式几种写法

阅读更多

所谓单例模式,简单来说,就是在整个应用中保证只有一个类的实例存在。类似Spring中的IOC 配置,bean实例化默认都是单例模式的。

 单例的四种写法:

1.饿汉式单例

//饿汉式
public class Singleton{
  //1.私有的唯一的静态实例变量,在类加载的时候就创建好单例对象  
  private static final Singletion instance= new Singleton();
  //2.私有的构造函数,确保不能在类的外部访问该类的构造函数  
  private Singleton{}
  //3.通过静态工厂方法返回类的唯一实例
  private static Singletion getInstance(){
    return instance;
  }
}

  优点:此写法是线程安全的

  缺点:会增大初始化类和创建对象的开销

 

2.懒汉式

public class Singleton {
  //1.一个私有的指向自己的静态变量  
 private static Singleton instance = null;
  // 2.私有的构造方法,保证不能从外部创建对象
  private Singleton{}
  //3.真正获取实例的时候才进行初始化,如果多线程访问 synchronized会阻塞其他线程
 public static synchronized Singleton getInstance() {
  if (instance == null)
   instance = new Singleton(); // lazy load
  return instance;
 } 
}

优点: 延时加载,只有在使用的时候进行初始化

问题:同步锁粒度在多线程进行获取实例的时候会出现阻塞,加大了因锁竞争的性能开销

 

3.double-check双重检查锁定

public class Singleton { 
  //1.volatile保证可见性
 private static volatile Singleton instance = null;
  // 2.私有的构造方法,保证不能从外部创建对象
  private Singleton{}
 public static Singleton getInstance() { 
     //3.instance使用volatile标识可以保证所有线程访问同一共享变量的可见性问题
   if (instance == null) {// double check (jdk1.5+)
      //4.synchronized虽然保证了原子性,但不能保证 同步方法里面的顺序性
      //5. instance = new Singletion(),其实由三步组成  
      //   1).分配对象内存空间 2).初始化对象  3).设置instance指向刚分配的内存地址 
      //6.由于不同cpu的内核,JMM重排序粒度不一样,instance在第2,3步见可能会被重排序
      //  执行过程中instance不为null,但获取对象 并不是真正赋值对象(旧值或空值)
   synchronized (Singleton.class)
    if (instance == null){
     instance = new Singleton();
        }
      }
  return instance;   
 } 
} 

优点: 用双重验证的方式,降低因多线程因为同步锁而造成的开销,同步锁保证模块执行的原子性,volatile保证实例可见性

缺点:同步锁模块内部方法体instance = new Singleton();并不是原子性操作(像count++也不是原子性操作) 还是可能造成JIT编译器对代码进行重排序 导致对象的值不正确

 

4.静态内部类写法

public class Singleton { 
  //1.在第一次被引用时被加载 
 private static class Holder { // lazy class
  static final Singleton instance = new Singleton();
 }
  //2.保证不能进行构造
  private Singleton(){ } 
  //3.通过静态方法获取
 public static Singleton getInstance() {
  return Holder.instance;   
 } 
} 

 优点:线程安全的,且在使用时才会被进行初始化操作,优于上面三种方式

 

5.单例  枚举写法

 

public enum SingletonEnum {

    instance;
    /*
     * do something
     */
    public void doSomething(){
        System.out.println("do something");
    }
}
 

 

 

总之,懒汉,恶汉,双重校验锁,静态内部类,枚举。
恶汉:因为加载类的时候就创建实例,所以线程安全(多个ClassLoader存在时例外)。缺点是不能延时加载。
懒汉:需要加锁才能实现多线程同步,但是效率会降低。优点是延时加载。
双重校验锁:麻烦,在当前Java内存模型中不一定都管用,某些平台和编译器甚至是错误的,因为instance = new Singletion()这种代码在不同编译器上的行为和实现方式不可预知。
静态内部类:延迟加载,减少内存开销。因为用到的时候才加载,避免了静态field在单例类加载时即进入到堆内存的permanent代而永远得不到回收的缺点(大多数垃圾回收算法是这样)。
枚举:很好,不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象。但是失去了类的一些特性,没有延迟加载,用的人也太少了~~

 

可参考:

http://www.tuicool.com/articles/NVza2am

分享到:
评论

相关推荐

    java-单例模式几种写法

    自己总结的6中单例模式的写法,也有测试类,可以试验下,自己稍微修改一下后,验证安全性,纯粹为学习,建议可提

    unity中涉及的三种单例模式

    unity中在场景切换时需要经常数据分享并处理,在此分享给大家利用C#模式和Unity模式分别实现的单例共享数据

    面试官的一道简单的单例模式问题给我问懵了,详解单例模式双重检查加锁为什么要加volatile关键字!

    面试官:说说单例模式几种写法? 我:懒汉式和饿汉式,懒汉式巴拉巴拉,饿汉式巴拉巴拉。 面试官:我们都知道synchronized加锁是比较耗费资源的,你这种写法每次访问都需要获得锁(基础的懒汉式写法),效率比较低,...

    简单了解python单例模式的几种写法

    主要介绍了简单了解python单例模式的几种写法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    线程安全的单例模式的几种实现方法分享

    线程安全的单例模式实现有几种思路,个人认为第2种方案最优雅:、饿汉式、借助内部类、普通加锁解决、双重检测,但要注意写法,如果单体模式继续扩展为N元单体模式,那就是对象池模式了

    详解java中的6种单例写法及优缺点

    在java中,单例有很多种写法,面试时,手写代码环节,除了写算法题,有时候也会让手写单例模式,这里记录一下单例的几种写法和优缺点。需要的朋友可以参考下

    谈一谈iOS单例模式

    单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。...2、具体单例模式的几种模式 第一种单例模式 //非线程安全写法 static UserHelper * helper = nil; + (UserH

    详解Java中如何正确书写单例模式

    一般单例都是五种写法:懒汉,饿汉,双重校验锁,静态内部类和枚举。本文整理了几种常见的单例写法,下面跟着小编一起来看下吧

    DegignPattern.rar

    策略模式实例,单例模式(懒汉最优实例【饿汉模式的几种写法】,经典饿汉模式)后面会持续追加其他设计模式

    C#设计模式.rar

    C# 几种 设计模式Demo 以及优缺点注释 主要有 1单例模式 2简单工厂 3抽象工厂 4委托的另外一种写法 5...

    2023年最新java面试大全

    【06期】单例模式有几种写法? 【07期】Redis中是如何实现分布式锁的? 【08期】说说Object类下面有几种方法呢? 【09期】说说hashCode() 和 equals() 之间的关系? 【10期】Redis 面试常见问答 【11期】分布式...

    精通QTP——自动化测试技术领航

    1.7.2 掌握描述性编程的两种写法 173 1.7.3 Object Identification与Spy结合DP的妙用 177 1.7.4 描述性编程的妙用以及与对象库编程的混搭 180 1.7.5 终极对决—对象库编程(OP)?VS描述性编程(DP) 186 1.7.6 总结 ...

Global site tag (gtag.js) - Google Analytics