设计模式 - 单例模式
Posted 思想累积
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式 - 单例模式相关的知识,希望对你有一定的参考价值。
创建者模式提供创建对象的机制,提升已有代码的灵活性和可复用性
创建者模式包括工厂模式、抽象工厂、生成器、原形、单例这 5 类
1、使用单例模式的原因
在开发中,有时候为了节省系统资源,我们需要确保系统中的某个类只有唯一一个实例,这个实例创建后,我们无法再创建一个同类型的其他对象,所有操作都是基于这个唯一的实例进行的。为了确保对象的唯一性,我们可以通过单例模式来进行实现。
2、单例模式概述
2.1 单例模式要点
- 一个类只能有一个实例,这个类称为单例类
- 这个类的实例必须是这个类自己创建的
- 这个类必须向整个系统提供这个实例,提供全局访问的方法
2.2 单例模式实现步骤
首先,我们定义一个类 SingleBean,包含了构造方法和初始化的方法,代码如下:
public class SingleBean
public SingleBean()
public void init();
为了实现该类的唯一性,我们通过以下步骤对该类进行重构
-
首先为了防止每次使用 new 来实例化 SingleBean 都会产生一个新的对象,我们禁止类使用 new 来创建对象,将构造函数的修饰符改为 private
public class SingleBean private SingleBean() public void init();
-
外部已经无法使用 new 来创建对象了后,我们在需要在类的内部创建并保存一个唯一的实例,提供给外部进行访问。为了封装我们将成员变量修饰符设置为 private
public class SingleBean private static SingleBean singleBean = null; private SingleBean() public void init();
-
外界需要使用的时候,我们提供一个公共的静态方法对该类进行实例化
使用 public static 修饰,保证方法可以直接通过类名访问到,在方法中首先判断 singleBean 对象是否存在,如果不存在,则 new 一个新的 SingleBean 对象返回,否则直接返回已有的 singleBean 对象
public static SingleBean getInstance() if (singleBean == null) singleBean = new SingleBean(); return singleBean;
3、饿汉式和懒汉式单例
3.1 饿汉式
在定义变量的时候就实例化单例类,在类加载的时候就已经创建了对象
类在加载时,静态变量 eagerSingle 会被初始化,创建一个唯一的实例
class EagerSingle
private static final EagerSingle eagerSingle = new EagerSingle();
private EagerSingle();
public static EagerSingle getInstance()
return eagerSingle;
3.2 懒汉式
懒汉式在第一次调用单例类提供的获取实例对象的方法时,进行实例化,类加载的时候不进行实例化。为了避免多个线程同时调用,我们可以使用关键字 synchronized
进行线程锁
class LazySingle
private static LazySingle lazySingle = null;
private LazySingle();
synchronized public static LazySingle getInstance()
if(lazySingle == null)
lazySingle = new LazySingle();
return lazySingle;
增加线程锁后,多线程访问每次都需要进行判断,我们还可以继续对代码进行优化
我们不用对整个方法加锁,可以对进行实例化的代码块加锁,进行如下改进:
class LazySingle
private static LazySingle lazySingle = null;
private LazySingle();
public static LazySingle getInstance()
if(lazySingle == null)
synchronized(LazySingle.class)
lazySingle = new LazySingle();
return lazySingle;
如果对代码块进行加锁后,看似不会出现问题,但是如果多个线程同时调用 getInstance 方法,如果变量 lazySingle 对象为 null,都可以进入 if 条件内,线程依次执行代码块内容,导致多个对象的产生
所以我们还需要再进行一次判断,在加锁代码块内对变量再次进行判断。为了保证可见性,需要对变量增加 volatile
关键字,保证多个线程能够正确处理
class LazySingle
private volatile static LazySingle lazySingle = null;
private LazySingle();
public static LazySingle getInstance()
if(lazySingle == null)
synchronized(LazySingle.class)
if (lazySingle == null)
lazySingle = new LazySingle();
return lazySingle;
3.3 懒汉式与饿汉式单例比较
- 饿汉式在类加载时就进行了实例化,不用考虑多线程访问问题,确保实例唯一性。但饿汉式单例不管用不用得到都会进行实例化,始终占据内存
- 懒汉式在第一次使用时创建,延迟进行加载,为了处理多线程问题我们必须要进行双重锁定进行控制,性能会有一定影响
3.4 其它实现方式
使用静态内部类进行实现
class SingleBean
private SingleBean();
private static class SingleBeanInstance
private final static SingleBean instance = new SingleBean();
public static SingleBean getInstance()
return SingleBeanInstance.instance;
使用枚举进行实现
public enum EnumSingleBean
SINGLE_BEAN_INSTANCE;
private SingleBean singleBean = null;
private EnumSingleBean()
singleBean = new SingleBean();
public SingleBean getInstance()
return singleBean;
以上是关于设计模式 - 单例模式的主要内容,如果未能解决你的问题,请参考以下文章