设计模式之单例模式


单例模式
  初衷是为了使资源共享,只需要赋值或者初始化一次,大家都能重复利用

应用场景: Listener本身单例,日历Calendar,IOC容器,配置信息Config(除了差异性的)

技术方案: 保证整个运行过程中只有一份,
饿汉式、懒汉式、注册登记式(枚举式)、反序列如何保证单例

1.饿汉式

特点:

  • 这个是线程绝对安全的:
  • 优点:没有加任何锁,执行效率高
  • 用户体验:比懒汉式更好
  • 缺点:类加载的时候就初始化了,不管用不用都占用空间,浪费内存
	public class Hungry{
	  private Hungry{}
	  private static final Hungry hugry  = new Hungry();
	  
	  public static Hungry getInstance(){
	    return hugry;
	  }
	}
2.懒汉式

特点: 延迟加载

2.1 (线程非安全)
 public class Lazy{
 	  private Lazy{}
	  
	  private static Lazy lazy;
	  
	  public static Lazy getInstance(){
		  if(lazy == null){
		     lazy = new Lazy();
		  }
	    return hugry;
	  }
	}	
2.2 (线程安全)
  public class LazyTwo{
 	  private LazyTwo{}
	  
	  private static LazyTwo lazy;
	  
	  public  static synchronized LazyTwo getInstance(){
		  if(lazy == null){
		     lazy = new LazyTwo();
		  }
	    return lazy;
	  }
	}	

或者 //双重校验式,稍微增加点效率

public class LazyTwo{
	private volatile static LazyTwo lazy; //这里这里需要使用volatile否则可能还是有问题
	private LazyTwo() {}
	public static LazyTwo getSingleton() {
		if (lazy== null) {
			synchronized (LazyTwo.class) {
				if (lazy== null) {
					lazy= new LazyTwo(); //如果lazy引用不是使用volatile修饰,这里会发生指令重排序的问题,造成一定的问题(虽然概率较小),可以参考https://blog.csdn.net/weixin_40792878/article/details/86411163
				}
			}
		}
		return singleton;
	}
}
3.内部类实现

特点:
利用了外部类被调用的时候内部类才会被加载
内部类一定是要在方法调用之前初始化
兼顾了:懒汉式的延迟加载以及synchronized的安全问题

public class LazyThree{
    
	private static boolean initialized =false;  //这里可能出现通过反射改写的情况,也稍微耗费性能
	
	private LazyThree(){
	  //避免反射入侵
	 sychronized(LazyThree.class){
	    if(initialized == false){
	      initialized = !initialized;
		}else{
		  throw new RuntimeException("单例被侵犯...")
		}
	 }
           
	}
	
	//static 使单例空间共享
	//final保证方法不会被重写,重载
	public static final LazyThree getInstance() {return LazyHolder.Lazy;}
	
	//默认不加载
	private static class LazyHolder{  //默认不加载
	   private static final LazyThree LAZY =new LazyThree();
	}
	
  }	
4.注册登记式

这个是Spring中使用的方式,这里简单的使用下

 public class BeanFactory{
    private BeanFactory(){}
      //利用ConcurrentHashMap的锁
	 private static Map<String,Object> ioc = new ConcurrentHashMap<>();
  
     public static synchronized Object getBean(String className){
	  if(ioc.containsKey(className)){
	     return ioc.get(className);
	  }else{
	    Obj obj = Class.forName(className).newInstance();
		return ioc.put(className,obj);
	  }
	 }
  
  }
5.枚举式
public enum Season{
   SPRING(){
    private string des = "春天恒美";
   },SUMMER;
}  
6.使用CAS来实现
public class Singleton {
    private static final AtomicReference<Singleton> INSTANCE = new AtomicReference<Singleton>(); 

    private Singleton() {}

    public static Singleton getInstance() {
        for (;;) {
            Singleton singleton = INSTANCE.get();
            if (null != singleton) {
                return singleton;
            }

            singleton = new Singleton();
            if (INSTANCE.compareAndSet(null, singleton)) {
                return singleton;
            }
        }
    }
}
7.解决反序列化单例问题解决

有时候反序列化 也会多new一个对象。
参考:https://blog.csdn.net/chy6575/article/details/51063505

 public class Seriable implements Serializable{
   
	  private Seriable(){}
   
      public final static Seriable INSTANCE = new Seriable();
	  
	  public static Seriable getInstance(){
	     return INSTANCE;
	  }
	  
	  //添加这个hook函数,那么系统在反序列化的过程中就会通过该Hook方法得到原有的单例
    //而不是重新创建一个单例。
	  private Object readResolver(){
		return INSTANCE;
	  }     
   }

这个只是一些笔记,反序列化和登记式只是一个方案,需要自己优化代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值