• 设计模式之单例模式


    单例模式:

      对于某些应用场景下,某应用在整个系统运行期间,无需创建多份,典型应用如任务管理器,文档编辑工具(Office)。一是不会造成系统资源浪费,二不会出现内容不一致的情况。这样通过单例模式可以保证一致性。

      首先单例模式需要保证不能通过new关键字创建对象实例,及控制构造函数私有,然后通过统一的静态方法入口获取单一实例。

      单例模式常见的有两种:恶汉式、懒汉式。先看一下饿汉式模式

    1、饿汉模式

      饿汉模式,即在类加载时就创建对象,代码如下

    class EagerSingleton {
    private static final EagerSingleton instance = new EagerSingleton();
    private EagerSingleton() { }
    public static EagerSingleton getInstance() {
    
    return instanct;}

    2、懒汉模式

    懒汉模式,即实现“”延迟加载”,对象实例声明为null ,当调用时进行new。代码如下

    class LazySingleton {
    private static LazySingleton instance = null;
    private LazySingleton() { }
    public static LazySingleton getInstance() {
    if (instance == null) {
    instance = new LazySingleton();
    }
    return instance;
    }
    }

    但是懒汉有一个问题,即不能保证线程安全,考虑到多线程并发访问的时候可能导致对象不一致,为此可以为getInstance()方法前添加synchronized关键字,由于锁力度较大,可以考虑在instance = new LazySingleton();前增加synchronized代码块控制。另外这种情况也是会出现不一致的情况,通常类初始化较为复杂,可能两个线程都进入instance为null的判断,因此为保证一致性可以考虑在synchronized代码块中增加第二重为null判断,即双重锁检查(Double Lock Check)。

    class LazySingleton {
    private volatile static LazySingleton instance = null;
    private LazySingleton() { }
    public static LazySingleton getInstance() {
    //第一重判断
    if (instance == null) {
    //锁定代码块
    synchronized (LazySingleton.class) {
    //第二重判断
    if (instance == null) {
    instance = new LazySingleton(); //创建单例实例
    }
    }
    }
    return instance;
    }
    }
    

      注意:instance声明处,需要将其加上volatile关键字,可以确定多个线程可以正确处理。

    3、饿汉与懒汉模式的优缺点

      饿汉式单例在类初始化加载时,即创建。无需考虑线程安全,可以确保实例的一致性。调用速度,反应时间要较懒汉式优秀。资源利用率上,类加载时都需要进行实例化对象,时间可能更长。

      懒汉式单例,第一次使用时占用系统资源,实现延迟加载,必须处理好多线程的访问安全性问题,可通过双重检查锁进行控制。

      有没有既能保证一致性,也可以提交访问效率、提高资源利用率的方式呢?

    4、Initialization Demand Holder (IoDH)

      

    //Initialization on Demand Holder
    class Singleton {
    private Singleton() {
    }
    private static class HolderClass {
    private final static Singleton instance = new Singleton();
    }
    public static Singleton getInstance() {
    return HolderClass.instance;
    }
    public static void main(String args[]) {
    Singleton s1, s2;
    s1 = Singleton.getInstance();
    s2 = Singleton.getInstance();
    System.out.println(s1==s2);
    }
    }
    

      

    由于静态单例对象没有作为Singleton的成员变量直接实例化,因此类加载时不会实例化Singleton,第一次调用getInstance()时将加载内部类HolderClass,在该内部类中定义了一个static类型的变量instance,此时会首先初始化这个成员变量,由Java虚拟机来保证其线程安全性,确保该成员变量只能初始化一次。由于getInstance()方法没有任何线程锁定,因此其性能不会造成任何影响。通过使用IoDH,我们既可以实现延迟加载,又可以保证线程安全,不影响系统性能。

    (参考http://gof.quanke.name/)

  • 相关阅读:
    我为能准时下班而做的准备,以及由此的收获,同时总结下不足
    用象棋的思维趣说IT人的职业发展和钱途
    简历上如果出现过于高大上的项目,反而过犹不及:再论如何通过项目引出技术
    用python的matplotlib和numpy库绘制股票K线均线的整合效果(含从网络接口爬取数据和验证交易策略代码)
    如果当前没有拿得出手的简历,也别慌,努力的话最多两年情况就能改变
    分析若干没面试机会和没体现实力的简历
    IT人为了自己父母和家庭,更得注意自己的身体和心理健康
    Spring Cloud系列文,Feign整合Ribbon和Hysrix
    以互联网公司的经验告诉大家,架构师究竟比高级开发厉害在哪?
    博客园是个大金矿,管理员不挖掘有些可惜:给博客园提一些双赢的建议
  • 原文地址:https://www.cnblogs.com/SmilingFish/p/11489000.html
Copyright © 2020-2023  润新知