1. 定义

为了确保一个类有且仅有一个实例,而且自行实例化并向整个系统提供这个实例。

2. 使用场景

确保某个类有且只有一个对象的场景,避免产生多个对象消耗过多的资源,或者某种类型的对象只应该有且只有一个。例如,创建一个对象需要消耗的资源过多,如要访问IO和数据库等资源,这时候就需要考虑使用单例模式。

3. 机制

创建一个独一无二觉得的对象,有多种方式。但是不管你如何创建一个单例对象,都必须要确保其他开发人员不能创建该单例对象的新的实例。

那么如何做到这一点呢?  答:为了避免其他开发人员实例化你定义的类,可以创建唯一一个构造函数,并将其设置为私有的访问权限。注意,如果创建了其他非私有的构造函数,或者没有创建任何构造函数,其他对象都能够实例化改类。

设计一个单例类的时候,需要确定何时实例化该类的单例对象。一种做法是创建这个类的实例,并将它作为该类的静态成员变量。例如:

private static Factory factory = new Factory();

然后通过一个公共的getFactory()静态方法获得该类的唯一实例。实例代码:

public class Factory{
    private static Factory factory = new Factory ();
    public static Factory getFactory() {
        return factory;
    }
    private Factory() {}
}

如果不希望提前创建单例实例,还可以在第一次需要的时候,延迟初始化它。

if (factory == null)
    factory = new Factory();

延迟不延迟有哪些方面的区别呢? 为什么实例化还有延迟和非延迟?   一般延迟实例化对象有两个原因: 1. 在静态初始化的时候,没有足够的信息对单例对象进行初始化。  2. 选择延迟初始化单例对象与获取资源有关,如数据库连接,没有使用的需求,就没有必要实例化该单例对象。

3. 单例与线程

如果想在多线程环境下延迟初始化一个单例模型,必须避免多个线程同时初始化该单例对象。在多线程环境下,无法保证在其他线程开始执行该方法时,当前线程已经完整的执行完该方法。这可能出现两个线程同时初始化一个单例对象的情况。为了避免这种情况,需要使用双重校验锁机制(Double Check Lock)去协调不同线程对同一方法的执行。

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

单例模式或许是最负盛名的一个设计模式,但是很容易被误用,不要让单例作为创建全局变量的一种花哨方法。因为单例会引入耦合,应减少使用单例模式的类的数量。最好的方式是:类只知道与它协作的对象,不必了解它所需要的限制。 需要注意的是:对象具有唯一性,不代表使用了单例模式。

4. 推荐使用的单例模式实现方式

在应用单例模式时,我们知道懒汉模式、饿汉模式、双重检验锁模式。这些实现方式都有各自的特点和缺陷,其中双重校验锁算性是应用最为广泛的,但是也不是完美的。《Java并发编程实践》这本书给出来一个推荐的实现方式:

public class Singleton {
       // 构造函数
       private Singleton() {}
  
       public static Singleton getInstance(){
      return SingletonHloder.sInstance;
       }

    // 静态内部类
      private static class SingletonHloder {
      private static final Singleton sInstance = new Singleton();
     }
}    

实现方式解读:

当第一次加载Singletion类时并不会初始化sInstance,只有在第一次调用Singleton的getInstance方法时才会导致sInstance被初始化。因此,第一次调用getInstance方法会导致虚拟机加载SingletonHolder类,这种方式不仅能够确保线程安全,也能保证单例对象的唯一性,同时也延迟了单例的实例化,所以这是推荐使用的单例模式的实现方式。

最新文章

  1. 【原创】如何确定Kafka的分区数、key和consumer线程数
  2. MySQL 5.6 for Windows 解压缩版配置安装
  3. Qt snippet — 打开文件&保存文件
  4. lambda 个人学习理解
  5. Android Menu菜单使用
  6. linux安装ftp服务器
  7. iOS之AVPlayer的简单应用
  8. a/b + c/d
  9. solr6.4.1搜索引擎同步mysql数据库
  10. 在vs2010中显示代码的行数
  11. [bzoj4161]Shlw loves matrix I
  12. cocos 场景制作流程
  13. 使用antd Table + mobx 处理数组 出现的一系列问题
  14. 基于开发者中心DevOps流水线快速上云
  15. 大数据-将MP3保存到数据库并读取出来《黑马程序员_超全面的JavaWeb视频教程vedio》day17
  16. c c++ 函数不要返回局部变量的指针
  17. springboot打成Jar包后部署至Linux服务器上
  18. 手机端 https://doc.vux.li/zh-CN/components/badge.html
  19. java8新特性(二)_lambda表达式
  20. 为什么使用this构造器

热门文章

  1. 与引导文件系统/vmfs/devices..的备用设备之间的连接已丢失,主机配置更改将不会保存到持久存储中
  2. cdnbest日志分析显示404的原因
  3. Python设计模式 - UML - 包图(Package Diagram)
  4. 华为NB-IOT报告
  5. VMware虚拟机配置端口转发(端口映射),实现远程访问【转】
  6. oracle数据库卸数及ddl导出
  7. iOS 拨打电话三种方式
  8. Java之IO流总结
  9. Python之路(第三十篇) 网络编程:socket、tcp/ip协议
  10. Event对象和触发