首页 > 技术文章 > Java设计模式之单例模式

xiexi 2021-09-02 18:09 原文

单例模式

概述

单例模式就是要确保类在内存中只有一个对象,
该实例必须自动创建,并且对外提供

优点
在系统内存中只存在一个对象,因此可以节约系统资源,
对于一些需要频繁创建和销毁的对象单例模式可以提高系统性能

缺点
没有抽象层,因此扩展很难
职责过重,在一定程序上违背了单一职责

实现

  1. 构造方法私有
  2. 在成员位置创建一个对象,对象为私有(防止外界改变)静态
  3. 公共静态方法提供访问

分类
饿汉式:类一加载就创建对象 (开发中,Java中的Runtime类)
懒汉式:用的时候,才去创建 (面试中)

懒汉式问题
延迟加载
线程安全问题,需要加synchronized

饿汉式

public class Singleton {
	
	//1.构造方法私有
	private Singleton() {}
	
	//2.在成员位置创建一个对象,对象为私有(防止外界改变)静态 (类一加载就创建对象)
	private static Singleton instance = new Singleton();
	
	//3.提供一个访问的方法
	public static Singleton getInstance(){
		return instance;
	}
}

懒汉式

public class Singleton {
	
	//1.构造方法私有
	private Singleton() {}
	
	//2.在成员位置创建一个对象,对象为私有(防止外界改变)静态
	private static volatile Singleton instance = null;
	
	//3.提供一个访问的方法
	public static Singleton getInstance(){
		
		if(instance == null){
			synchronized (Singleton.class) {
				if(instance == null){
					return instance = new Singleton();
				}
			}
		}
		return instance;
	}
}

volatile:作为禁止指令重排,保证返回Singleton对象一定在创建对象后。instance = new Singleton();语句非原子性,实际会执行以下内容:1.在堆上开辟空间;2.属性初始化;3.引用指向对象。
在单线程的情况下,指令重排不会有影响(正常顺序为1→2→3,重排后顺序可能为:1→3→2)
在多线程的情况下,指令重排后可能会导致返回的对象为空
volatile关键字可保证指令的顺序执行。

第一层null检:检测是否有引用指向对象,高并发情况下会有多个线程同时进入。

:保证只有一个线程进入

双重检查:防止多个线程同时进入第一层检查(因单例模式值允许存在一个对象,故在创建对象之前无引用指向对象,所有线程均可进入第一层检查)
当某一线程获得锁创建一个Singleton对象是,即已有引用指向对象,Singleton不为空,从而保证只会创建一个对象。
假设没有第二层检查,那么第一个线程创建完对象释放锁后,后面进入的线程也会创建对象,会产生多个对象

推荐阅读