单例模式浅谈
单例模式
单例模式:单例模式是指一个类只有一个实例并且该类能够自行创建这个实例的一种模式
特点
1、单例类只有一个实例对象
2、单例对象必须由该单例类自行创建
3、该单例类提供给外部唯一的访问点(即只能通过类中的一个具体方法才能访问到该单例)
缺点
1、单例模式一般没有接口,扩展起来比较困难,除了修改单例类的原代码,没有第二种途径,违背了设计模式中的开闭原则。
开闭原则的意思是:对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。
2、在并发测试中,单例模式不利于代码调试。在调试过程中,如果单例中的代码没有执行完,也不能模拟生成一个新的对象。
3、单例模式的功能代码通常写在一个类中,如果功能设计不合理,则很容易违背单一职责原则。
单一职责原则的意思是一个类不应该承担太多职责,一个类应该有且仅有一个引起它变化的原因,否则这个类应该被拆分。
单例模式的实现
①懒汉式:该模式的特点是类加载时没有生成单例,只有第一次调用getInstance方法时才去创建这个实例
public class LazySingleton {
// 先给单例赋值为空
private static LazySingleton instance = null ;
// 防止该单例类在外部被实例化
private LazySingleton(){
}
// 获取该单例类的单例对象
public static LazySingleton getInstance(){
if (instance == null){
instance = new LazySingleton();
}
return instance;
}
}
②饿汉式:该模式的特点是只要类一加载完成就会创建一个单例,即在调用getInstance前该实例就已经存在
public class HungrySingleton {
private static HungrySingleton instance = new HungrySingleton() ;
private HungrySingleton(){
}
public static HungrySingleton getInstance(){
return instance;
}
}
}
③双检锁/双重校验锁(DCL):这种方式采用双锁机制,不仅多线程安全而且可以保持高性能。
public class Singleton{
// 加volatile的防止构造函数与单例声明在jvm的优化下发生指令重排序
private static volatile Singleton singleton;
private Singleton(){
}
// DCL没有选择在方法上加锁,这样会导致效率低下
public static Singleton getInstance(){
// 进行第一次判断
if(singleton == null){
// 把Singleton的类对象锁起来,只能让一个线程进入到内部进行创建
synchronized (Singleton.class) {
// 当第一个获取锁的线程创建完成singleton对象后
// 其他的在第二次判断singleton一定不会为null
// 直接返回已经创建好的singleton对象
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
双检锁机制是在懒汉模式的基础上为了线程安全进行的改造,该方法不仅保留了懒汉模式下的懒加载机制同时还保证了线程的安全性
④登记式/静态内部类:使用内部静态类,能达到双检锁方式一样的功效,实现更简单,对静态域使用延迟初始化
public class Singleton{
private static class SigletonHolder{
private static final Singleton singleton = new Singleton();
}
private Singleton(){
}
public static Singleton getInstance(){
return SigletonHolder.singleton;
}
}
⑤枚举:这是实现单例模式的最佳方法。它更简洁,自动支持序列化机制,绝对防止多次实例化。
public enum Singleton{
INSTANCE;
public void whateverMethod(){
}
}