zoukankan      html  css  js  c++  java
  • [设计模式]单件模式概念和三个解决多线程问题的方案

    主要是从 Head Fisrt 设计模式中学习到知识;

    1. 定义单件模式

      单件模式确保一个类只有一个实例,并提供一个全局访问点;

      在整个系统上下文中,只有一个对象,对于很多在系统中只需要一个或者创建代价比较大的对象,可以使用,例如:线程池、缓存、对话框、处理偏好设置和注册表对象、日志对象、充当打印机、显卡等设备的驱动程序的对象;

      采用单件模式可以避免系统维护太多没有记录状态数据、所有实例功能可替代的相关对象,还有就是多个实例处理会可能会造成结果不一致的问题;

    2. 主要思想

      2.1 由类持有一个静态的类对象,并通过方法暴露对类对象的获取接口;

      2.2 类禁止外部对象实例化

    3. 单件模式的实现

      3.1 下面是单件模式的简单实现,思想就是持有一个静态对象,当需要的时候就通过类的公用方法获取对象的引用,这里还有一个做法就是延迟实例化,当对象需要用到的时候才会去实例化对象,如果对象没有被引用到,那么就是一直都不会实例化,系统资源也不会浪费。

    public class Singleton {
      private static Singleton uniqueInstance;
    
      private Singleton () {}
    
      public static Singleton getInstance () {
        if (uniqueInstance == null) {
              uniqueInstance = new Singleton();
          }
        }
        return uniqueInstance;
      }
    
      public static void main(String[] args) {
    
        Singleton singleton = Singleton.getInstance();  
        System.out.println(singleton.toString());    // Singleton@15db9742
    
        singleton = Singleton.getInstance();
        System.out.println(singleton.toString());    // Singleton@15db9742
    
        singleton = Singleton.getInstance();
        System.out.println(singleton.toString());    // Singleton@15db9742
    
        singleton = Singleton.getInstance();
        System.out.println(singleton.toString());    // Singleton@15db9742
    
      }
    }

      这里打印出来,几个类的对象的内存地址都是同一个,引用了同一个对象。

    4. 单件模式和多线程

      上面的单件模式实现已经能够满足基本的使用要求,但是当单件模式模式遇到多线程之后,很多奇怪的问题就发生了(事实上很多代码遇到多线程后都会有问题),

      例如上面的例子,当代码的推进状态像下面的状态,就会出现问题:

      这个时候对象已经不是同一个了,多线程造成 单件模式 已经和我们定义的不一样了。

      为了解决这个问题,有以下的三个解决方法:

      * 使用synchronized方法,将getInstance()变成同步的方法,这样能够解决我们的问题,但是实例化只是在第一次的时候使用,后面就没有这个问题存在了,然后通过synchronized强制同步会降低系统的并发性能,这种情况适合getInstance()的性能不影响或者影响了可以接受的地方;

      

     public static synchronized Singleton getInstance () {
    ...

      * 使用“急切”的实例化方法,在类初始化的时候就像对象生成;

    public class Singleton {
      private static Singleton uniqueInstance = new Singleton();
      private Singleton () {}
      public static Singleton getInstance () { 
        return uniqueInstance;  
      }
    }

      * 使用“双重检查加锁”( since jdk 1.4 )

      使用之后代码是这样子的:

      

    public class Singleton {
      private volatile static Singleton uniqueInstance;
    
      private Singleton () {}
    
      public static Singleton getInstance () {
        if (uniqueInstance == null) {
          synchronized (Singleton.class) {
            if (uniqueInstance == null){
                  uniqueInstance = new Singleton();
            }
          }
        }
        return uniqueInstance;
      }
    
      public static void main(String[] args) {
        System.out.println("test");
        Singleton singleton = Singleton.getInstance();
        System.out.println(singleton.toString());
    
        singleton = Singleton.getInstance();
        System.out.println(singleton.toString());
        singleton = Singleton.getInstance();
        System.out.println(singleton.toString());
        singleton = Singleton.getInstance();
        System.out.println(singleton.toString());
      }
    }

      通过 volatile 标识该变量的修改是对其他线程可见的,还有禁止指令排序;详细用法见:地址

      然后当判断是未初始化的时候,再将类进入锁定然后再次判空之后再初始化类,这样就解决了我们前面遇到的问题,也很好的实现了单件模式的理念。

  • 相关阅读:
    1.求整数最大的连续0的个数 BinaryGap Find longest sequence of zeros in binary representation of an integer.
    JTree实例
    java发送邮件完整实例 java邮件工具类
    oracle存储过程中文乱码问题
    黑马day16 jquery&内容过滤选择器&可见度选择器
    隐性反馈行为数据的协同过滤推荐算法
    ACdream 1083 有向无环图dp
    正則表達式
    hdu 2209 bfs+状压
    action属性注入为null
  • 原文地址:https://www.cnblogs.com/zhuangmingnan/p/9383859.html
Copyright © 2011-2022 走看看