美文网首页
单例模式

单例模式

作者: Teemo_fca4 | 来源:发表于2020-05-07 21:07 被阅读0次

单例设计模式:采取某种方法,对某个类在整个系统中,只有一个对象实例。比如Hibernate 的SessionFactory,一个数据源只需要一个SessionFactory就够了。
适用于频繁创建和销毁的对象,工具类对象,频繁使用数据库或文件的对象(比如数据源,session工厂等)

单例模式 可以细分为以下几种

  • 饿汉式(静态常量)
  • 饿汉式(静态代码块)
  • 懒汉式(线程不安全)
  • 懒汉式(同步方法,线程安全)
  • 懒汉式(同步代码块,线程不安全)
  • 双锁检验
  • 静态内部类
  • 枚举
饿汉式(静态常量)
public class SingletonTest01 {
    public static void main(String[] args) {
        //测试
        Singleton instance = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();
        System.out.println(instance == instance2); // true
        System.out.println("instance.hashCode=" + instance.hashCode());
        System.out.println("instance2.hashCode=" + instance2.hashCode());
    }
}

//饿汉式(静态变量)
class Singleton {
    //1. 构造器私有化, 防止外部new
    private Singleton() {}
    
    //2.本类内部创建静态对象实例
    private final static Singleton instance = new Singleton();
    
    //3. 提供一个公有的静态方法,返回实例对象
    public static Singleton getInstance() {
        return instance;
    }
}

分析:
这种写法非常简单,没有线程问题,利用类装载的时候创建对象,但是导致类装载的时机是很多的,因此资源浪费的问题。
资源浪费不是特别严重的问题,因此总体是可以接受的,是可用的。

饿汉式(静态代码块)
class Singleton {
    private Singleton() {}//构造方法私有化,防止外部new

    //2.本类内部创建对象实例
    private  static Singleton instance;
    
    static { // 在静态代码块中,创建单例对象
        instance = new Singleton();
    }
    
    //3. 提供一个公有的静态方法,返回实例对象
    public static Singleton getInstance() {
        return instance;
    }
}

这种方法和上面的几乎一样,只不过将对象实例化的过程放到了代码块中。优缺点和上面的是一样的。

懒汉式(线程不安全)
class Singleton {
    private static Singleton instance;
    
    private Singleton() {}
    
    //提供一个静态的公有方法,当使用到该方法时,才去创建 instance
    public static Singleton getInstance() {
        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

起到了懒加载的效果,但是在多线程环境下不安全,可能会创建多个对象实例出来,因此这个方法是不能使用的

懒汉式(同步方法,线程安全)
// 懒汉式(线程安全,同步方法)
class Singleton {
    private static Singleton instance;
    
    private Singleton() {}
    
    //提供一个静态的公有方法,加入同步处理的代码,解决线程安全问题
    public static synchronized Singleton getInstance() {
        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

解决了线程安全的问题,但是效率比较低,如果系统中要频繁的获取对象实例,那么这种方法毫无疑问是不推荐的。

懒汉式(同步代码块,线程不安全)
class Singleton {
    private static Singleton instance;
    
    private Singleton() {}
    
    //提供一个静态的公有方法,加入同步处理的代码,解决线程安全问题
    public static  Singleton getInstance() {
        if(instance == null) {
            synchronized (Singleton.class){
                instance = new Singleton();
            }
        }
        return instance;
    }
}

毫无疑问 这是线程不安全的,多线程环境下不能使用这个方法。

双锁检验
class Singleton {
    private static volatile Singleton instance;//volatile 抑制指令重排序
    private Singleton() {}
    
    //提供一个静态的公有方法,加入双重检查代码,解决线程安全问题, 同时解决懒加载问题
    //同时保证了效率, 推荐使用
    public static Singleton getInstance() {
        if(instance == null) {
            synchronized (Singleton.class) {
                if(instance == null) {
                    instance = new Singleton();
                }
            }   
        }
        return instance;
    }
}

线程安全,实现了懒加载,实际中可以使用这种方式。

静态内部类
class Singleton {
    private Singleton() {}//构造器私有化
    
    //写一个静态内部类,该类中有一个静态属性 Singleton
    private static class SingletonInstance {
        private static final Singleton INSTANCE = new Singleton(); 
    }
    
    //提供一个静态的公有方法,直接返回SingletonInstance.INSTANCE
    public static synchronized Singleton getInstance() {
        return SingletonInstance.INSTANCE;
    }
}

在加载外部类Singleton 时候,内部类SingletonInstance 不会被加载,只是在调用外部类的getInstance()方法时,内部类SingletonInstance才会去加载,这种方法线程安全,实现了延迟加载,并且代码简单,推荐使用这种方法

枚举
public class SingletonTest08 {
    public static void main(String[] args) {
        Singleton instance = Singleton.INSTANCE;
        Singleton instance2 = Singleton.INSTANCE;
        System.out.println(instance == instance2);
        
        System.out.println(instance.hashCode());
        System.out.println(instance2.hashCode());
        
        instance.sayOK();
    }
}

//使用枚举,可以实现单例, 推荐
enum Singleton {
    INSTANCE; //属性
    public void sayOK() {
        System.out.println("ok~");
    }
}

线程安全,还能防止反序列化重新创建新的对象,这种方法是Effective Java的作者Josh BLoch提倡的方法。 推荐使用这种方法。

JDK中使用的设计模式
JDK中的java.lang.Runtime 类中就用的了饿汉式实现单例模式

相关文章

  • 【设计模式】单例模式

    单例模式 常用单例模式: 懒汉单例模式: 静态内部类单例模式: Android Application 中使用单例模式:

  • Android设计模式总结

    单例模式:饿汉单例模式://饿汉单例模式 懒汉单例模式: Double CheckLock(DCL)实现单例 Bu...

  • 2018-04-08php实战设计模式

    一、单例模式 单例模式是最经典的设计模式之一,到底什么是单例?单例模式适用场景是什么?单例模式如何设计?php中单...

  • 设计模式之单例模式详解

    设计模式之单例模式详解 单例模式写法大全,也许有你不知道的写法 导航 引言 什么是单例? 单例模式作用 单例模式的...

  • Telegram开源项目之单例模式

    NotificationCenter的单例模式 NotificationCenter的单例模式分析 这种单例模式是...

  • 单例模式Java篇

    单例设计模式- 饿汉式 单例设计模式 - 懒汉式 单例设计模式 - 懒汉式 - 多线程并发 单例设计模式 - 懒汉...

  • IOS单例模式的底层原理

    单例介绍 本文源码下载地址 1.什么是单例 说到单例首先要提到单例模式,因为单例模式是单例存在的目的 单例模式是一...

  • 单例

    iOS单例模式iOS之单例模式初探iOS单例详解

  • 单例模式

    单例模式1 单例模式2

  • java的单例模式

    饿汉单例模式 懒汉单例模式

网友评论

      本文标题:单例模式

      本文链接:https://www.haomeiwen.com/subject/sfttmctx.html