设计模式-单例模式(5种创建方式)

1.概述:

所谓单例,就是整个程序有且仅有一个实例.该类负责创建自己的对象,同时确保只有一个对象被创建,常用于工具类的实现和创建对象需要消耗资源
特点:
构造器私有
持有自己的属性
对外提供获取实例的静态方法

2.创建单例的5种方式

  • 饿汉模式
  • 懒汉模式
  • 静态内部类
  • 枚举

1.饿汉模式:
当程序启动或类被加载的时候,实例就就被创建。

public class SingleBean{
	//构造私有
	private SingleBean(){}
	private static SingleBean singleBean=new SingleBean();
	public static SingleBean getInstance(){
		return singleBean;
	}
} 

2懒汉模式
—优点:单例对象在需要时,才会去构造
—缺点:线程不安全的,多个线程调用,会产生多个单例对象

public class SingleBean{
	//构造私有
	private SingleBean(){}
	private static SingleBean singleBean=null;
	public static SingleBean getInstance(){
		if(null==singleton){
			singleBean=new Singleton();
		}
		return singleBean;
	}

2.1懒汉模式(加双重锁+双重判断)

–优点:可以解决线程安全问题,效率高

public class SingleBean{
	//构造私有
	private SingleBean(){}
	private static volatile SingleBean singleBean=null;
	public static SingleBean getInstance(){
		//懒汉式初始化
		if(singleBean!=null){
			return singleBean;
		}
		synchronized(SingBean.class){
			if(singleBean!=null){
				return singleBean;
			}
			singleBean =new SingleBean();
		}
		return singleBean;
	}
} 

解释:
由于singleton=new Singleton()对象的创建在JVM中可能会进行重排序,在多线程访问下存在风险,使用volatile修饰signleton实例变量有效,解决该问题。
1.第一个判断,避免不要的实例。解决多线程情况下,不为空,直接返回,不需要再判断同步锁,提高性能
2.第二个判断,避免同步。在多线程情况下,一条线程a在执行new对象操作,其他线程在锁外等待,不加判断的话,则线程a执行完new之后,会产出多个单例对象

3.静态内部类
java的静态内部类的加载时在使用在该静态内部类的时候才去加载,是线程安全的

  1. 优点:实现简单,懒加载,线程安全
  2. 缺点:增加一个静态内部类,apk文件增大
public class SingleBean{
	//构造私有
	private SingleBean(){}
	private static class InnerClass{
		private static SingleBean singleBean;
		static{
			singleBean=new SingleBean();
		}
	}

	public static SingleBean getInstance(){
		return InnerClass.singleBean;
	}
} 

4.枚举
众所周知,单例模式是创建型模式,都会新建一个实例。那么一个重要的问题就是反序列化。当实例被写入到文件到反序列化成实例时,我们需要重写readResolve方法,以让实例唯一。

  1. 优点:使用枚举是线程安全的,不用担心序列化和反射问题
  2. 缺点:枚举占用内存多一点,。但枚举实例在日常开发是很少使用的,就是很简单以导致可读性较差。
public enum EnumSingleton{
	SINGLEBEAN;
	//doSomething 该实例支持的行为
      
    //可以省略此方法,通过Singleton.SINGLEBEAN进行操作
    public static Singleton getInstance() {
        return Singleton.SINGLEBEAN;
    }
	
}

5.CAS 自旋锁的方式创建单例

 //基于CAS的单例模式
    private static final AtomicReference<SingleBean> INSTANCE = new AtomicReference<SingleBean>();
    public static final SingleBean getInstance() {
        for (; ; ) {
            SingleBean current = INSTANCE.get();
            if (current != null) {
                return current;
            }
            current = new SingleBean();//高并发的场景下,可能会创建多个对象,但是最终只有一个会被使用,其它的会被丢弃
            System.out.println(current);
            if (INSTANCE.compareAndSet(null, current)) {
                return current;
            }
        }
    }

猜你喜欢

转载自blog.csdn.net/qq_18361601/article/details/106917579