警告:我不是一个多线程编程的专家。事实上,甚至不能说我可以胜任这个东西。我的整个职业生涯,需要用到多线程来实现代码的次数也不多。所以请用一个怀疑的态度来看待我以下的所有观点。

有一个我经常问的问题是:“这个代码是线程安全的吗?”,要回答这个问题,我们很显然要先知道线程安全是什么。
但是在我们讨论这个问题前,我想先把另外一个问题搞清楚,还有一个我稍微问的没有那么多的问题是“Eric,为什么Michelle pfeiffer在照片里总是这么好看”,要回答这个难题,我咨询了一下维基百科:

一个上镜的对象指的是对象总能在照片里面很有吸引力或引人注目

为什么Michelle pfeiffer在照片里那么好看?因为她很上镜。显然的。
好的,我很高兴我们先把这个谜团解决了,但是不知怎么的又有另一个难题现在悬在我的手中。维基百科是这么定义线程安全(thread safe)的:

“A piece of code is thread-safe if it functions correctly during simultaneous execution by multiple threads.”
代码的一部分如果能在多线程同时执行时运行正确那么就是线程安全的

就跟上镜一样,这很明显,当我们问“这个代码是线程安全的吗?”我们实际上是在问“这份代码在特定情况下可以运行正常吗?”那么我们要如何来定义代码是不是正常呢?这个我们还没有任何定义。
维基百科写到:

“In particular, it must satisfy the need for multiple threads to access the same shared data, …”
尤其重要的是,必须要满足多线程访问共享数据的的需求

这好像是对的。这好像就是人们想要表达线程安全的意思。但是:

“…and the need for a shared piece of data to be accessed by only one thread at any given time.”
还有…被需要共享的数据同一个时间只能有一个线程来访问

到现在我们才开始讨论到写线程安全代码的技巧,而不再是讨论线程安全到底是什么。把一个数据锁住,这个同一个时间只有一个线程进行访问只是实现线程安全的其中一个技巧,而不是线程安全的定义。

我不是说这个定义是错的。相较于之前的线程安全的定义,这个定义完全不差。我实际上想说的是,这个定义很含糊,跟之前的“在某些情况下执行正确”表述没有什么不一样。因为,当我问“这个代码是线程安全的吗?”我常常要往回退一步讲“你是在讨论哪个场景下的应用?”和“到底是在哪个场景下表现出哪种结果才算是正确的行为?”

人们在谈论线程安全的时候,总会产生很多不一样的问题。比如,当我告诉你我有一个“线程安全的可变队列”,你可以把这个用在你的程序中时。你很高兴的写了一个线程来执行它然后又用另外一个线程频繁的来新增或者移除可变队列中的对象:

if (!queue.IsEmpty) Console.WriteLine(queue.Peek());

然后你的代码在peek抛出QueueEmptyException时崩溃了,到底发生了什么?我说这个是线程安全的,但是你的代码却在一个多线程使用场景中崩溃了。

当我说“这个队列是线程安全的”的时候,我的意思是,这个队列会持续不断的维护其内部的状态,无论其他的线程以什么样的顺序来单独执行。但是我没有说在一个队列顺序周期内多次操作它还会自行维护状态。简单的说,我所理解的正确行为跟你所理解的正确行为不是一回事。我只关心它会不会崩溃,但是你在乎的是队列能不能正确的返回相应的方法。

在这个例子中,你和我可能都谈到了不同的线程安全。可变数据的线程安全通常指的是要确保运行中共享数据永远都是最新的状态,即使是我们操作的过程中逻辑并不连贯,就跟上面的例子一样。不可变数据结构的线程安全通常讲的是执行过程中逻辑是一致的,尽管你要找的不可变快照是过时的数据。

现在的问题是要不要获取第一个元素取决于“过时”的数据,要设计一个在所有场景下都不允许有“过时”数据的真线程安全可变数据结构是十分困难的。如果你真的要将“peek”操作做到真正的线程安全,你需要一个新的方法:

if (!queue.Peek(out first)) Console.WriteLine(first);

这个是线程安全的吗?看起来的确好多了。但是如果执行完peek之后,另一个线程执行了出队(dequeues)操作呢? 代码不会崩溃,但是你已经完全把之前程序的行为都改变了。在之前的逻辑里,如果测试后有另一个线程对其进行了“出队”操作,那么第一个元素会是什么,要么程序崩溃,要么就将第一个元素的最新状态打印出来。现在你打印的第一个数据是过时的。那么这是正常的吗?如果我们不总是想要对最新的数据进行操作的话。

这里稍微暂停一下,实际上,之前版本的代码也有这个问题。如果你在进行peek成功操作之后有另一个线程执行了出队操作,而且是在你打印操作之前,那么你可能打印出的就是一个过时数据。

如果你是想要无论何时都打印出最新的数据呢?你实际上想要实现的线程安全操作是:

queue.DoSomethingToHead(first=>{Console.WriteLine(first);});

现在这个队列的作者和使用者都在怎么使用它上达成了一致意见,所以这才是真正的线程安全,对吗?

除非…有超级复杂的需求。如果在某个需求里触发了代码执行另外一个线程,从而导致了队列操作,进而产生了死锁。那么死锁算不算一个正确的行为,如果不是,那么这个方法是真正的安全吗?

是的。

现在你应该理解了我的观点,就像我之前所说的那样,如果不沟通好具体是哪种安全威胁或者没有经过验证的话,说要编写一个安全的代码是完全没有帮助的。同样的,如果不讨论哪种不合适的行为会利用线程安全机制,哪种行为预防不了而去说这个代码是线程安全的也是完全没有帮助的。线程安全和代码规范大同小异。你同意以某种形式去和一个对象进行沟通,如果你符合规范的话,它就会给你返回一个正确的结果。如果你这么做了,那么它就会按照规范那样表现,但到底怎么定义正确的反馈,这确实是一个潜在的难题。

是的,我意识到了维基百科上所说的可能是错的,我可以把它改过来,但是这里有两个我不去这么做的原因。首先,我已经表述过了,我不是这个领域的专家,我把它留个真正这个领域的专家来做。第二,我的观点不是要说维基百科是错的,而是它上面的陈述的真的十分模糊。

原文

https://docs.microsoft.com/en-us/archive/blogs/ericlippert/what-is-this-thing-you-call-thread-safe

说明

该英文原文是在10/19/2009发布的,作者指出了维基百科关于线程安全的定义十分模糊的问题,但是他没有修改其定义,而是将其留给了其他更加专业的人去修改。一年后,维基百科关于线程安全的定义已经有了更加细节的修正,基本符合了该作者所阐述的观点。

Thread safety is a computer programming concept applicable to multi-threaded code. Thread-safe code only manipulates shared data structures in a manner that ensures that all threads behave properly and fulfill their design specifications without unintended interaction. There are various strategies for making thread-safe data structures
线程安全是计算机编程多线程编程的一个概念。线程安全的代码只会在某种规范下操作共享数据,并确保其他线程的行为是准确的并保证他们的行为是符合其需求的同时其他线程不会对其有意料之外的操作。实现线程安全的数据结构有多种多样的方式。

线程安全(thread safe)是什么?相关推荐

  1. non thread safe php vc11,PHP 中什么线程安全(TS)和非线程安全(NTS)

    显示行号 | 选择喜欢的代码风格 默认 GitHub Dune LakeSide Plateau Vibrant Blue Eighties Tranquil Windows 版的 PHP 从版本 P ...

  2. PHP5 VC9、VC6、Thread Safe、Non Thread Safe各个版本区别

    2019独角兽企业重金招聘Python工程师标准>>> 一.如何选择PHP5.3的VC9版本和VC6版本 网站推广 VC6版本是使用Visual Studio 6编译器编译的,如果你 ...

  3. PHP版本VC6与VC9/VC11/VC14、Thread Safe与None-Thread Safe等的区别

    原文:PHP版本VC6与VC9/VC11/VC14.Thread Safe与None-Thread Safe等的区别 最近正好在弄一个PHP的程序,在这之前一直没有怎么以接触,发现对PHP版本知识了解 ...

  4. php5.6non thread safe 区别,PHP版本Non Thread Safe和Thread Safe如何选择?区别是什么?

    PHP版本分为Non Thread Safe和Thread Safe,Non Thread Safe是指非线程安全,Thread Safe是指线程安全,区别是什么?如何选择? Non Thread S ...

  5. PHP关于VC11,VC9,VC6以及Thread Safe和Non Thread Safe版本选择

    2019独角兽企业重金招聘Python工程师标准>>> 这里是我在搭建php环境时收集的资料供大家参考: 现在PHP官网上下载PHP安装包都有VC11或VC9的字样,这是什么含义,我 ...

  6. PHP 5.3 下载时 VC9、VC6、Thread Safe、Non Thread Safe 是什么意思?

    我最近在 PHP 官网上看到又有新版的 PHP 下载了,于是上去找找 For Windows 的版本,可是一看确傻眼了,一共给了四个版本,VC9 x86 Non Thread Safe.VC9 x86 ...

  7. PHP版本选择讲解:VC6与VC9,Thread Safe与None-Thread Safe等的选择

    October 28, 2010 | 作者:白菜 最近发现很多PHP程序员对PHP版本知识了解不是很清楚,自己也看了不少类似的文章,还是感觉不够明确和全面,网上的结论又都是模棱两可,在此,给出最完整甚 ...

  8. 关于VC9和VC6以及Thread Safe和Non Thread Safe版本选择的问题

    一.如何选择PHP5.3的VC9版本和VC6版本 VC6版本是使用Visual Studio 6编译器编译的,如果你的PHP是用Apache来架设的,那你就选择VC6版本. VC9版本是使用Visua ...

  9. PHP版本VC6与VC9、Thread Safe与None-Thread Safe等的区别

    转载:http://www.cnblogs.com/whoknows/articles/2425841.html 最近发现很多PHP程序员对PHP版本知识了解不是很清楚,自己也看了不少类似的文章,还是 ...

最新文章

  1. 单个神经元不可靠!这项新研究推翻以往认知,感知的最大限制在于解码过程...
  2. webservice获取天气预报异常
  3. idea连接nefu练习数据库
  4. rust游戏解封了吗_柚子君宾馆爬墙听隔壁声,潇天傲解封不罢休!继续专场嘲讽散打哥...
  5. django-行对向的反向查找
  6. python中文叫什么-在python中,quot;~”是什么意思?
  7. img src请求后台值值能判断_MVC中根据后台绝对路径读取图片并显示在IMG中
  8. php post 302,php – Laravel 5.2 Post 302重定向到GET
  9. Java练习 SDUT-1294_选票统计
  10. php本地文件包含 截断,php本地文件包含远程文件包含
  11. 基于python的新闻发布系统
  12. Pikachu靶场之(XSS盲打)
  13. 抖音火了,但MCN却在毁掉整个行业
  14. selenium/requess爬取京东手机商品的详细信息1~selenium练习版
  15. 学会这几招,能找到90%以上的资源
  16. WordPress树叶飘落特效插件1.2
  17. java项目中数据查询慢问题
  18. Android 高德地图 自己位置的显示与点地图上任意一点的坐标
  19. 解读《创业家》2009年中国创新企业榜TOP100
  20. 怎么输出链表最后一个元素_听说AI将是人类最后一个发明?听听他怎么说!

热门文章

  1. android icon红点,android 桌面图标消息红点
  2. Ubuntu 命令行安装Anaconda3(root用户)
  3. FreeRTOS中相对延时和绝对延时的区别
  4. mysql同时更新2个表_mysql中同时update更新多个表
  5. Ubuntu 18.04 修改设置 DNS 并生效的方法
  6. Spring boot 发送手机验证码
  7. c语言程序教师节祝福,2015年教师节祝福语(大学生适用)
  8. 给SQL查询结果加上序号
  9. 基础邮件原理(MUA,MTA,MDA)
  10. JAVA基础 :数据类型