设计模式之单例模式

设计模式之单例模式

单例设计模式:

  • 单例顾名思义只包含一个对象被称为单例的特殊类。
  • 通过单例模式可以保证系统中,应用该模式的类只有一个对象实例。

使用场景

  • 业务系统全局只需要一个对象实例,比如redis连接对象、发号器等
  • Spring IOC容器中的bean默认就是单例
  • spring boot中的controller、service、dao层中通过@autowire的依赖注入对象默认都是单例的

分类

  • 懒汉:就是所谓的懒加载,延迟创建对象
  • 饿汉:与懒汉相反,提前创建好对象

实现步骤

  • 私有化构造函数
  • 提供获取单例的方法

设计模式之单例模式_第1张图片
懒汉方式实现的几种方式如下:

public class SingletonLazy{
     
	//private static SingletonLazy instance;
	/**
	*构造函数私有化
	*/
	private SingletonLazy(){
     }
	/**
	*单例对象的方法
	*/
	public void process(){
     
		system.out.printIn("方法调用成功");
	}
	/**
	*第一种方式
	*对外暴露一个方法获取类的对象
	*多线程下存在安全问题,线程不安全
	*/
	/*
	public static Singletonlazy getInstance(){
		if(instance == null){
			instance  = new SingletonLazy();
		}
		return instance;
	}
	*/
	/**
	*第二种方式
	*通过synchronized加锁保证单例
	*采用synchronized对方法加锁有很大的性能开销
	*解决办法:锁粒度不要这么大
	*/
	/*
	public static synchronized Singletonlazy getInstance(){
		if(instance == null){
			instance  = new SingletonLazy();
		}
		return instance;
	}
	*/

/**
	*第三种方式
	*DCL 双重检查锁定,在多线程情况下保存高性能
	*不一定安全,因为instance = new SingletonLazy();并不是原子性操作
	*1、分配空间给对象
	*2、在空间内创建对象
	*3、将对象赋值给引用instance
	*根据JVM的指令重排特性,假如线程按照1->3->2顺序,会把值写进主内存,其他线程就会读到instance最新的值,但是这个是不完全的对象
	*/
	/*
	public static  Singletonlazy getInstance(){
		if(instance == null){
			synchronized(SingletonLazy.class){
			if(instance == null){
				instance  = new SingletonLazy();
				}
			}
			
		}
		return instance;
	}
	*/

/**
	*volatile是java提供的关键字,它具有可见性和可序性
	*指令重排是JVM对语句执行的优化,只要语句间没有依赖,那JVM就有权对语句进行优化
	*禁止指令重排
	*/
	
	private static volatile SingletonLazy instance;
	public static  Singletonlazy getInstance(){
     
	//第一重检查
		if(instance == null){
     
		//A、B线程锁定
			synchronized(SingletonLazy.class){
     
			//第二重检查
			if(instance == null){
     
				instance  = new SingletonLazy();
				}
			}
			
		}
		return instance;
	}
	
	
	
	



}

饿汉的实现方式比较简单如下:

public class SingletonHungry{
     
	private static SingletonHungry instance = new SignletonHungry();

	//私有化构造函数
	private SingletonHungry(){
     }

	public static SingletonHungry getInstance(){
     
		return instance;
	}
/**
	*单例对象的方法
	*/
	public void process(){
     
		system.out.printIn("方法调用成功");
	}

}

饿汉方式的优缺点:

  • 优点;实现简单,没有多线程同步问题
  • 缺点:不管有没有使用,instance对象一直占用着这段内存

懒汉与饿汉如何选择:

  • 如果对象不大,且创建不复杂,直接用饿汉的方式
  • 其他情况则更多采用懒汉实现方式

JDK源码里面的单例模式

  • JDK中Runtime类 饿汉方式
    设计模式之单例模式_第2张图片
  • JDK中Desktop类 懒汉方式

设计模式之单例模式_第3张图片

你可能感兴趣的:(设计模式)