• 单例模式


      介绍

      概述:单例(Singleton)模式要求一个类有且仅有一个实例,并且提供了一个全局的访问点。那么问题来了:如何绕过常规的构造器,

         提供一种机制来保证一个类只有一个实例?客户程序在调用某一个类时,它是不会考虑这个类是否只能有一个实例等问题的,

         Singleton模式其实相当于一种职责型模式。因为我们创建了一个对象,这个对象扮演了独一无二的角色。

    • 什么是单例模式?

        保证一个类只有一个实例,并且提供一个访问该实例的全局访问点

    • 有什么作用?

        单例有其独有的使用场景,一般是对于那些业务逻辑上限定不能多例只能单例的情况,例如:类似于计数器之类的存在,

        一般都需要使用一个实例来进行记录,若多例计数则会不准确。

    • 应用场景

        举个例子:

        在我们的windows桌面上,我们打开了一个回收站,当我们试图再次打开一个新的回收站时,Windows系统并不会

        为你弹出一个新的回收站窗口。也就是说在整个系统运行的过程中,系统只维护一个回收站的实例。这就是个单例模式运用。

        就像企业只能有一个老板,有且只有一个。   

      实现方式

    • 饿汉模式

          最基本的思路,就是将类的构造器私有化,那么就不能在外部调用 new 创建实例了。

         其次,通过调用静态方法获取实例。

      

     1 // 一般情况来说,这种方式就够用了!
     2 
     3 public class Boss {
     4     private Boss() {}
     5 
     6     private static Boss instance = new Boss();
     7 
     8     public static Boss getInstance() {
     9         return instance;
    10     }
    11 }
    • 懒汉模式以及演进

        饿汉模式的问题在于,即使没有用到 boss,它也会被实例化,有些浪费空间…

        而懒汉模式就是让 boss 只在用到的时候才去加载。

        其设计的思路及代码如下:

        

     1 public class Boss {
     2     // 1. 私有化构造器
     3     private Boss {}
     4 
     5     // 2. 定义实例的变量
     6     private static Boss instance;
     7 
     8     // 3. 通过静态方法创建或返回实例
     9     public static Boss getInstance () {
    10         if (instance == null) {
    11             instance = new Boss();  // 虽然构造器是私有的,但是可以在内部调用
    12         }
    13         return instance;
    14     }
    15 }

      这种方法在单线程下没有任何问题,但是在多线程环境中,却可能会实例化出多个对象。也就是说,它并不是线程安全的。为了解决这个问题,需要对 getInstance 加锁:

      

     1 public class Boss {
     2     // 1. 私有化构造器
     3     private Boss {}
     4 
     5     // 2. 定义实例的变量
     6     private static Boss instance;
     7 
     8     // 3. 通过静态方法创建或返回实例
     9     public synchronized static Boss getInstance () { // 通过锁,将对此方法的调用变成串行的。这就防止了错误
    10         if (instance == null) {
    11             instance = new Boss();  // 虽然构造器是私有的,但是可以在内部调用
    12         }
    13         return instance;
    14     }
    15 }

    上述加锁的方式,可以保证正确实例化对象。但是,因为在方法上加了锁,使得获取单例对象的效率过低。这时候,需要兼顾线程安全和效率,就出现了双重检查锁的概念:

     1 // 1. 将构造器私有化
     2 private Boss() {}
     3 
     4 // 2. 初始化一个静态变量
     5 private static volatile Boss instance = null;
     6 
     7 // 3. 构造一个静态方法,通过它初始化或返还对象
     8 public static Boss getInstance() {
     9     // 双重检查锁机制
    10     if (instance == null) {
    11         synchronized (Boss.class) {
    12             if (instance == null) {
    13                 instance = new Boss();
    14             }
    15         }
    16     }
    17     return instance;
    18 }

      其中:

    •  synchronized :块尽量缩小了锁定的范围,提高效率
    •  volatile :是为防止编译器指令重排而导致双重检查锁失效

      另外:

    • 指令重排本是为了优化代码执行效率而存在的,虽然在单线程中效果拔群,但是在多线程中却能带来麻烦。 volatile  可以要求编译器不要做指令重排。
    • 静态内部类(实现)

        这是相对来说,非常优秀的一种实现。在很多地方,推荐使用这种方式。

     1 public class Boss {
     2     // 1. 将构造器私有化
     3     private Boss() { }
     4 
     5     // 2. 充分利用了静态内部类的特性,在里面初始化 Boss 实例
     6     //    - 只会被初始化一次
     7     //    - 只有当静态内部类内部的属性、方法等被调用的时候,静态内部类才会被加载
     8     static class Singleton {
     9         private final static Boss INSTANCE = new Boss();
    10     }
    11 
    12     // 3. 提供一个公共方法,获取实例化好之后的对象
    13     public static Boss getInstance() {
    14         return Singleton.INSTANCE;
    15     }
    16 }
    • 枚举类

      ENUM 应该是最简单,也是最好的一种实现单例模式的方式。

      它充分利用了 JVM 的特性,既保证了线程安全,又保证了延迟加载。

     1 enum Boss {
     2     INSTANCE;
     3 
     4     public void sayHello () {
     5         System.out.println("hello");
     6     }
     7 }
     8 
     9 public class Main {
    10     public static void main (String... args) {
    11         Boss theBoss = Boss.INSTANCE;  // 获取实例
    12         theBoss.sayHello();            // 调用方法
    13     }
    14 }

     

  • 相关阅读:
    web.config中配置字符串中特殊字符的处理
    开源网络蜘蛛(Spider) 大全
    漂浮层广告代码[层为隐藏,点击广告后层消失][24小时/次]
    用asp.net和xml做的新闻更新系统
    网页采集时,常用的几种正则表达式
    C# Check is No number
    随机显示 ** 条记录的SQL语句
    如何在Asp.net中使用HtmlArea编辑器
    精通ASP.NET中弹出窗口技术
    设计模式学习笔记简单工厂模式
  • 原文地址:https://www.cnblogs.com/lhy-549/p/10088826.html
Copyright © 2020-2023  润新知