单例模式那件小事,看了你不会后悔

  欢迎关注下文:单例模式不是一件小事,快回来看看。

  单例模式是一种创建型模式,某个类采用单例模式,则在这个类被创建后,只可能产生一个实例供外部访问,并且提供一个全局的访问点。

  主要思想如下:

  • 将构造方法私有化( 声明为 private ),这样外界不能随意 new 出新的实例对象;
  • 声明一个私有的静态的实例对象,供外界使用;
  • 提供一个公开的方法,让外界获得该类的实例对象。

  具体实现代码如下:

  代码①

public class Singleton {
    /**
     * 构造方法私有化
     */
    private Singleton() {
    }

    /**
     * 定义一个私有的静态的实例
     */
    private static Singleton sSingleton = new Singleton();

    /**
     * 提供静态的方法给外界访问
     *
     * @return
     */
    public static Singleton getInstance() {
        return sSingleton;
    }
}

  上面代码①便是传说中的饿汉式单例模式。饿汉式有一个缺点是在类一加载的时候,就实例化,提前占用了系统资源。为此,我们可以稍微优化一下:

  代码②

public class Singleton {
    private Singleton() {
    }
    private static Singleton sSingleton;

    public static Singleton getInstance() {
        if (sSingleton == null) {
            sSingleton = new Singleton();
        }
        return sSingleton;
    }
}

  这样便成了“懒人”的使用方式,在需要使用该类的时候,再实例化,解决了上面所说的缺点,称为“懒汉式”。不过,这样存在线程安全问题,可能会造成重复创建对象,与单例模式的思想相悖。所以我们需要改进该方法:

  代码③

public class Singleton {
    private Singleton() {
    }

    private static Singleton sSingleton;

    public synchronized static Singleton getInstance() {
        if (sSingleton == null) {
            sSingleton = new Singleton();
        }
        return sSingleton;
    }
}

  OK,给方法加上同步,就可以避免并发环境下的问题了。这就是传说中的懒汉式单例模式。同步该方法后,可以避免多个线程重复创建对象,因为每次只能有一个线程去访问该方法,其他线程必须等待,假设现在实例对象已经初始化了,不需要再创建了,上面的方式就显得效率低了。所以,该方法可以继续做如下优化:

  代码④

public class Singleton {
    private Singleton() {
    }

    /**
     * volatile is since JDK5
     */
    private static volatile Singleton sSingleton;

    public static Singleton getInstance() {
        if (sSingleton == null) {
            synchronized (Singleton.class) {
                // 未初始化,则初始instance变量
                if (sSingleton == null) {
                    sSingleton = new Singleton();
                }
            }
        }
        return sSingleton;
    }
}

  上面的代码,不再同步方法了,采用双重判断,同步代码块,这样大大地提高了懒汉式单例模式的效率,特别要注意的是:声明对象的时候,使用了一个关键字:volatile,该关键字是从JDK1.5之后新加入的,不加该关键字,编译器可能会失去大量优化的机会或者可能会在编译时出现一些不可预知的错误。

  此外,还有一种静态内部类实现单例模式的方法,如下:

  代码⑤

public class Singleton {

    private Singleton () {
    }

    private static class InnerClassSingleton {     private final static Singleton sSingleton = new Singleton();
    }

    public static Singleton getInstance() {
        return InnerClassSingleton.sSingleton;
    }
}

  该方法简单明了,不需要同步,代码也不是很复杂。上面代码中静态内部类 InnerClassSingleton 在 Singleton 类加载的时候并不会加载,下面修改代码④,进行验证:

public class Singleton {

    public Singleton () {
    }

    private static class InnerClassSingleton {
        static{
            System.out.println("-----InnerClassSingleton 已经加载了....");
        }
        private final static Singleton sSingleton = new Singleton();
    }

    public static Singleton getInstance() {
        System.out.println(InnerClassSingleton.sSingleton.hashCode());
        return InnerClassSingleton.sSingleton;
    }
}

  注意特意将 Singleton 的构造方法公开化了,再编写一个测试类:

public class Test {
    public static void main(String[] args) {
        new Singleton();
        System.out.println(Singleton.class);
    }
}

  运行代码,打印结果只有一行:

class com.examle.joy.Singleton

  这说明静态内部类并没有加载,再次修改测试类:

public class Test {
    public static void main(String[] args) {
        System.out.println(Singleton.getInstance());
        System.out.println(Singleton.getInstance());
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Singleton.getInstance());
            }
        }).start();
    }
}

  这次的运行结果如下:

-----InnerClassSingleton 已经加载了...
[email protected]
[email protected]
[email protected]

  上面的打印结果是符合我们预期的。

  最后总结一下:代码⑤是单例模式最佳的实现方法,在实际开发中,饿汉式代码简洁,容易理解,用的比较多,如果不涉及并发操作的话,也可以使用懒汉式代码②,设计到多线程并发问题,用懒汉式的话,需要使用代码④,代码⑤显得很优雅,是个人比较推荐的一种方式。最后值得一提的是,所有的单例模式,都只能用在非反射场景中,因为利用反射,成员变量或者方法即便声明为 private,也可以被外部访问。

时间: 2024-10-05 14:15:39

单例模式那件小事,看了你不会后悔的相关文章

单例模式那件小事,看了你不会后悔(转)

原文地址:http://www.cnblogs.com/joy99/p/6262465.html 单例模式是一种创建型模式,某个类采用单例模式,则在这个类被创建后,只可能产生一个实例供外部访问,并且提供一个全局的访问点. 主要思想如下: 将构造方法私有化( 声明为 private ),这样外界不能随意 new 出新的实例对象: 声明一个私有的静态的实例对象,供外界使用: 提供一个公开的方法,让外界获得该类的实例对象. 具体实现代码如下: 代码① public class Singleton {

单例模式不是一件小事,快回来看看

上次写了一篇<单例模式那件小事,看了你不会后悔>的文章,总结了常用的单例模式的实现.本文是上文的延续,单例模式绝不是一件小事,想弄清楚,真不是那么简单的.上文提到了常用的三种单例模式的实现方法:饿汉式(除了提前占用资源,没毛病.),懒汉式(DCL优化过后,没毛病?),静态内部类式(优雅的方法,没毛病.).文末最后还提到,反射会破坏单例. 本文继续,双重检查锁定优化过后的懒汉式,真的没毛病吗?其实不是,这里涉及到java编译器编译时的一些细节,对象初始化时的写操作与写入 sSingleton 字

一件小事引发纯属自我的调节,于是有了这篇随笔

只能说今天运气差到极点了吧,也是因此,晚上十点半的现在的我也只能在word上把随笔先写好,等网好了再发出去. 原定的计划是先把周末的网页先写得差不多再直接睡觉的,结果先是PS运行不了,再是快把PS安装包下载完的时候网络又出问题了.弄来弄去结果就把心态搞炸了.在写这篇随笔的时候网络还是忽好忽坏,PS还是没有下下来.这么早就睡觉肯定是睡不着的,也是想借写随笔的过程来平复下烦躁的心情吧. 学习日近尾声,老师的节奏加快的同时,自己的节奏越发受到外界因素的影响,许久未曾谋面的烦躁又开始活跃起来了.而且由于

·记2014.5.16的一件小事

周五,上班. 由于张工有事请假回家,我和曹工留下一起做接口. 我主要负责接口上层交互部分.期间测试code的时候.发现自己图快点做好.忽略了基本的接口数据类型的定义.有在前一晚上图快,粘贴复制没有检查数据类型.导致了第二天调试付出了惨痛的代价. 目前,我是能抓住大方向的,但是在小的细节不重视.没有在这上面摘过跟头.这次早期及时暴露出来是个好事. 之前看过很多细节决定人生的故事,总会幻想自己也能成为一个这样的人.但是实现却给我当头一棒.梦想没有经过现实的打磨只会成为一个幻想,别人口里的一个笑谈.星

做成一件小事

课基本结束了,调整调整,开始做科研. 最大的感触,做事情不能没有节奏感.什么是节奏感?有起点,有节点:顺利的时候能按照一个计划先前走,遇到困难,能迂回.持续.找办法,继续前进.经常可能遇到的状态是,遇到点困难,停滞不前,深深的自责,然后,然后放弃.无果而终,无疾而终.留下一个心理阴影.我不要这样的节奏. 我要坚持做成一件小事.这件小事,可能看上去是很小,就是实现一个自动字段切割的方法.这是一个基础,希望把前期的工作实物化,有一个载体.在这个基础上,再进一步,把自己的工作延续下去.

K8s 从懵圈到熟练 – 镜像拉取这件小事

作者 | 声东 阿里云售后技术专家 导读:相比 K8s 集群的其他功能,私有镜像的自动拉取,看起来可能是比较简单的.而镜像拉取失败,大多数情况下都和权限有关.所以,在处理相关问题的时候,我们往往会轻松的说:这问题很简单,肯定是权限问题.但实际的情况是,我们经常为一个问题,花了多个人的时间却找不到原因.这主要还是我们对镜像拉取,特别是私有镜像自动拉取的原理理解不深.这篇文章,作者将带领大家讨论下相关原理. 顺序上来说,私有镜像自动拉取会首先通过阿里云 Acr credential helper 组

《一件小事.呐喊》--鲁迅 词语解释

<一件小事> -出自鲁迅小说集<呐喊>. 伊:彼,他,她. 装腔作势:故意装出一种腔调,做出一种姿势,用来比喻故意做作. 威压:表现出使人敬畏的气魄.威:表现出来使人敬畏的气魄:威力,威风,权威:凭借力量或势力:威胁,威逼. 压:从上面加力:压住:用威力制服.镇服:镇压,压服,压迫:逼近:大兵压境.

【转载】deep learning这件小事……

deep learning这件小事…… (2013-03-30 16:35:17) 转载▼ 标签: deep-learning 机器学习 深度神经网络 监督学习 非监督学习 分类: 机器学习 「深度神经网络」(deep neural network)具体是怎样工作的? 多层的好处是可以用较少的参数表示复杂的函数. 在监督学习中,以前的多层神经网络的问题是容易陷入局部极值点.如果训练样本足够充分覆盖未来的样本,那么学到的多层权重可以很好的用来预测新的测试样本.但是很多任务难以得到足够多的标记样本,

响应式布局这件小事

讲到响应式布局, 相信大家都有一定的了解,响应式布局是今年很流行的一个设计理念,随着移动互联网的盛行,为解决如今各式各样的浏览器分辨率以及不同移动设备的显示效果, 设计师提出了响应式布局的设计方案.今天就和大家来讲讲响应式布局这件小事,包含什么是响应式布局.响应式布局的优点和缺点以及响应式布局该怎么设计(通 过CSS3 Media Query实现响应布局). 一.什么是响应式布局? 响应式布局是Ethan Marcotte在2010年5月份提出的一个概念,简而言之,就是一个网站能够兼容多个终端—