单例模式(下)---聊一聊单例模式的几种写法

在上一篇文章 单例模式(上)—-如何优雅地保证线程安全问题中,我们采取了懒汉式写法来写我们的单例模式,并且重点讲解了懒汉式中线程安全的问题。这篇我们来讲讲单例模式中的其他几种写法。

上篇文章中,方法和变量的声明都忘了加上“static”的声明,这里提醒一下。

懒汉式

懒汉式在上节我们已经讲过了,直接给出代码:

public class Singleton {
    private static volatile Singleton instance = null;
    private Singleton(){};

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class){
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

懒汉式这种方式需要我们来自己加锁,保证线程安全的问题。

不过就算我们保证了线程安全,这种写法还是无法保证存在唯一一个对象实例。因为别人还是可以通过反射的方式来创建一个新的对象。我写个示例:

public class Singleton {
    public static void main(String[] args) throws Exception{
        //获得构造器
        Constructor<Singleton> c = Singleton.class.getDeclaredConstructor();
        //把构造器设置为可访问
        c.setAccessible(true);
        //创建两个实例对象
        Singleton s1 = c.newInstance();
        Singleton s2 = c.newInstance();
        //比较下两个实例是否相等
        System.out.println(s1 == s2);
    }
}

打印结果:false。

所以懒汉式这种方式还是存在一些缺点的。

饿汉式

所谓饿汉式,就是一开始把对象实例创建出来,而不是等getInstance这个方法被调用才来创建对象。代码如下:

public class Singleton2 {
    private static Singleton2 instance = new Singleton2();
    //私有构造器
    private Singleton2(){};

    public static Singleton2 getInstance() {
        return instance;
    }
}

饿汉式与懒汉式相比,我们不用管线程安全的问题,代码看起来也比较简洁。

但是,由于对象一开始就被创建出来了,假如我们从头到尾都不调用getInstance()这个方法,那么这个对象就白创建了。

当然,和懒汉式一样,饿汉式也存在反射问题。

总结一下饿汉式的一些问题:

1、有可能出现对象白白浪费的情况。

2、和懒汉式一样,无法组织反射问题。

采用静态内部类的写法

直接上代码

public class Singleton3 {
    //静态内部类
    private static class LazyHolder{
        private static Singleton3 instance = new Singleton3();
    }
    //私有构造器
    private Singleton3(){};
    public static Singleton3 getInstance() {
        return LazyHolder.instance;
    }
}

由于外部类无法访问静态内部类,因此只有当外部类调用Singleton.getInstance()方法的时候,才能得到instance实例。

并且,instance实例对象初始化的时机并不是在Singleton被加载的时候,而是当getInstance()方法被调用的时候,静态内部类才会被加载,这时instance对象才会被初始化。并且也是线程安全的。

所以,与饿汉式相比,通过静态内部类的方式,可以保证instance实例对象不会被白白浪费。

但是,它仍然存在反射问题。

采取枚举的方式

直接上代码:

public enum Singleton4 {
    //一般用大写的了,不过为了和前面的统一
    //我就用小写的了

    instance;
}

枚举的方式简单吧?一行代码就搞定了,不过和饿汉式一样,由于一开始instance实例就被创建了,所以有可能出现白白浪费的情况。

但是,通过枚举的方式,不仅代码简单,线程安全,而且JVM还能阻止反射获取枚举类的私有构造器。

下面做个实验

public enum Singleton4 {
    //一般用大写的了,不过为了和前面的统一
    //我就用小写的了
    instance;

    public static void main(String[] args) throws Exception{
        //获得构造器
        Constructor<Singleton4> c = Singleton4.class.getDeclaredConstructor();
        //把构造器设置为可访问
        c.setAccessible(true);
        //创建两个实例对象
        Singleton4 s1 = c.newInstance();
        Singleton4 s2 = c.newInstance();
        //比较下两个实例是否相等
        System.out.println(s1 == s2);
    }
}

结果出现了异常:

Exception in thread “main” java.lang.NoSuchMethodException: singleton.Singleton4.()

at java.lang.Class.getConstructor0(Class.java:3082)

at java.lang.Class.getDeclaredConstructor(Class.java:2178)

at singleton.Singleton4.main(Singleton4.java:12)

所以,这种枚举的方式可以说的用的最多的一种方式了,唯一的缺点就是对象一开始就被创建,可能出现白白浪费没有用到对象的情况。

不过,总体上,还是推荐采用枚举的方式来写。

获取更多原创文章,可以关注下我的公众号:苦逼的码农,我会不定期分享一些资源和软件等。后台回复礼包送你一份时下热门的资源大礼包。同时也感谢把文章介绍给更多需要的人。

?

原文地址:https://www.cnblogs.com/kubidemanong/p/9671315.html

时间: 2024-10-11 16:27:23

单例模式(下)---聊一聊单例模式的几种写法的相关文章

Java:单例模式的七种写法

转载出处:http://cantellow.javaeye.com/blog/838473 第一种(懒汉,线程不安全): 1 public class Singleton {   2     private static Singleton instance;   3     private Singleton (){}    4     public static Singleton getInstance() {   5     if (instance == null) {   6    

1.18 单例模式的七种写法(转的 虽然看不懂但是感觉可能有用)

转载请注明出处:http://cantellow.iteye.com/blog/838473 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建自己的唯一实例. 3.单例类必须给所有其他对象提供这一实例. 第一种(懒汉,线程不安全): public class Singleton { private static Singleton instance; private Singleton (){} public static Singleton getInstance()

单例模式几种写法

第一种(懒汉,线程不安全): Java代码 public class Singleton { private static Singleton instance; private Singleton (){} public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } 这种写法lazy loading很明显,但是致命的是在多线程

Java:单例模式的七种写法 (转)

第一种(懒汉,线程不安全): 1 public class Singleton {   2     private static Singleton instance;   3     private Singleton (){}    4     public static Singleton getInstance() {   5     if (instance == null) {   6         instance = new Singleton();   7     }   8

单例模式的八种写法比较

单例模式是最常用到的设计模式之一,熟悉设计模式的朋友对单例模式都不会陌生.一般介绍单例模式的书籍都会提到 饿汉式 和 懒汉式 这两种实现方式.但是除了这两种方式,本文还会介绍其他几种实现单例的方式,让我们来一起看看吧. 简介 单例模式是一种常用的软件设计模式,其定义是单例对象的类只能允许一个实例存在. 许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为.比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象

温故而知新(java实现)单例模式的七种写法

第一种(懒汉,线程不安全): Java代码 public class Singleton { private static Singleton instance; private Singleton (){} public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } 这种写法lazy loading很明显,但是致命的是在多线程

Android设计模式之单例模式的七种写法

一 单例模式介绍及它的使用场景 单例模式是应用最广的模式,也是我最先知道的一种设计模式.在深入了解单例模式之前.每当遇到如:getInstance()这样的创建实例的代码时,我都会把它当做一种单例模式的实现. 事实上常常使用的图片载入框架ImageLoader的实例创建就是使用了单例模式.由于这个ImageLoader中含有线程池.缓存系统.网络请求,非常消耗资源,不应该创建多个对象,这时候就须要用到单例模式. ImageLoader的创建代码例如以下: ImageLoader.getInsta

单例模式的五种写法

首先来明确一个问题,那就是在某些情况下,有些对象,我们只需要一个就可以了,比如,一台计算机上可以连好几个打印机,但是这个计算机上的打印程序只能有一个,这里就可以通过单例模式来避免两个打印作业同时输出到打印机中,即在整个的打印过程中我只有一个打印程序的实例. 简单说来,单例模式(也叫单件模式)的作用就是保证在整个应用程序的生命周期中, 任何一个时刻,单例类的实例都只存在一个(当然也可以不存在). package singleton; /** * @author lei * 单例模式的五种写法: *

单例模式的 几种写法

1 首先要知道,什么叫做单例模式. 单例模式是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例的特殊类.通过单例模式可以保证系统中一个类只有一个实例.即一个类只有一个对象实例 2 单例模式简介 单例模式是设计模式中最简单的形式之一.这一模式的目的是使得类的一个对象成为系统中的唯一实例.要实现这一点,可以从客户端对其进行实例化开始.因此需要用一种只允许生成对象类的唯一实例的机制,"阻止"所有想要生成对象的访问.使用工厂方法来限制实例化过程.这个方法应该是静态方法(类方法),因