单例模式
定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点
引子:读取配置文件
很多地方要用到,如果每次都new 一个对象的话,会浪费内存资源。
改装成饿汉式(饿汉式有线程并发问题,懒汉式没有)
也可以完成需求,但是节约资源了?因为只有一个地方去使用,也见不到效果
场景:需要读取配置,这个用途在开发中是很常见的。
package com.tao.YanMoDesignPattern.singleton.pattern.case1_Origin;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
* @Author Mi_Tao
* @Date 2023/7/23
* @Description
* @Version 1.0
**/
public class AppConfig {
private String parameterA;
private String parameterB;
public AppConfig(){
readConfig();
}
private void readConfig() {
Properties properties = new Properties();
InputStream in = null;
try {
in = AppConfig.class.getResourceAsStream("/Appconfig.properties");
properties.load(in);
// 把配置文件中的内容读出来设置到属性上
this.parameterA = properties.getProperty("parameterA");
this.parameterB = properties.getProperty("parameterB");
} catch (IOException e) {
System.out.println("转载配置文件出错了!");
e.printStackTrace();
}finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public String getParameterA() {
return parameterA;
}
public String getParameterB() {
return parameterB;
}
}
配置类位置
直接的做法,读取文件
package com.tao.YanMoDesignPattern.singleton.pattern.case1_Origin;
/**
* @Author Mi_Tao
* @Date 2023/7/23
* @Description
* @Version 1.0
**/
public class Client {
public static void main(String[] args) {
// 创建读取应用的配置对象
AppConfig config = new AppConfig();
String parameterA = config.getParameterA();
System.out.println("parameterA = " + parameterA);
String parameterB = config.getParameterB();
System.out.println("parameterB = " + parameterB);
}
}
这种方式:快捷。但是如果但很多的类都需要使用到这些配置,就会大量new 出重复的对象,造成资源浪费!!
解决方法:既然这些配置都是一样的,我们其实只需要一个实例就行。所以我们可以使用单例模式
而常见单例的方法也是多样的:
1、饿汉式
package com.tao.YanMoDesignPattern.singleton.pattern.case1_Origin;
/**
* 饿汉式
*
* @Author Mi_Tao
* @Date 2023/7/23
* @Description
* @Version 1.0
**/
public class HungrySingleton {
//定义一个变量来存储创建好的类实例,只能创建一次
private static HungrySingleton uniqueInstance = new HungrySingleton();
/**
* 构造私有化方法,可以再内部控制创建实例的数目
*/
private static HungrySingleton getInstance() {
// 直接使用创建好的实例
return uniqueInstance;
}
/**
* 单例可以有自己的操作
*/
public void singletonOperation(){
}
public String getSingletonData() {
return singletonData;
}
// 属性,单例可以有自己的属性
private String singletonData;
}
2、懒汉式
package com.tao.YanMoDesignPattern.singleton.pattern.case1_Origin;
/**
* 懒汉式
*
* @Author Mi_Tao
* @Date 2023/7/23
* @Description
* @Version 1.0
**/
public class LazySingleton {
//定义一个变量来存储创建好的类实例
private static LazySingleton uniqueInstance = null;
/**
* 构造私有化方法,可以再内部控制创建实例的数目
*/
private LazySingleton() {
}
/**
* 获取单例
*
* @return {@link LazySingleton}
*/
public static synchronized LazySingleton getSingleton(){
// 判断存储实例的变量是否有值
if (uniqueInstance == null){
// 如果没有,就创建一个
uniqueInstance = new LazySingleton();
}
// 否则直接返回
return uniqueInstance;
}
/**
* 单例可以有自己的操作
*/
public void singletonOperation(){
}
public String getSingletonData() {
return singletonData;
}
// 属性,单例可以有自己的属性
private String singletonData;
}
测试
package com.tao.YanMoDesignPattern.singleton.pattern.case1_Origin;
/**
* @Author Mi_Tao
* @Date 2023/7/23
* @Description
* @Version 1.0
**/
public class ClientV2_Hungry {
public static void main(String[] args) {
// 创建读取应用的配置对象
AppConfigV2_Hungry config = AppConfigV2_Hungry.getInstance();
String parameterA = config.getParameterA();
System.out.println("parameterA = " + parameterA);
String parameterB = config.getParameterB();
System.out.println("parameterB = " + parameterB);
}
}
懒汉式。从名字不难理解。在需要使用的使用才会去创建,而不去创建就不去创建。但是会有并发问题。
并发问题的解决,我们可以使用双检锁来升级一下,解决问题
package com.tao.YanMoDesignPattern.singleton.pattern.case1_Origin;
/**
* 懒汉式
*
* @Author Mi_Tao
* @Date 2023/7/23
* @Description 考虑并发时候的单例 双检锁
* @Version 1.0
**/
public class LazySingleton_current {
//定义一个变量来存储创建好的类实例 内存屏障去掉,直接访问共享内存
private volatile static LazySingleton_current uniqueInstance = null;
/**
* 构造私有化方法,可以再内部控制创建实例的数目
*/
private LazySingleton_current() {
}
/**
* 获取单例
*
* @return {@link LazySingleton_current}
*/
public static synchronized LazySingleton_current getSingleton(){
// 判断存储实例的变量是否有值
if (uniqueInstance == null){
synchronized (LazySingleton_current.class){
if (uniqueInstance == null){
// 如果没有,就创建一个
uniqueInstance = new LazySingleton_current();
}
}
}
// 否则直接返回
return uniqueInstance;
}
/**
* 单例可以有自己的操作
*/
public void singletonOperation(){
}
public String getSingletonData() {
return singletonData;
}
// 属性,单例可以有自己的属性
private String singletonData;
}
tips
使用枚举类也可以实现单例
本文参考:《研磨设计模式》