目录:

  1、单例模式(Singleton Pattern)
  2、概念
  3、饿汉式:不是延迟加载,加载类的时候直接初始化
  4、懒汉式:延迟加载,首次需要使用的时候在实例化,需要考虑线程安全
  5、静态内部类实现
  6、枚举实现

1、单例模式(Singleton Pattern)   <==返回目录

    确保一个类只有一个实例,并提供一个全局访问点。

2、概念   <==返回目录

下面的内容转载自博客: 23种设计模式之单例模式 ( https://chenmingyu.top/design-singleton/)

  单例模式:单例模式属于创建型模式;

  定义:确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。单例模式目的是保证在程序运行期间一个类只有一个实例,并提供一个全局访问点,无论什么情况下,只会生成一个实例,免去繁琐的创建销毁对象的过程。

  优点:

)减少了内存开支,避免频繁地创建、销毁对象;
)避免对资源的多重占用;

  缺点:

没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化

  如何设计单例模式

    如何设计单例模式其实很简单,只需要考虑一个问题,实例是否可以保证是全局唯一。关于实例是否保证是全局唯一延伸出的问题:

是否线程安全,不安全肯定就不能保证全局只有一个实例
是否支持序列化,支持序列化的类,被反序列化之后肯定就不是全局唯一了
是否支持反射,支持反射肯定也不是全局唯一的
是否可以被克隆,这个也不能保证全局唯一

 

  所以设计一个安全的单例需要考虑的问题还是很多的。针对上述问题常见的解决办法:

保证线程安全,使用volatile+synchronized实现
防止序列化攻击,重写readResolve方法
防止反射,常用的方案是在单例类里增加一个boolean类型的flag标识,在实例化的时候先判断flag标识
防止克隆,重写clone()方法

  

  实现一个最简单的单例就需要考虑到以上的所有问题,这个时候什么有用的方法还没写那,代码就已经很多了,那有没有简单的办法既满足上述条件,代码又简洁那,那肯定有,使用枚举实现单例。

  常见的单例模式实现

常见的单例模式实现方案大概有五种,懒汉模式,饿汉模式,双重检查方式实现,静态内部类实现,枚举实现

  分个类:

是否支持延迟加载,分为懒汉模式和饿汉模式
线程安全设计了双重检查模式实现,静态内部类实现方式
不支持序列化,反射,克隆,枚举实现方式

  其中懒汉模式,饿汉模式,双重检查方式实现,静态内部类的实现方式都可以概括为以下两步:

  1.构造函数私有化,保证在外部无法new对象
  2.提供一个static方法获取当前实例(不同方案,实现不同)

  

  当然枚举的实现方式最简单,也最安全的,所以推荐使用枚举实现,其次推荐使用静态内部类方式实现。

3、饿汉式:不是延迟加载,加载类的时候直接初始化   <==返回目录

优点:线程安全,代码简单。

缺点:不是延迟加载,如果你用不到这个类,它也会实例化,还有一个问题就是如果这个实例依赖外部一些配置文件,参数什么的,在实例化之前就要获取到,否则就实例化异常

/**
* 单例模式:饿汉式
* @author oy
* @date 2019年9月3日 下午11:13:49
*/
public class Singleton { private static Singleton singleton = new Singleton(); private Singleton() {
} public static Singleton getInstance(){
return singleton;
}
}

4、懒汉式:延迟加载,首次需要使用的时候在实例化,需要考虑线程安全   <==返回目录

  线程不安全的实现方式:

/**
* 单例模式:懒汉式,线程不安全
* @author oy
* @date 2019年9月3日 下午11:15:47*/
public class Singleton {
private static Singleton singleton;
private Singleton() {}
public static Singleton getInstance(){
if(null == singleton){
singleton = new Singleton();
}
return singleton;
}
}

  线程安全的实现方式:双重检查(DCL:Double Check Lock)

/**
* 单例模式:双重检查(DCL:Double Check Lock)
* @author oy
* @date 2019年9月3日 下午11:17:06
*/
public class Singleton {
private static volatile Singleton singleton;
private Singleton() {} public static Singleton getInstance(){
if(null == singleton){
synchronized (Singleton.class){
if(null == singleton){
singleton = new Singleton();
}
}
}
return singleton;
}
}

  面试题:为什么使用volatile修饰singleton变量?

1.说的volatile,首先肯定回答volatile的可见性
2.防止重排序优化,如果不用volatile修饰,多线程的情况下,可能会出现线程A进入synchronized代码块,
执行new Singleton();,首先给singleton分配内存,但是还没有初始化变量,
这时候线程B进入getInstance方法,进行第一个判断,此时singleton已经不为空,
直接返回singleton,然后肯定报错。使用volatile修饰之后禁止jvm重排序优化,所以就不会出现上面的问题

5、静态内部类实现   <==返回目录

  使用静态内部类实现也是延迟加载,利用静态内部类去实现线程安全,只有在第一次调用getInstance方法的时候才会去加载SingletonHolder,初始化SINGLETON

/**
* 单例模式:静态内部类实现
* @author oy
* @date 2019年9月3日 下午11:17:06
*/
public class Singleton { private Singleton() {} public static Singleton getInstance() {
return SingletonHolder.SINGLETON;
} private static class SingletonHolder {
private static final Singleton SINGLETON = new Singleton();
}
}

6、枚举实现   <==返回目录

  枚举实现代码更简洁,线程安全,并且保证枚举不会被反序列化,反射和克隆

/**
* 单例模式:枚举实现
* @author oy
* @date 2019年9月3日 下午11:17:06
*/
public enum Singleton { SINGLETON; /**
* 提供的方法
*/
public void method() {
System.out.println("枚举实现");
}
}

最新文章

  1. codeforces 733D
  2. Firemonkey Bitmap 设定像素颜色 Pixel
  3. 结果集(result set)解释与用法
  4. spring 标注 详解
  5. The mmap module
  6. iwebshop中的增删改查
  7. Python常用的第三方库
  8. Linq GroupBy
  9. Java对字符串加密并返回星号※
  10. MQ &amp; RPC 消息队列与RPC的区别与使用场景
  11. Impl模式实现之注意内联
  12. bzoj4198 荷马史诗
  13. 200. Orchard学习 目录
  14. BZOJ.2095.[POI2010]Bridges(最大流ISAP 二分 欧拉回路)
  15. js 过滤日期格式
  16. 【Python】xpath-1
  17. 全面了解HTTP请求方法说明
  18. [Unity3D] 01 - Try Unity3D
  19. 数据库之mongodb
  20. jsp页面都放在web-inf下面说是要防止用户直接访问jsp页面,为么不能直接访问jsp

热门文章

  1. Swool的安装与使用
  2. 看某视频开始做LINUX笔记的第一天
  3. 第四周课程总结&amp;试验报告2
  4. [转帖]英特尔的 ME 或侵犯 Minix3 的自由软件许可证
  5. oracle数据库表恢复到特定时间点
  6. .Net Core Web应用加载读取Json配置文件
  7. AppCan IDE中有时格式化代码后,代码就运行不了了。
  8. file_put_contents实现内容追加
  9. ListVie的用法
  10. O007、KVM 存储虚拟化