首页 > 其他 > 详细

设计模式之单例模式

时间:2020-05-28 19:16:01      阅读:43      评论:0      收藏:0      [点我收藏+]

     好久没写过博客了,最近准备把自己对设计模式的理解写下来,既是作为分享也是为了记录。这一篇我们来一块聊聊单例模式。

单例模式的核心点就是只创建一个实例,我们先看下如何实现的。

package com.guantong.seeing.screening.common;

/**
 * 单例模式
 * cxx
 */
public class Singleton {
    /**
     * 私有静态实例
     */
    private static Singleton instance = null;

    /**
     * 私有构造方法,防止被实例化
     */
    private Singleton() {
    }

    /**
     * 创建唯一实例
     * @return
     */
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }

}

   这样就实现了最初版本的单例模式,我们来写个测试类,验证下是否是单例。

package com.guantong.seeing.screening.common;

import org.junit.Test;

public class SingletonTest {

    @Test
    public void testGetInstance()   {
        Singleton result = Singleton.getInstance();
        Singleton result1 = Singleton.getInstance();
        System.out.println(result);
        System.out.println(result1);
    }
}

输入结果:

技术分享图片

 

 可以看到,内存地址都是一致的,证明是一个单例模式

        但是这是单线程的单例模式,如果处于高并发的环境,同时有两个线程F1,F2进入到了getInstance方法,我们来写段代码看看会发生什么

  @Test
    public void testGetInstance1() throws InterruptedException {

       new Thread(() -> {
            Singleton instance = Singleton.getInstance();
            System.out.println(instance);
        }).start();

      new Thread(() -> {
            Singleton instance = Singleton.getInstance();
            System.out.println(instance);
        }).start();


    }

 

技术分享图片

 

通过跑多线程环境,我发现这个单例被破坏了。也就是说,当两个线程同时 创建实例的时候,单例就被破坏了,我们可以对这个单例模式加个锁

 /**
     * 创建唯一实例
     * @return
     */
    public static  synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }

但是这样性能不好,我们可以把锁的范围调小点。


/**
* 创建唯一实例
*
* @return
*/
public static Singleton getInstance() {
if (instance == null) {
synchronized (instance) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}

 

这样解决了我们上面的问题,但是又有一个新问题浮现了。

由于jvm的对象创建机制是  分配地址和初始化是随机顺序的。所以当线程F1被jvm分配内存之后,并且未初始化Singleton之间,F2请求尽来了,这时候F2通过代码判断已经有了实例了,便直接拿去用了,

问题就出现了,F2拿去的可能是空的实例,会导致空指针等问题。

这时候我们就需要 volatile锁了

package com.guantong.seeing.screening.common;

/**
 * 单例模式
 * cxx
 */
public class Singleton {
    /**
     * 私有静态实例
     */
    private static volatile Singleton instance = null;

    /**
     * 私有构造方法,防止被实例化
     */
    private Singleton() {
    }

    /**
     * 创建唯一实例
     *
     * @return
     */
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (instance) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }

}

值得注意的是,volatile控制的并不是jvm分配内存地址和初始化的顺序,而是在这两步没完成前不会去调用  if (instance == null) 这一步

 

设计模式之单例模式

原文:https://www.cnblogs.com/blogsofmy/p/12982695.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!