Java一天GET一个设计模式之单例模式


前言

单例模式:单例模式是比较常见的一种设计模式,其优点也是比较明显

1.它能避免对象重复创建,节约空间并提升效率
2.避免有偶遇操作不同实例导致逻辑错误

单例模式的构建

1.1饿汉式

三步完成:

  • new一个静态对象
  • 私有构造器
  • 提供个共有化的对象获取方法
public class HungrySingleton {
    
    private static HungrySingleton singleton = new HungrySingleton();
    //构造器私有化
    private HungrySingleton(){}
    public static HungrySingleton getInstance() {
        return singleton;
    }
}

结论

饥饿胡汉三疯狂的想找对象 ,以至于使用的招数下流简单粗暴 
所以找到的对象也不是正经安全的对象 = 线程不安全的单例模式

1.2懒汉式

构建也是与饿汉式比较的相似

public class LazySingleton {
    private static LazySingleton singleton;
    //私有化构造器
    private LazySingleton(){}
    //synchronized  加上同步才能实现单例
    public static synchronized LazySingleton getInstance() {
        if (null == singleton){
            singleton = new LazySingleton();
        }
        return singleton;
    }
}

当然也有另一种写法:

这种写法锁颗粒度更细,锁之外可有更多的扩展。

public class LazySingleton {
    private static LazySingleton singleton;
    //私有化构造器
    private LazySingleton(){}
    public static LazySingleton getInstance() {
    	synchronized(LazySingleton.class){
    		if (null == singleton){
            	singleton = new LazySingleton();
        	}
    	} 
        return singleton;
    }
}

以上写法是乍一看没有毛病,但是多线程情况下同时进入getInstance()方法,每次都要执行synchronized同步化方法,这样会严重影响性能,所以更高级的做法就是在同步前,再加上一层检查。
这种方式又叫做:双重校验锁单例模式

public class LazySingleton {
    private static LazySingleton singleton;
    //私有化构造器
    private LazySingleton(){}
    public static LazySingleton getInstance() {
    	if (null == singleton){
            synchronized(LazySingleton.class){
		    	if (null == singleton){
		            singleton = new LazySingleton();
		        }
    		} 
        }
        return singleton;
    }
}

结论

懒汉懒汉虽然很懒,又渴望对象
懒汉找对象肯定想找个比较好的对象,来弥补自己的懒散,然而自己又比较懒,所以找得比较慢
故:懒汉式效率低而线程安全

1.3静态内部类

静态内部类的方式在实际开发环境中还是比较少用的,原因就是它用懒加载的方式实现的。

那么静态内部类是怎么去实现懒加载的呢

Java类加载过程中包含:加载、验证、准备、解析、初始化。
初始化阶段就是执行clinit方法(clinit = class + initialize),包括为类的静态变量赋初始值和执行静态代码块中的内容。
但是不会立即执行加载内部类,而是在调用它时才会加载。
所以当此StaticInnerClassSingleton 类加载时,Singleton 并不会被加载,所以不向饿汉式那样占用内存。

其次,Java虚拟机规定,当访问一个类的静态字段时,如果此类未被初始化,则立即初始化此类。
所以但StaticInnerClassSingleton 调用getInstance 方法时,由于使用到了Singleton 的SINGLETON 变量,这时候才会去初始化内部类。
这就实现了懒加载。
public class StaticInnerClassSingleton {
    private StaticInnerClassSingleton(){}

    //实质上就式在静态类中去建立一个对象
    private static class Singleton {
        private static final StaticInnerClassSingleton SINGLETON = new StaticInnerClassSingleton();

    }

    public static StaticInnerClassSingleton getInstance(){
        return Singleton.SINGLETON;
    }

}

1.4枚举

枚举时jdk1.5之后才出现的,估计很多小伙伴用的都比较少吧

public enum  EnumSingleton {
    SINGLETON;
    
    public void method(){

    }
}

枚举类型使用起来也是简单,直接EnumSingleton.SINGLETON 调用即可。

总结

笔者使用的比较多的是枚举类型,使用起来简单方便。不过还是要根据自己的环境进行取舍。一般建议是对于那些构建不复杂的,加载完立即使用的,建议使用饿汉式。对于构建耗时较长的使用较少的,建议使用懒汉式。因为程序要讲构建和使用分离,达到更好的解耦,所以这里一般很少用到静态内部类的方式。

总目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值