• 设计模式-单例模式的5种实现


    单例模式是开发中使用频率极高的一个模式,比如Spring的bean默认就是单例的。

    概念

    单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

    单例模式有一下特点:

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

    实现方式

    一般意义上来讲单例模式有两种实现方式,懒汉模式和饿汉模式。

    饿汉模式

    public class Singleton {  
        private static Singleton instance = new Singleton();  
        private Singleton (){}  
        public static Singleton getInstance() {  
            return instance;  
        }  
    }  
    

    类加载自动初始化对象,不是lazy init ,系统启动的压力增大。

    懒汉模式

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

    典型的懒汉模式,在需要初始化使用单例对象时才决定是否初始化,减轻了启动的负担,但是无法在多线程环境下运行,可能会导致产生多个实例。

    改进版的懒汉模式

    为了解决懒汉模式在多线程情况的问题,我们使用synchronized关键词同步代码,不就可以避免了同步问题了吗?

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

    这种改良方式的确会解决多线程的问题,但同时synchronized会导致每次方法调用时锁住Singleton实例一次,性能消耗太大。而且instance一旦初始化后,同步锁更加拖累效率。

    双重锁定的懒汉模式

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

    这种模式避免了域在被初始化之火访问这个域的锁定开销。这种模式的基本思想是:
    第一次检查时看看有没有锁定,看一看这个域是否已被初始化了;第二次检查时有锁定,只有当第二次检查时表明这个域没有被初始化,才开始进行初始化。

    这种模式既规避了延迟加载也避免了重复加锁带来的额外性能消耗。

    静态内部类

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

    当getInstance方法第一次调用时,第一次读取SingletonHolder.INSTANCE,导致SingletonHolder类得到初始化,这种方式并没有使用任何线程同步的机制,就保证了一次访问域代码。延迟初始化没有增加访问成本,这个方法值得推荐。

    结论

    5种方式,相对比较推荐第4种和第5种,做到了延迟加载,也没有引入额外的问题和性能开销。

  • 相关阅读:
    乱七八糟
    堆-heap
    转linux文件的读写
    @转EXT2->EXT3->EXT4
    (转)僵死进程与孤儿进程
    java
    poj-1062-昂贵的聘礼
    java 之 wait, notify, park, unpark , synchronized, Condition
    事物(笔记)
    BPX-tree
  • 原文地址:https://www.cnblogs.com/jason0529/p/6561017.html
Copyright © 2020-2023  润新知