单例模式完整解析

volatile, static readonly, double check

直到对象要求产生一个实例才执行实例化;这种方法称为"懒实例化"。懒实例化避免了在应用程序启动时实例化不必要的 singleton

1.

using System;
public class Singleton
{
   private static Singleton instance;
   private Singleton() {}
   public static Singleton Instance
   {
      get
      {
         if (instance == null)
         {
            instance = new Singleton();
         }
         return instance;
      }
   }
}

但是,这种实现的主要缺点是在多线程环境下它是不安全的。如果执行过程的不同线程同时进入 Instance 属性方法,那么可能会创建多个 Singleton 对象实例。每个线程都会执行下列语句,并决定必须创建新的实例:

if (instance == null)

解决此问题的方法有很多。一种方法是使用被称为 Double-Check Locking [Lea99] 的技术。而 C# 与公共语言运行库也提供了一种"静态初始化"方法,这种方法不需要开发人员显式地编写线程安全代码,即可解决这些问题。

2.  C# 与公共语言运行库提供的"静态初始化"方法

One of the reasons Design Patterns [Gamma95] 避免使用静态初始化的原因之一是,C++ 规范在静态变量的初始化顺序方面留下了一些多义性。幸运的是,.NET Framework 通过其变量初始化处理方法解决了这种多义性:

public sealed class Singleton
{
   private static readonly Singleton instance = new Singleton();
   private Singleton(){}
   public static Singleton Instance
   {
      get
      {
         return instance;
      }
   }
} 

3. Double-Check Locking方法

用volatile修饰instance, 只有实例变量instance分配完,其他线程才能访问它,多线程读它的时候要么是null,要么是完整的分配好的对象。

lock的对象是private的object对象,不要lock公有的对象比如this,type,以免发生死锁。

using System;
public sealed class Singleton
{
   private static volatile Singleton instance;
   private static object syncRoot = new Object();
   private Singleton() {}
   public static Singleton Instance
   {
      get
      {
         if (instance == null)
         {
            lock (syncRoot)
            {
               if (instance == null)
                  instance = new Singleton();
            }
         }
         return instance;
      }
   }
}

此 double-check locking 方法解决了线程并发问题,同时避免在每个 Instance 属性方法的调用中都出现独占锁定。这里的避免独占锁定是不需要锁定整个Instance属性方法,性能不受影响。它还允许您将实例化延迟到第一次访问对象时发生。实际上,应用程序很少需要这种类型的实现。大多数情况下,静态初始化方法已经够用。

优点:Double-Check Locking 技术已在公共语言运行库中正确实现。但是其他环境中还是会有一些常见的、与使用 Double-Check Locking 有关的问题。

总结:

最后还是推荐用"静态初始化"方法实现Singleton。实现简单,实现依赖于CLR框架解决多线程问题。

参考文章:

http://msdn.microsoft.com/zh-cn/library/ff650316.aspx

http://msdn.microsoft.com/zh-cn/library/ms954629.aspx

http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

时间: 2024-10-18 06:43:03

单例模式完整解析的相关文章

曹工说Spring Boot源码(15)-- Spring从xml文件里到底得到了什么(context:load-time-weaver 完整解析)

写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean Definition到底是什么,咱们对着接口,逐个方法讲解 曹工说Spring Boot源码(3)-- 手动注册Bean Definition不比游戏好玩吗,我们来试一下 曹工说Spring Boot源码(4)-- 我是怎么自定义ApplicationContext,从json文件读取bean de

曹工说Spring Boot源码(16)-- Spring从xml文件里到底得到了什么(aop:config完整解析【上】)

写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean Definition到底是什么,咱们对着接口,逐个方法讲解 曹工说Spring Boot源码(3)-- 手动注册Bean Definition不比游戏好玩吗,我们来试一下 曹工说Spring Boot源码(4)-- 我是怎么自定义ApplicationContext,从json文件读取bean de

曹工说Spring Boot源码(18)-- Spring AOP源码分析三部曲,终于快讲完了 (aop:config完整解析【下】)

写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean Definition到底是什么,咱们对着接口,逐个方法讲解 曹工说Spring Boot源码(3)-- 手动注册Bean Definition不比游戏好玩吗,我们来试一下 曹工说Spring Boot源码(4)-- 我是怎么自定义ApplicationContext,从json文件读取bean de

java单例模式深度解析

应用场景 由于单例模式只生成一个实例, 减少了系统性能开销(如: 当一个对象的产生需要比较多的资源时, 如读取配置, 产生其他依赖对象, 则可以通过在应用启动时直接产生一个单例对象, 然后永久驻留内存的方式来解决) Windows中的任务管理器; 文件系统, 一个操作系统只能有一个文件系统; 数据库连接池的设计与实现; Spring中, 一个Component就只有一个实例Java-Web中, 一个Servlet类只有一个实例; 实现要点 声明为private来隐藏构造器 private sta

php中单例模式的解析说明

1 <?php 2 //单例模式 3 class Dbconn{ 4 private static $_instance=null; 5 protected static $_counter=0; 6 protected $_db; 7 private function __construct(){ 8 self::$_counter+=1; 9 } 10 public static function getInstance(){ 11 if(!self::$_instance instance

单例模式简单解析--Singleton 单例模式(懒汉方式和饿汉方式)

单例模式的概念: 单例模式的意思就是只有一个实例.单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例.这个类称为单例类. 关键点: 1)一个类只有一个实例       这是最基本的 2)它必须自行创建这个实例 3)它必须自行向整个系统提供这个实例 -------------------------------------------------------------------------------------------------------------------

GO语言完整解析GO!GO!GO!(一)基础语法(未完待续)

前言 适用大概用过Golang编程的朋友,本文档属于一份总结,与査漏补缺. 一:GO的数据类型--基础类型 0,定义一个变量的标准格式为: var  变量名   类型 1,数字类 1)整数类型:int8, int16,int32,int64(有符号)/uint8, uint16,uint32,uint64(无符号),分别占用8bit,16bit,32bit,64bit; int/uint,占用多大空间取绝于CPU的机器字大小,一般为32bit或者64bit rune,表示一个字符占用的存储空间

设计模式课程 设计模式精讲 8-6 单例设计模式-序列化破坏单例模式原理解析及解决方案

1 原理解析 2 代码演练 2.1 原理解析 2.2 解决方案 1 原理解析 2 代码演练 2.1 原理解析 测试类: package com.geely.design.pattern.creational.singleton; import java.io.*; public class Test { /*public static void main(String [] args){ //这样写异常,因为构造方法私有 // LazySingleton lazySingleton = new

vuex所有核心概念完整解析State Getters Mutations Actions

vuex是解决vue组件和组件间相互通信而存在的,vuex理解起来稍微复杂,但一旦看懂则即为好用: 安装: npm install --save vuex 引入 import Vuex from 'vuex' import Vue from 'vue' Vue.use(Vuex) vuex的几个参数的介绍 State         储存初始化数据 Getters      对State 里面的数据二次处理(对数据进行过滤类似filter的作用)比如State返回的为一个对象,我们想取对象中一个