设计模式之单例模式--简单单例模式(1)

使用场景:需要在系统中确保类只有一个实例,一般这种类的创建都会比较占用系统资源。比如配置文件初始化,将配置文件中的数据读取到类中,通常需要耗费一定的系统资源,而且配置文件中的内容一般都是不变的,修改完配置文件一般都会要求重启系统。所以这种类最适合使用单例模式

简单单例模式

实现

/**
 * 简单的单例模式
 *
 * @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

在多线程环境下,这种方式居然失效了。我们在后面的文章中分析如何保证在多线程环境下,能够只有一个实例。也就是单例模式在多线程环境有效。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大扑棱蛾子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值