java设计模式--单例模式(饿汉懒汉双重检索)-附代码
Posted 言之有李LAX
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java设计模式--单例模式(饿汉懒汉双重检索)-附代码相关的知识,希望对你有一定的参考价值。
目录(其他设计模式请移步该文章进行查看,持续更新,所有的代码都在码云上,可自行下载):
java常用设计模式以及场景使用及代码实现-系列_言之有李LAX的博客-CSDN博客
【释义】
单例模式 顾名思义就是任何适合都只能有一个实例。且该类需自行创建这个实例,并对其他的类提供调用这一实例的方法。是java中常用的设计模式。
单例在实现方式上主要有:饿汉模式、懒汉模式(线程不安全)、懒汉模式(线程安全)、双重检索模式(推荐使用)以及其他不列举。
【场景】
单例在项目中的使用场景一般是针对频繁创建和销毁的对象,需根据业务自行判断。比如Spring中的bean创建、数据库的连接池等。优点是保证了对象的实例有且只有一个,节省资源,获取速度较快。缺点自然也有,就是对于经常变化的对象不适用。
【实现方式】
tips: 四种模式中推荐使用第四种,第一种其次,但是需要从1-4进行观看更容易理解!
1. 饿汉模式
【释义】-就是比较饥饿,在类实例化的时候就要创建实例,无论后面是否会真正用到。
【优点】-线程安全,在类加载的同时已经创建好一个静态对象,调用的时候反应速度快
【缺点】-对象提前创建,如果后续业务没有使用到该实例,就会造成内存浪费,虽然现在的服务内存都比较大,但是如果项目中存在很多饿汉单例,也不容小觑。相当于用空间换时间。
public class EhSingleton
/**
* 私有化该实例,且静态变量在类加载的时候就会初始化,所以是线程安全的
*/
private static final EhSingleton ehSingleton = new EhSingleton();
/**
* 私有构造方法
*/
private EhSingleton()
/**
* 该类对外提供的唯一获取实例方法(静态工厂方法)
*
* @return
*/
public static EhSingleton getInstance()
return ehSingleton;
/**
* 运行main方法,可以在控制台看到三条打印的对象实际是同一个
* 实现了单例保证系统中只有一个实例的结果
*/
public static void main(String[] args)
EhSingleton ehSingleton = EhSingleton.getInstance();
System.out.println(ehSingleton);
EhSingleton ehSingleton1 = EhSingleton.getInstance();
System.out.println(ehSingleton1);
EhSingleton ehSingleton2 = EhSingleton.getInstance();
System.out.println(ehSingleton2);
运行该类中的main方法,可以在控制台看到三条打印的对象实际是同一个, 实现了单例保证系统中只有一个实例的结果
2.懒汉模式(非线程安全)
【释义】-就是比较懒,只有在真正被调用的时候才会去检查有没有实例,如果有则直接返回,如果没有则会新建,然后返回。
【优点】-有延迟加载的效果,但是只能在单线程环境下使用
【缺点】-如果在多线程的环境下,两个线程同时进入到了(lhSingleton == null) 的判断中,则两个线程都会得到lhSingleton == null, 从而这两个线程都会进入到if语句中进行创建对象,便会产生多个实例。
public class LhUnsafeSingleton
/**
* 私有化实例
*/
private static LhUnsafeSingleton lhUnsafeSingleton;
/**
* 私有构造方法
*/
private LhUnsafeSingleton()
/**
* 该类对外提供的唯一获取实例方法(静态工厂方法)
*
* @return
*/
public static LhUnsafeSingleton getInstance()
if (lhUnsafeSingleton == null)
lhUnsafeSingleton = new LhUnsafeSingleton();
return lhUnsafeSingleton;
public static void main(String[] args)
//非线程安全,不好复现 可以通过写多线程同时请求LhUnsafeSingleton.getInstance() 进行模拟,并打印出来返回的结果
//如果返回的结果有不同的,则表示懒汉模式在多线程下容易出问题
3.懒汉模式(线程安全)
【释义】-就是比较懒,只有在真正被调用的时候才会去检查有没有实例,如果有则直接返回,如果没有则会新建,然后返回, 同时对getInstance()方法添加synchronized关键字
【优点】-解决了懒汉模式线程不安全的问题
【缺点】-每次调用都加锁同步执行,对象返回的效率低,不推荐使用
public class LhSafeSingleton
/**
* 私有化实例
*/
private static LhSafeSingleton lhSafeSingleton;
/**
* 私有构造方法
*/
private LhSafeSingleton()
/**
* 该类对外提供的唯一获取实例方法(静态工厂方法) 该方法使用synchronized加锁,来保证线程安全性
* synchronized作用在方法上,如果有别的线程来访问该方法,需要先获取锁,查看对象是否可用
*
* @return
*/
public static synchronized LhSafeSingleton getInstance()
if (lhSafeSingleton == null)
lhSafeSingleton = new LhSafeSingleton();
return lhSafeSingleton;
4. 双重检索模式
进入方法先检查实例是否存在,存在则直接返回,如果不存在才会进入同步代码, 此时再次检查是否存在实例,如果不存在,则在同步状态下进行实例创建,既保证了懒加载,又保证了高性能。 项目中常用此种单例模式。
public class DoubleCheckSingleton
/**
* 私有化实例
*/
private static DoubleCheckSingleton doubleCheckSingleton;
/**
* 私有构造方法
*/
private DoubleCheckSingleton()
/**
* 该类对外提供的唯一获取实例方法(静态工厂方法)
*
* @return
*/
public static DoubleCheckSingleton getInstance()
//首先判断是否为空,防止已经被实例化后再次加锁,导致重复操作
if (doubleCheckSingleton == null)
//加锁
synchronized (DoubleCheckSingleton.class)
//此时已经加锁,同一时间只有一个线程会进入此步骤,所以不会出现懒汉模式时的问题
if (doubleCheckSingleton == null)
doubleCheckSingleton = new DoubleCheckSingleton();
return doubleCheckSingleton;
当然还有其他方式比如枚举等模式,但是基本不会用到,就不一一列举了,感兴趣的可以去自行搜一下。
以上是关于java设计模式--单例模式(饿汉懒汉双重检索)-附代码的主要内容,如果未能解决你的问题,请参考以下文章