目录(其他设计模式请移步该文章进行查看,持续更新,所有的代码都在码云上,可自行下载):
java常用设计模式以及场景使用及代码实现-系列_言之有李LAX的博客-CSDN博客
单例模式 顾名思义就是任何适合都只能有一个实例。且该类需自行创建这个实例,并对其他的类提供调用这一实例的方法。是java中常用的设计模式。
单例在实现方式上主要有:饿汉模式、懒汉模式(线程不安全)、懒汉模式(线程安全)、双重检索模式(推荐使用)以及其他不列举。
单例在项目中的使用场景一般是针对频繁创建和销毁的对象,需根据业务自行判断。比如Spring中的bean创建、数据库的连接池等。优点是保证了对象的实例有且只有一个,节省资源,获取速度较快。缺点自然也有,就是对于经常变化的对象不适用。
tips: 四种模式中推荐使用第四种,第一种其次,但是需要从1-4进行观看更容易理解!
【释义】-就是比较饥饿,在类实例化的时候就要创建实例,无论后面是否会真正用到。
【优点】-线程安全,在类加载的同时已经创建好一个静态对象,调用的时候反应速度快
【缺点】-对象提前创建,如果后续业务没有使用到该实例,就会造成内存浪费,虽然现在的服务内存都比较大,但是如果项目中存在很多饿汉单例,也不容小觑。相当于用空间换时间。
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方法,可以在控制台看到三条打印的对象实际是同一个, 实现了单例保证系统中只有一个实例的结果
【释义】-就是比较懒,只有在真正被调用的时候才会去检查有没有实例,如果有则直接返回,如果没有则会新建,然后返回。
【优点】-有延迟加载的效果,但是只能在单线程环境下使用
【缺点】-如果在多线程的环境下,两个线程同时进入到了(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() 进行模拟,并打印出来返回的结果
//如果返回的结果有不同的,则表示懒汉模式在多线程下容易出问题
}
}
【释义】-就是比较懒,只有在真正被调用的时候才会去检查有没有实例,如果有则直接返回,如果没有则会新建,然后返回, 同时对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;
}
}
进入方法先检查实例是否存在,存在则直接返回,如果不存在才会进入同步代码, 此时再次检查是否存在实例,如果不存在,则在同步状态下进行实例创建,既保证了懒加载,又保证了高性能。 项目中常用此种单例模式。
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;
}
}
当然还有其他方式比如枚举等模式,但是基本不会用到,就不一一列举了,感兴趣的可以去自行搜一下。