多线程问题与double-check小结
2015-11-26 15:36
330 查看
解决多线程问题,最常见的方式就是加锁,使得某一资源在同一时刻只能被一个线程所用,而其他线程则必须在被加锁的代码外等待,直到锁被解除,例如如下c#代码所示:
lock(_lock)
{
//do something to the shared resources.
}
下面说说double-check。
多线程问题也常常和一种lazy-initialize的设计模式联系在一起。在这里就会慢慢引出double-check。lazy-initialize讲的是,对于一些特别复杂的对象,让程序在第一次调用它的时候再对它进行初始化,而且保证仅仅初始化一次。
首先想到的设计是这样的:
Class A
{
private static 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;
}
这样,上面的问题就彻底解决了~
相关文章推荐
- Zookeeper你应该了解基础知识
- SQL实现循环每一行做一定操作。
- 2014.7.23 内存分析_栈_堆_栈帧
- 更新Debian内核e1000e驱动模块
- [LeetCode]Edit Distance
- Geometry类详解
- 【技♂巧】bzoj1257余数之和
- 实现多国语言的几个小知识
- swift可选链和类型转换
- 【学习笔记】分区表和分区索引——概念部分(一)
- [python]python子字符串的提取、字符串连接、字符串重复
- oracle function学习1
- 模拟迁途箭头圆圈
- ubuntu下创建、删除文件、文件夹,移动文件
- css层叠样式详解
- android View各属性详解
- 二叉搜索树-BST-查找算法-插入算法-删除算法 http://www.cnblogs.com/pangxiaodong/archive/2011/08/24/2151060.html
- 模拟迁途.html
- windows server做NTP时间服务器 及时间设置internet时间同步的方法
- 【实战Java高并发程序设计 2】无锁的对象引用:AtomicReference