设计模式之单例(饿汉式、懒汉式、注册式枚举、容器)

这篇博客详细介绍了Java中的单例模式实现方式,包括饿汉式、懒汉式和注册式。饿汉式在类加载时创建单例,但可能导致资源浪费;懒汉式在首次使用时创建,但简单的实现不线程安全;双重检查锁解决了线程安全问题,但增加了代码复杂性。静态内部类利用类加载机制保证线程安全,但可能因反射破坏单例。注册式中,枚举在加载时实例化,而容器式优化了内存使用,但可能引发线程安全问题,如Spring的IOC容器所采用的方式。
摘要由CSDN通过智能技术生成

一、饿汉式

1. 简单的饿汉式

	public class HungrySingleton {
	
	    private HungrySingleton(){
	
	    }
	
	    private final static HungrySingleton h = new HungrySingleton();
	
	    public  static HungrySingleton getInstance(){
	        return HungrySingleton.h;
	    }
	}

2. 静态代码块写法

public class HungrySingletonStatic {
	
	    private HungrySingletonStatic(){
	
	    }
	
	    private final static  HungrySingletonStatic h;
	
	    static {
	        h = new HungrySingletonStatic();
	    }
	
	    public static  HungrySingletonStatic getInstance(){
	        return HungrySingletonStatic.h;
	    }
	}

3. 两种写法的总结

饿汉式的这两种写法都是一样的,在类初始化的时候就创建了一个对象实例,当调用这个静态方法的时候返回的也是同一个对象实例,符合单例的设计思想。但是如果使用的单例比较多的情况下,使用这种方法在加载类的时候就会耗费很多资源,有些单例类可能暂时用不上,造成资源浪费。

二、懒汉式

1. 简单的懒汉式

public class LazySingleton {

    private LazySingleton(){}

    private static LazySingleton lazySingleton ;

    public static  LazySingleton getInstance(){
        if(lazySingleton == null){
            return new LazySingleton();
        }
        return lazySingleton;
    }
}

这里的懒汉式是线程不安全的,如果要线程安全需要枷锁,加锁之后代码如下

public class LazySingleton {

    private LazySingleton(){}

    private static LazySingleton lazySingleton ;

    public static synchronized LazySingleton getInstance(){
        if(lazySingleton == null){
            return new LazySingleton();
        }
        return lazySingleton;
    }
}

但是这种懒汉式加锁之后有性能问题

2. 双重检查锁

public class LazySingletonLock {

    private LazySingletonLock(){

    }

    private static LazySingletonLock lazySingleton ;

    public static  LazySingletonLock getInstance(){
        if(lazySingleton == null){
            synchronized (LazySingletonLock.class){
                if (lazySingleton == null){
                    lazySingleton = new LazySingletonLock();
                }
            }

        }
        return lazySingleton;
    }

}

双重检查锁解决了性能问题,但是代码量稍大。

3. 静态内部类

public class LazySingletonStatic {

    private LazySingletonStatic(){

    }
    
    private static class LazySingleton{
        private static final LazySingletonStatic l = new LazySingletonStatic();
    }

    public static  LazySingletonStatic getInstance(){
        return LazySingleton.l;
    }

}

这里用了Java的类加载机制,静态内部类只有使用的时候才会被加载,但是使用反射强制获取构造方法的时候就会破环单例,使用反射获得的构造方法可以创建无数个实例。

三、注册式

1. 枚举

public enum EnumSingleton {
    INSTANCE;
    private Object data;
    public Object getObj(){return data;}

    public void setData(Object data) {
        this.data = data;
    }

    public static EnumSingleton getInstance(){
        return INSTANCE;
    }
}

如果使用反射强制获取枚举的构造方法并且创建实例的时候,枚举的构造方法会抛出一个异常
在加载的时候就会实例化,内存浪费,又变成饿汉式。

2. 容器式

public class Container {

    private Container(){}

    //hashMap在初始化的时候,会有多个KEY相同,但是值不相同的数据,存储时一个KEY可能存入两个value的情况
    private static Map<String,Object> singleton = new HashMap<>();

    public static void putInstance(String key,Object object){
        if( key.length() > 0 && object != null){
            if(!Container.singleton.containsKey(key)){
                singleton.put(key,object);
            }
        }
    }

    public static Object getInstance(String key){
        return singleton.get(key);
    }
}

是枚举单例的优化版本,解决了可能造成内存浪费的问题,但是引发了线程安全问题,Spring IOC容器使用的这种方式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值