[设计模式]单件模式概念和三个解决多线程问题的方案

主要是从 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());    // [email protected]

    singleton = Singleton.getInstance();
    System.out.println(singleton.toString());    // [email protected]

    singleton = Singleton.getInstance();
    System.out.println(singleton.toString());    // [email protected]

    singleton = Singleton.getInstance();
    System.out.println(singleton.toString());    // [email protected]

  }
}

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

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 标识该变量的修改是对其他线程可见的,还有禁止指令排序;详细用法见:地址

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

原文地址:https://www.cnblogs.com/zhuangmingnan/p/9383859.html

时间: 2024-10-15 16:30:06

[设计模式]单件模式概念和三个解决多线程问题的方案的相关文章

设计模式 - 单件模式(singleton pattern) 详解

单件模式(singleton pattern) 详解 本文地址: http://blog.csdn.net/caroline_wendy/article/details/28595349 单件模式(singleton pattern) : 确保一个类只有一个实例, 并提供一个全局访问点. 单价模式包括3个部分: 私有构造器, 静态变量, 静态方法. 具体方法: 1. 标准的单例模式: /** * @time 2014.6.5 */ package singleton; /** * @author

Operation System - Peterson's Solution算法 解决多线程冲突

Person's solution 是用来一种基于软件的解决关键区域问题的算法(critical-section). 它并不是完美的,有可能不对地工作.并且是限制解决两个进程同步的问题. 可是它非常easy,非常原始,学习起来也是非常轻松的. 代码例如以下: do { flag[i] = true; turn = j; while (flag[j] && turn == j); critical section flag[i] = false; remainder section } wh

Operation System - Peterson's Solution算法 解决多线程冲突

Person's solution 是用来一种基于软件的解决关键区域问题的算法(critical-section). 它并非完美的,有可能不正确地工作.而且是限制解决两个进程同步的问题. 但是它很简单,很原始,学习起来也是很轻松的. 代码如下: do { flag[i] = true; turn = j; while (flag[j] && turn == j); critical section flag[i] = false; remainder section } while (tr

C++设计模式-单件

理解 1.       Singleton模式用来取代全局静态变量.C++通过静态成员变量来实现类实例全局唯一性. 2.       instance()方法是单件提供的唯一调用入口. 要点 1.       为了防止外界调用产生多个实例,将构造方法.析构方法.拷贝构造方法.赋值重载方法都作为protected. 2.       instance()方法产生对象方式有两种:使用局部static对象,生命期在首次进入局部生命期产生(见下面),在程序结束时销毁:通过new产生新对象,在析构方法中d

解决多线程并发问题

1.文件锁 如果对该表的更新或插入的操作,都会经过一个统一的文件,这种方式是可以解决的多进程并发的问题: 实现方式如下: public static function cbInventoryReserve() { $LOCK_FILE_PATH = $_SERVER['DOCUMENT_ROOT']."wmsinventoryapi/inventory/InventoryReserve.php"; $fp = fopen( $LOCK_FILE_PATH, "r"

.NET中TextBox控件设置ReadOnly=true后台取不到值三种解决方法

.NET中TextBox控件设置ReadOnly=true后台取不到值三种解决方法 当TextBox设置了ReadOnly=true后要是在前台为控件添加了值,后台是取不到的,值为空,多么郁闷的一个问题经过尝试,发现可以通过如下的方式解决这个问题.感兴趣的朋友可以了解下 当TextBox设置了ReadOnly="true" 后,要是在前台为控件添加了值,后台是取不到的,值为“空” 原理没想通,说不清楚微软是出于什么考虑的,不过有时是要我们能通过前台脚本来填充值,并不希望用户修改其控件内

第三章解决堆栈的编程问题

第三章      解决堆栈的编程问题 堆栈是一种特殊的线性表,是一种只允许在表的一端进行插入或删除操作的线性表. 堆栈的主要特点是后进先出. 用一片连续的存储空间来存储栈中的元素,这样的栈称为顺序栈. 用链式存储结构存储的栈称为链栈. 汉诺塔问题 汉诺塔问题来自一个古老的传说:在世界刚刚被创建的时候有一座砖石宝塔(A),其上有64个金蝶.所有按从大到小的顺序从塔底堆放至塔顶.紧挨着这座塔有两个砖石塔(B和C).从世界创始之日起,婆罗门的牧师们就一直在试图把A塔上的碟子移动到B上去,其间借助于C的

C++设计模式之建造者模式(三)

4.引入钩子方法的建造者模式 建造者模式除了逐步构建一个复杂产品对象外,还可以通过Director类来更加精细地控制产品的创建过程,例如增加一类称之为钩子方法(HookMethod)的特殊方法来控制是否对某个buildPartX()的调用,也就是判断产品中某个部件是否需要被建造.钩子方法的返回类型通常为boolean类型,方法名一般为isXXX(),钩子方法定义在抽象建造者类中.在抽象建造者类中提供钩子方法的默认实现,具体建造者类如果不需要建造某个部件,则该建造者类覆盖抽象建造者类的钩子方法.

CSS 基本概念(Basic CSS Concepts)三、解决样式冲突

三.解决样式冲突(Resolving Style Conflicts) 在创建一个样式表的过程中,很可能有许多不同的规则将适用于同一个元素.例如,如果一个规则适用于所有的段落元素,另一个规则适用于具有一个具有紧急值的类属性的所有元素,那么应该使用哪一个规则? 当它发生时,这两个规则将适用.如果不同的规则包含处理不同属性的声明,那么就没有冲突,样式都是“组合在一起”的.但是,如果有不同的规则试图为同一个属性设置值的声明,那么有机制决定哪些样式将被使用. 举例说明,假设有以下三个规则: div#as