写点什么

构建更好的线程安全集合

  • 2009-02-26
  • 本文字数:1027 字

    阅读完需:约 3 分钟

大部分线程安全的集合都有一些基础性的缺陷:虽然每个操作都是线程安全的,但是多个操作无法组合起来使用。这意味着一些基本的执行顺序,例如在弹出顶部元素之前检查栈内元素数量会出现潜在的危险。尽管已经有一些 API 设法将某些操作绑定起来(例如.NET 4 的Coordination Data Structures ),但是它们往往会引入丑陋的方法(如TryDequeue)。

.NET 1 里的集合尝试了另一种方式,它们会对外暴露一个SyncRoot 属性,而不是在内部进行锁定。虽然SyncRoot 仍然是同步对象的默认机制,但是.NET 2 已经抛弃了SyncRoot/Wrapper 设计模式

那么该如何创建一个可用的组合式API 呢?Jared Parson 认为集合不应该直接暴露出线程安全的API,所有的方法都应该属于一个临时的对象,而这个对象只有在您锁定集合的时候才被创建出来。这个临时对象是集合的“钥匙”,只有钥匙的持有者才能获取集合内容。

以下示例为 Jared Parsons 的线程安全队列

复制代码
static void Example1(ThreadSafeQueue<int></int> queue) {<br></br> using (var locked = queue.Lock()) {<br></br> if (locked.Count > 0) {<br></br> var first = locked.Dequeue();<br></br> }<br></br> }<br></br>}

名为 locked 的对象本身不是线程安全的,但是开发人员只有在 using 代码块中才能正确执行操作。在遵守了这一简单规则之后,开发块里的所有代码就是线程安全的。Jared 解释道:

与大部分线程安全的设计一样,这些代码还是有被误用的可能:

  1. 在 ILockedQueue 销毁之后却继续使用它。这种做法应该被禁止,用户现有的知识一般足以避免这个问题。此外一些静态检查工具,例如 FxCop,会把这种做法识别为一个错误。我们也可以使用一种更严厉的做法来阻止此类情况出现:添加一个 disposed 标记,并在每个方法中进行检查。
  2. 如果用户在跨越多个 Lock 语句的情况下保留某个值(例如 Count),那么可能会对集合的状况出现错误的判断和假设。
  3. 如果用户没有正确销毁 ILockedQueue,那么这个对象会被永久锁定。幸运的是,对于实现了 IDisposable 的对象,FxCop 同样会将这种做法识别为一个错误——尽管这不是一个万分稳妥的机制。
  4. 无法确定用户是否会长期持有 ILockedQueue 对象。虽然 IDisposable 一般包含着“短期”的意味,但是这并不能做出完美的保证。
  5. ILockedQueue 并不是线程安全的。虽然一般情况下用户不会把 IDisposable 对象交给多个线程使用,但这也是必须考虑到的情况之一。

查看英文原文: Building a Better Thread-safe Collection

2009-02-26 06:282004
用户头像

发布了 157 篇内容, 共 62.7 次阅读, 收获喜欢 6 次。

关注

评论

发布
暂无评论
发现更多内容

情绪的力量:如何使用情绪来达成目标

董一凡

情绪

线程池续:你必须要知道的线程池submit()实现原理之FutureTask!

一枝花算不算浪漫

源码分析 并发编程

Vue生态篇(一)

shirley

Java Vue

美团可能会强势涉足 ToB

罗小布

创业 互联网巨头 深度思考 互联网

开源分布式文件系统大检阅

焱融科技

开源 sds 存储 焱融科技 文件存储

ARTS - Week Two

shepherd

js algorithm

从 0 到 1 搭建技术中台之发布系统实践:集泳道、灰度、四端和多区域于一体的设计与权衡

伴鱼技术团队

架构 系统设计 系统架构 系统性思考 架构设计

我的 Windows 利器

玄兴梦影

工具 Win

我为什么开始技术写作?

架构精进之路

技术创作

每个人都是领导者的工程团队

hongfei

工程能力 项目实践

# LeetCode 215. Kth Largest Element in an Array

liu_liu

算法 LeetCode

Python 自动化办公之"你还在手动操作“文件”或“文件夹”吗?"

JackTian

Python 自动化

你不知道的SSD那些事

焱融科技

分布式 存储 SSD nvme

原创 | 使用JUnit、AssertJ和Mockito编写单元测试和实践TDD (十三)编写测试-生命周期方法

编程道与术

Java 编程 TDD 单元测试 JUnit

我常用的浏览器插件

彭宏豪95

chrome 效率工具 浏览器 插件

MySQL的各种日志

超超不会飞

MySQL

杂谈-JSONP探索

卡尔

Java jsonp

一个人,沿着童年的路究竟可以走多远?

zhoo299

童年 NASA 航天

知识也会生宝宝?

史方远

个人成长 随笔杂谈

奈学:传授“带权重的负载均衡实现算法”独家设计思路

奈学教育

分布式

【Java 25周年有奖征文获奖名单公布!!!】关于Java,你最想赞扬、吐槽、期待的变化是什么?

InfoQ写作社区官方

写作平台 Java25周年 热门活动

Go语言分布式系统配置治理

田晓亮

微服务

互联网时代的界限管理

非著名程序员

程序员 职场 提升认知 界限管理

程序员修炼的务实哲学

博文视点Broadview

程序员 软件 编程思维 工程师 编程之路

Redis持久化了解一波!

不才陈某

redis 程序员 后端

数据产品经理实战-数据门户搭建(上)

第519区

数据中台 开发数据

# LeetCode 863. All Nodes Distance K in Binary Tree

liu_liu

算法 LeetCode

ARTS 第二周打卡

陈文昕

Vue生态篇(二)

shirley

Vue

patroni 通过服务启动报错

hobson

数据库 高可用 AntDB

这是一个测试文档

Geek_073cad

构建更好的线程安全集合_.NET_Jonathan Allen_InfoQ精选文章