设计模式之《单例模式》的多种实现--Java

Java单例模式如何实现

 

单例模式属于创建型设计模式,该类设计模式抽象了对象创建、组织的过程,将目标类的信息进行封装,仅向外部提供获取对象的接口。

单例模式确保系统中只包含一个目标类的实例,负责完成其实例化并向外部提供该实例。一般可用于文件创建、数据库连接等辅助类,实现对系统资源的控制。

一般来说,单例模式在实现上具有私有构造方法、私有静态变量、公有返回接口等特点。以下为几种常见的单例模式实现方法。

1.饿汉模式

饿汉模式在类加载时完成实例的创建,不存在线程安全的问题,缺点在于即使未被引用也始终会存在该类的实例。

class Singleton{
    private static final Singleton singleton = new Singleton();
​
    private Singleton(){}
​
    public static Singleton getInstance(){
        return singleton;
    }
}
  • 注意final,保证引用的实例不变。

2.懒汉模式

懒汉模式在初次获取实例时完成创建并返回,可以实现懒加载,但其缺点在于初次获取时可能需要更长的时间;适用于创建消耗大、实例使用少的情况,存在线程安全问题。

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

3.双重检验锁

双重检验锁是适用于多线程模式下的懒汉模式,相比于直接对整个getInstance()方法加锁,可以减少大量进入临界区的性能消耗。

class Singleton{
    private static volatile Singleton singleton;
​
    private Singleton(){}
​
    public static Singleton getInstance(){
        if (singleton == null){
            synchronized (Singleton.class){
                if (singleton == null){
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}
  • 第一层判断是为了在实例已经初始化时直接返回,第二层锁可以防止同时进入临界区的不同线程多次实例化对象。

  • 注意volatile:

    • 由于singleton = new Singleton();并非原子操作,而是由分配内存空间、初始化对象以及将引用指向堆对象三个步骤完成,而在JVM执行时可能产生重排序,使得引用变量指向了未初始化的堆对象,导致另一个线程判断失败(第一层)获取到该未初始化的实例;如下图所示:

    • volatile关键字可以保证线程之间的可见性及有序性,使所有写操作先于读操作执行,避免上述问题。

4.利用静态内部类

  1. 线程安全:与懒汉模式相同,利用类的加载保证单例对象只被实例化一次;

  2. 懒加载:由于一个类只有在其静态成员初次被引用时才会被加载,即调用Singleton.getInstance()时内部类SingletonHolder才会被加载,同时初始化instance

  3. 反射安全:通过反射不能从外部类中获取内部类的属性,即不可对instance进行修改。

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

 

5.利用枚举Enum

在Java中,枚举可以看作一个类,其中也可以定义方法;而枚举中的变量可以看作该类的一个实例。枚举的构造方法限制为私有,在初次访问枚举实例时执行;而枚举中的实例定义为static final,从而只可实例化一次。

class SingleTon{}
​
enum SingleEnum{
    myEnum;          // 枚举实例
    private SingleTon singleTon;
    SingleEnum() {       // 构造方法,默认为private
        singleTon = new SingleTon();
    }
    public SingleTon getSingle(){
        return singleTon;
    }
}

实例的获取:

SingleTon s=SingleEnum.myEnum.getSingle();

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值