2019独角兽企业重金招聘Python工程师标准>>>

最近被多线程问题(multi-thread issue)弄昏了头。以前虽然也知道系统里要考虑多线程问题,也无数次见到double-check的代码,但是由于自己碰到这方面的问题基本上就是从其他地方拷贝一份现成的代码,改吧改吧,也一直没有遇到多线程带来的bug,所以就没有留心。知道年前,一份两三个月前写的代码出现了由于多线程带来的bug,最近写的代码在code review中又被师兄批评没有考虑多线程问题,这才专门去补了补这方面的知识,现在就小结一下multi-thread问题以及在其中经常会用到的double-check。

在一个多线程程序中,如果共享资源同时被多个线程使用,就有可能会造成多线程问题,这主要取决于针对该资源的某项操作是否是线程安全的。例如,.Net中的dictionary就是一个完全线程不安全的数据结构,对于dictionary的插入、删除都有可能带来多线程问题,这主要是由于dictionary的内部实现结构会频繁的由于插入、删除操作而改变长度,这时,如果出现多线程问题,程序最可能抛出数组越界的Exception。特别的,对于WebService来讲,每一个请求都会生成一个thread/instance,因此就要特别注意多线程问题了。

一般地,多线程问题常常发生于对于共享资源的同时使用。例如,对于类的成员变量的使用,对于全局静态变量的使用,而对于函数内部的局部变量而言,一般式不会存在多线程问题的,因为每个线程在调用一个特定的函数时,都会生成一份函数内部成员变量的副本,线程和线程之间是互不相干的。

解决多线程问题,最常见的方式就是加锁,使得某一资源在同一时刻只能被一个线程所用,而其他线程则必须在被加锁的代码外等待,直到锁被解除,例如如下c#代码所示:

lock(_lock)

{

//do something to the shared resources.

}

下面说说double-check。

多线程问题也常常和一种lazy-initialize的设计模式联系在一起。在这里就会慢慢引出double-check。lazy-initialize讲的是,对于一些特别复杂的对象,让程序在第一次调用它的时候再对它进行初始化,而且保证仅仅初始化一次。

首先想到的设计是这样的:

Class A

{

private ComplexClass _result = null;

public ComplexClass GetResult()

{

if(_result == null)

{

_result = new ComplexClass();

}

return _result;

}

}

但是这样有一个问题。ComplexClass的构造过程较长的话,当第一个线程还在进行ComplexClass构造的时候,_result可能是null,也可能指向了一个尚未初始化完成的对象。这样,要么两个线程初始化了两次ComplexClass,要么第二个线程会返回一个指向不完整对象的引用。所以,在这里需要用到一个锁,如下所示:

ComplexClass GetResult()

{

lock(_lock)

{

if(_result == null)

{

_result = new ComplexClass();

}

}

return _result;

}

这样,虽然多线程的问题解决了,但是每一次需要使用result时都会请求锁,而请求锁对程序的性能是有很大影响的,因此我们在lock的外面再加一层check:

ComplexClass GetResult()

{

if(_result == null)

{

lock(_lock)

{

if(_result == null)

{

_result = new ComplexClass();

}

}

}

return _result;

}

这样,对于所有初始化完成后的请求,就都不用请求锁,而是直接返回_result。

但是还是存在一点问题。对于一些编程语言来说,_result = new ComplexClass();这句代码会使得_result指向一个部分初始化的对象。也就是说,当线程A在初始化ComplexClass时,线程B有可能会判断_result已经不是null了,而这时其实初始化尚未完成,这时线程B就直接返回了一个部分初始化的对象,会造成程序的崩溃。那么,这个问题怎么解决呢?一般的解决方法是在程序内部再加一个局部变量(标识变量)做一层缓冲:

ComplexClass GetResult()

{

ComplexClass result;

if(_result == null)

{

lock(_lock)

{

if(_result == null)

{

result = new ComplexClass();

_result = result;

}

}

}

return _result;

}

这样,上面的问题就彻底解决了~

转载于:https://my.oschina.net/u/1024767/blog/745157

为什么单例模式需要double check相关推荐

  1. Double Check形式的单例模式

    这两天在看开源项目时,发现Event Bus和Universalimageloader中写单例模式都是Double Check的形式.平时总是看到各种各样的单例模式,如,饿汉式,懒汉式等等.其中大多存 ...

  2. Eureka源码-double check单例模式运用

    1.在看源码之前,首先先解释一下什么是double check,以及单例模式中为什么需要double check来进行单例模式的创建? double check,也叫双重检测,主要利用两次的判断进行校 ...

  3. 为什么单例模式中的Double Check要加volatile

    对于单例模式的详细内容,请参考我的上一篇文章 https://blog.csdn.net/Jarvenman/article/details/100136562 在单例模式中,有一种写法叫Double ...

  4. 您能看出这个Double Check里的问题吗?(解答)

    问题请参考:您能看出这个Double Check里的问题吗? 已经很有很多朋友得到了结果,是由于m_categories过早初始化,而导致double check的验证条件被破坏(或者说,满足). p ...

  5. 您能看出这个Double Check里的问题吗?

    昨天在做code review时看到一位同事写了这样的代码.这段代码的目的使用Double Check的做法来保证线程安全的延迟加载.但是我看到这代码之后发现了一个问题,这个问题不是第一次出现.因此, ...

  6. double check java_由java double check说起

    引子 在java中,为了保证某种资源只被初始化一次,我们通常会将其放入同步代码块中,如: public synchronized Resource getResource(){ if (resourc ...

  7. 单例模式的两种实现方式对比:DCL (double check idiom)双重检查 和 lazy initialization holder class(静态内部类)...

    首先这两种方式都是延迟初始化机制,就是当要用到的时候再去初始化. 但是Effective Java书中说过:除非绝对必要,否则就不要这么做. 1. DCL (double checked lockin ...

  8. 单例模式之双重检查锁(double check locking)的发展历程

    不安全的单例 没有注意过多线程安全问题的时候,我们的单例可能是这样的: public final class Singleton {private static Singleton instance; ...

  9. Android 开发者该如何进阶?

    封面.png 前言 经常在简书和微信上收到一些同学的私信,说自己马上毕业或者已经毕业一年,从事Android开发相关的工作,现在不知道要学习什么东西了.或者说自己也在摸索着学习,但是不知道学习的路线对 ...

最新文章

  1. iPhone中字符串的国际化
  2. 线性规划与网络流24题●09方格取数问题13星际转移问题
  3. 开源自然语言处理工具包hanlp中CRF分词实现详解
  4. antd react dva在model中使用另一个model的state值
  5. Android程序结构
  6. javascript MouseEvent对象
  7. 无锡php公司,start.php
  8. 资源下载的终极利器-资源轻松简单下载-资源万能下载法
  9. Android应用文本字体设置
  10. Quartz 定时任务时间表达式说明
  11. Unity中的资源管理-资源类型和基本使用
  12. 程序员面试被问,有没有别家的offer?这个问题怎么回答?
  13. 聚合数据API接口调用方法
  14. 【Python模块】matplotlib 柱状图
  15. android 音频在手机上测试播放不流畅问题
  16. 科研:中科大论文查新查引所用论文数据库
  17. vlookup使用步骤_vlookup怎么用详细步骤 vlookup函数的使用步骤 vlookup教程
  18. 淘宝天猫京东拼多多抖音苏宁1688等平台关键词监控价格API接口(店铺商品价格监控API接口调用展示)
  19. linux安装TensorFlow-GPU版本 非常详细安装必看
  20. pdf怎么转换成cad?简易步骤解决

热门文章

  1. python 文件保存读取时不用with的问题
  2. kaggle较好的竞赛经验
  3. php有哪些屏蔽错误的方法,php常见的错误类型及屏蔽方法
  4. seo建设者_前5名最佳免费和付费网站建设者
  5. python点击按钮浏览本地文件_Python button选取本地图片并显示的实例
  6. mysql for centos下载_python数据分析之路——centos下载并配置mysql与navicat的使用
  7. 【java】简单的方式实现文本文件的读写
  8. 信息系统项目管理师:第1章:信息化与信息系统-重点汇总
  9. 在linux下tomcat报javax.net.ssl.SSLHandshakeException sun.security.validator.ValidatorException: PKIX
  10. 笔记-信息系统安全管理-网络安全工具