版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jaune161/article/details/87880520
使用场景:需要在系统中确保类只有一个实例,一般这种类的创建都会比较占用系统资源。比如配置文件初始化,将配置文件中的数据读取到类中,通常需要耗费一定的系统资源,而且配置文件中的内容一般都是不变的,修改完配置文件一般都会要求重启系统。所以这种类最适合使用单例模式
简单单例模式
实现
/**
* 简单的单例模式
*
* @author 大扑棱蛾子
* @since 1.0.0
*/
public class SimpleConfigUtils {
private static org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(SimpleConfigUtils.class);
private static SimpleConfigUtils instance = null;
private Map<String, String> props = new HashMap<>();
/**
* 单例的目的就是为了控制实例数量,所以构造函数一定要私有化,这样才能被其他使用者不能够随便实例化对象。
*/
private SimpleConfigUtils() {
this.readFromConfigFile();
logger.info("对象实例化完成。");
}
/**
* 获取配置实例
* @return 配置实例
*/
public static SimpleConfigUtils getInstance() {
if (instance == null) {
instance = new SimpleConfigUtils();
}
return instance;
}
/**
* 根据配置项的名称获取配置项的值
* @param propName 配置项的名称
* @return 配置项的值
*/
public String getPropertyValue(String propName) {
return this.props.get(propName);
}
private void readFromConfigFile() {
logger.info("假装从配置文件中读取了配置");
props.put("application.name", "DesignPattern");
props.put("application.type", "SpringBoot");
}
}
实现单例模式要注意以下要点
- 构造函数私有化
- 提供一个静态方法来获取对象
- 对象的实例保存在静态变量中。获取实例的时候要验证变量是否被初始化。
测试
public class SimpleConfigUtilsTest {
private static Logger logger = LoggerFactory.getLogger(SimpleConfigUtilsTest.class);
@Test
public void test() {
SimpleConfigUtils configUtils = SimpleConfigUtils.getInstance();
String applicationName = configUtils.getPropertyValue("application.name");
logger.info("application.name: {}", applicationName);
SimpleConfigUtils configUtils2 = SimpleConfigUtils.getInstance();
String applicationType = configUtils2.getPropertyValue("application.type");
logger.info("application.type: {}", applicationType);
}
}
控制台输出
19-02-19 17:21:40 INFO com.codestd.singleton.SimpleConfigUtils - 假装从配置文件中读取了配置
19-02-19 17:21:40 INFO com.codestd.singleton.SimpleConfigUtils - 对象实例化完成。
19-02-19 17:21:40 INFO com.codestd.singleton.SimpleConfigUtilsTest - application.name: DesignPattern
19-02-19 17:21:40 INFO com.codestd.singleton.SimpleConfigUtilsTest - application.type: SpringBoot
从控制台可以看出类只被实例化了一次。
问题
下面我们模拟多线程环境再进行一次测试。
public class SimpleConfigUtilsTest {
private static Logger logger = LoggerFactory.getLogger(SimpleConfigUtilsTest.class);
private CountDownLatch countDownLatch = new CountDownLatch(4);
@Test
public void testMultiThreading() throws InterruptedException {
for (int i = 0; i < 4; i++) {
new Thread(() -> {
SimpleConfigUtils configUtils = SimpleConfigUtils.getInstance();
String applicationName = configUtils.getPropertyValue("application.name");
String applicationType = configUtils.getPropertyValue("application.type");
logger.info("{} - application.name: {}", Thread.currentThread().getName(), applicationName);
logger.info("{} - application.type: {}", Thread.currentThread().getName(), applicationType);
countDownLatch.countDown();
}).start();
}
countDownLatch.await();
}
}
控制台打印
19-02-19 18:07:53 INFO com.codestd.singleton.SimpleConfigUtils - 假装从配置文件中读取了配置
19-02-19 18:07:53 INFO com.codestd.singleton.SimpleConfigUtils - 假装从配置文件中读取了配置
19-02-19 18:07:53 INFO com.codestd.singleton.SimpleConfigUtils - 对象实例化完成。
19-02-19 18:07:53 INFO com.codestd.singleton.SimpleConfigUtils - 假装从配置文件中读取了配置
19-02-19 18:07:53 INFO com.codestd.singleton.SimpleConfigUtils - 对象实例化完成。
19-02-19 18:07:53 INFO com.codestd.singleton.SimpleConfigUtils - 假装从配置文件中读取了配置
19-02-19 18:07:53 INFO com.codestd.singleton.SimpleConfigUtils - 对象实例化完成。
19-02-19 18:07:53 INFO com.codestd.singleton.SimpleConfigUtils - 对象实例化完成。
19-02-19 18:07:53 INFO com.codestd.singleton.SimpleConfigUtilsTest - Thread-0 - application.name: DesignPattern
19-02-19 18:07:53 INFO com.codestd.singleton.SimpleConfigUtilsTest - Thread-1 - application.name: DesignPattern
19-02-19 18:07:53 INFO com.codestd.singleton.SimpleConfigUtilsTest - Thread-1 - application.type: SpringBoot
19-02-19 18:07:53 INFO com.codestd.singleton.SimpleConfigUtilsTest - Thread-3 - application.name: DesignPattern
19-02-19 18:07:53 INFO com.codestd.singleton.SimpleConfigUtilsTest - Thread-2 - application.name: DesignPattern
19-02-19 18:07:53 INFO com.codestd.singleton.SimpleConfigUtilsTest - Thread-2 - application.type: SpringBoot
19-02-19 18:07:53 INFO com.codestd.singleton.SimpleConfigUtilsTest - Thread-3 - application.type: SpringBoot
19-02-19 18:07:53 INFO com.codestd.singleton.SimpleConfigUtilsTest - Thread-0 - application.type: SpringBoot
在多线程环境下,这种方式居然失效了。我们在后面的文章中分析如何保证在多线程环境下,能够只有一个实例。也就是单例模式在多线程环境有效。