【设计模式笔记】建立型--单例模式

单例模式(Singleton)

确保一个类只有一个实例,而且自行实例化并向系统提供这个实例;提供全局访问的方法java

常见场景:windows的任务管理器(单实例)windows

结构图

 

上面的getInstance方法在多线程状况下,或致使屡次new实例,从而使用方获得的不是同一份实例安全

单例模式--饿汉式(多线程问题解决方式1)

 

代码样例:多线程

/**
 * 饿汉式单例:类加载式就启动实例的初始化,保证使用时实例已建立完毕,从而全部适用方都获取同一份实例
 * @author clari
 *
 */
public class EagerSingleton {
    
    // 类加载时,随即被实例化
    private static EagerSingleton instance = new EagerSingleton();
    
    private EagerSingleton()
    {
        
    }
    
    public static EagerSingleton getInstance()
    {
        return instance;
    }
}

单例模式--懒汉式单例(解决多线程问题)

 

 代码样例性能

/**
 *  懒汉式单例
 *  第一次使用时才建立,延迟加载,可能资源初始化耗时
 * @author clari
 *
 */
public class LazySingleton {

    private volatile static LazySingleton instance = null;
    
    private LazySingleton()
    {
        
    }
    
    // 双重检查锁定:同时增长volatile确保成员变量能够对多个线程正确处理
    private static LazySingleton getInstance()
    {
        if (null == instance) {
            synchronized (LazySingleton.class) {
                if (null == instance) {
                    instance = new LazySingleton();
                }
            }
        }
        return instance;
    }
}

 

饿汉式 vs 懒汉式

饿汉式:类加载时已实例化,不用考虑多线程访问问题。可是无论实例最终是否会使用,都会提早实例化,可能形成资源的浪费;同时系统加载时需实例化,可能形成系统加载缓慢;spa

懒汉式:第一次使用时实例化,不提早预占资源,必须处理好多个线程访问的问题。实例化时可能会耗费较长时间,意味着多线程同时访问的概率更大,须要双重检查致使系统性能获得损失。线程

 

更优的单例解决方法

IoDH: Initialization on Demand Holder: 类中增长一个静态内部类,内部类建立实例对象。code

第一次调用getInstance()方法时加载内部类,此时初始化该内部类的静态对象instance,由Java虚拟机保证内部类初始化实例的的线程安全性,确保只初始化一次。对象

既实现延迟加载,又保证线程安全,不影响系统性能(getInstance()方法没有任何线程绑定)。blog

public class BetterSingleton {

    private BetterSingleton()
    {
        
    }
    
    private static class HolderClass
    {
        private final static BetterSingleton instance = new BetterSingleton();
    }
    
    private static BetterSingleton getInstance()
    {
        return HolderClass.instance;
    }
    
    public static void main(String[] args) {
        BetterSingleton  s1, s2;
        s1 = BetterSingleton.getInstance();
        s2 = BetterSingleton.getInstance();
        
        System.out.println("s1 == s2: " + (s1==s2));
    }

}

 

 单例的缺点

一、没有抽象层,扩展存在困难;

二、职责太重,必定程度违背单一职责原则,同时提供业务方法,也提供建立对象方法,将对象建立和访问耦合一块儿。

三、java实现了垃圾自动回收,若是实例化对象长期不适用,可能会被垃圾回收,后面再适用再次从新实例化,则可能致使共享的单例对象状态的丢失。

相关文章
相关标签/搜索