单例模式

一、什么是单例模式

        单例模式确保一个类只有一个实例,并提供一个全局访问点来访问这个唯一实例。对于一个软件系统中的一些类而言,只有一个实例很重要。例如一个系统只能有一个窗口管理器或文件系统,一个系统只能有一个计时工具等。

二、单例模式的结构

        单例模式是最简单的设计模式,它只包含一个类,即单例类。对于Singleton(单例),在单例类的内部创建它的唯一实例,并通过公有静态方法getInstance()让客户端可以使用它的唯一实例;为了防止在外部对单例类实例化,将其构造函数的可见性设为private;在单例类内部定义一个Singleton类型的静态对象作为供外部共享访问的唯一实例。

三、单例模式实现

单例模式的实现代码如下:

public class Singleton{
    private static Singleton instance=null; //静态私有成员变量
    
    //静态构造函数
    private Singleton{
    }

    //静态公有工厂方法,返回唯一实例
    public static Singleton getInstance(){
        if(Singleton==null){
            instance=new Singleton();
         return instance;
    }
}

客户端测试代码:

public class Client{
    public static void main(String[] args){
        Singleton s1=Singleton.getInstance();
        Singleton s2=Singleton.getInstance();
        //判断两个对象是否相同
        if(s1==s2){
            System.out.println("两个对象是相同实例.");
        }
        else{
            System.out.println("两个对象是不同实例."):
        }
    }
}

编译代码并运行,输出结果为:

两个对象是相同实例.

四、饿汉式单例

    饿汉式单例类在定义静态变量的时候实例化单例类,因此在类加载时单例对象就已创建。代码如下:

public static EagerSingleton{
    private static final EagerSingleton instance=new EagerSingleton();
    private EagerSingleton(){
    }

    public static EagerSingleton getInstance(){
    return instance;
    }
}

        当类被加载时静态变量instance就会被初始化,此时类的私有构造函数会被调用,单例类的唯一实例就会被创建。

五、懒汉式单例

       懒汉式单例在第一次调用getInstance()方法时实例化,在类加载时并不自行实例化,这种技术又称为延迟加载技术,即需要的时候再加载实例。为了避免多个线程同时调用getInstance()方法,可以使用关键字synchronized,代码如下:

public class LazySingleton{
    private static LazySingleton instance=null;

    private LazySingleton(){}

    //使用synchronized关键字加锁,确保在任意时刻只有一个线程可执行该方法
    synchronized public static LazySingleton getInstance(){
        if(instance==null){
            instance=new LazySingleton();
        }
        return instance;
    }
}

        在上述懒汉式单例类中,在getInstance()方法前面增加了关键字synchronized进行线程锁定,以处理多个线程同时访问的问题。上述代码虽然解决了线程安全的问题,但每次调用getInstance()时都需要进行线程锁定判断,在多线程高并发访问环境中将会导致系统性能大大降低。因此可以继续对懒汉式单例模式进行改进,通过分析不难发现无需对整个getInstance()方法进行锁定,只需对其中的代码instance=new LazySingleton()进行锁定即可。getInstance()可以进行如下改进:

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

        但是上述代码仍然存在单例对象不唯一的情况。为解决这个问题,可以使用“双重检查锁定”(Doubl-Check Locking)。使用“双重检查锁定”实现的懒汉式单例类的完整代码如下:

public 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。

六、饿汉式单例类和懒汉式单例类的比较

        饿汉式单例类在类被加载时就将自己实例化,它的优点在于无需考虑多个线程同时访问的问题,可以确保单例的唯一性,但是在资源利用效率方面不如懒汉式;懒汉式实例类在第一次使用时创建,无须一直占用系统资源,实现了延迟加载,但是必须处理多个线程同时访问的问题。

七、单例模式使用环境

1.系统只需要一个实例对象,例如系统只需要一个唯一的序列号生产器或资源管理器

2.客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值