设计模式--单例模式

简介

单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例。即一个类只有一个对象实例。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息。这种方式简化了在复杂环境下的配置管理。在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序等对象常被设计成单例。

UML图

模式分析
单例模式的目的是保证一个类仅有一个实例,并提供一个访问它的全局访问点。单例模式包含的角色只有一个,就是单例类——Singleton。单例类拥有一个私有构造函数,确保用户无法通过new关键字直接实例化它。除此之外,该模式中包含一个静态私有成员变量与静态公有的工厂方法,该工厂方法负责检验实例的存在性并实例化自己,然后存储在静态成员变量中,以确保只有一个实例被创建。

在单例模式的实现过程中,需要注意如下三点:
       单例类的构造函数为私有;
       提供一个自身的静态私有成员变量;
       提供一个公有的静态工厂方法。

 

懒汉式

线程不安全

//懒汉式单例,在第一次调用时实例化自己(线程不安全)
/**
* 只能在单线程下使用。如果在多线程下,一个线程进入了if (singleton == null)判断语句块,还未来得及往    
* 下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。所以在多线程环境下不可使用这种方式。
**/
public class Singleton {

    private static Singleton singleton;

    // 私有化构造
    private Singleton() {}

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

线程安全

// 线程安全
public class Singleton {

    private static Singleton singleton;

    private Singleton() {}

    public static synchronized Singleton getInstance() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
}
// 线程安全。双重检查锁。
public class Singleton {

    private static Singleton singleton;

    private Singleton() {}

    public static Singleton getInstance() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                singleton = new Singleton();
            }
        }
        return singleton;
    }
}
// 静态内部类实现方式
public class Singleton {

    private Singleton() {}

    private static class SingletonInstance {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonInstance.INSTANCE;
    }
}

三种线程安全懒汉式比较:

  • 第一种在方法调用上增加了同步,线程安全,但每次都需要同步。这样会对性能有影响。毕竟大部分情况是不需要同步的。
  • 第二种在方法上做了两次实例是否为null的检查,确保了只有第一调用的时候同步。这样能避免每次同步的性能消耗。
  • 第三种利用了ClassLoader的机制来办证初始化instance只有一个线程。所以也是线程安全并且没有性能损耗问题。

补充,

// 双重检查,两次if判断
public class Singleton {

    private static volatile Singleton singleton;

    private Singleton() {}

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

进行了两次if (singleton == null)检查,这样就可以保证线程安全了。这样,实例化代码只用执行一次,后面再次访问时,判断if (singleton == null),直接return实例化对象。

饿汉式

// 饿汉式,静态常量方式
public class Singleton {

    private final static Singleton INSTANCE = new Singleton();

    private Singleton(){}

    public static Singleton getInstance(){
        return INSTANCE;
    }
}
// 饿汉式 静态代码块
public class Singleton {

    private static Singleton instance;

    static {
        instance = new Singleton();
    }

    private Singleton() {}

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

两种方式比较

  • 两种方式的区别在于一个是定义的静态变量,另一个是静态代码块中。两者的优缺点一致:
  • 优点是写法比较简单,就是在类装载的时候就完成实例化。避免了线程同步问题。
  • 缺点是在类装载的时候就完成实例化,没有达到Lazy Loading的效果。如果从始至终从未使用过这个实例,则会造成内存的浪费

第一篇简陋的博客、(*^▽^*)

参考网址:https://www.cnblogs.com/zhaoyan001/p/6365064.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值