iOS基础知识总结--atomic为什么不是线程安全

概述:

1、原子操作对线程安全并无任何安全保证。被atomic修饰的属性(不重载设置器和访问器)只保证了对数据读写的完整性,也就是原子性,但是与对象的线程安全无关。

2、线程安全已经有保障情况下、对性能也有要求的情况下可使用nonatomic替代atomic,当然也可以一直使用atomic。

描述:

首先我要纠正一个网上常见的关于atomic非线程安全的举例:如果线程 A 调了 getter,与此同时线程 B 、线程 C 都调了 setter——那最后线程 A get 到的值,有3种可能:可能是 B、C set 之前原始的值,也可能是 B set 的值,也可能是 C set 的值。同时,最终这个属性的值,可能是 B set 的值,也有可能是 C set 的值。所以atomic可并不能保证对象的线程安全。

类似的这个例子相信很多人都见过,看起来也非常合理,没什么错;但细琢磨,这个例子本身没问题,但根本不能证明atomic的非线程安全这个观点!所以面试的时候如果举这个例子!(说明你就没明白atomic的非线程安全性)

首先你得知道什么是线程不安全,线程的不安全是由于多线程访问和修改共享资源而引起的不可预测的结果(有可能crash)。可以简单理解为我们拿到的值是错的。这个例子中,如果线程A getter到的值是个错误的值才能说是线程不安全的,可是这个例子就算线程A可能取到好几种值,你能说取值不对吗;不能。所以这个例子是个错误的例子!

atomic的原子性和nonatomic的非原子性

atomic :系统自动生成的getter/setter方法会进行加锁操作;可以理解过读写锁,可以保证读写安全;较耗时;

nonatomic : 系统自动生成的getter/setter方法不会进行加锁操作;但速度会更快;

下面是两个nonatomic和atomic修饰的变量,我们用代码掩饰其内部实现;


nonatomic和atomic修饰的变量代码实现

atomic的原子性和nonatomic的非原子性官方解释

原子的(默认)

--原子是默认设置:如果您不输入任何内容,则您的属性是原子的。

--原子属性可以保证,如果您尝试从中读取内容,则将取回有效值。

--它不能保证该值是多少,但是您将获得合法有效的数据,而不仅仅是垃圾内存(又叫脏数据)。

--这允许您执行的操作是,如果您有多个线程或多个进程指向一个变量,则一个线程可以读取而另一个线程可以写入。

--如果它们同时命中,则保证读取器线程获得两个值之一:更改之前或更改之后。

--原子不会给您带来任何保证,您可能会获得其中哪些值。

--原子通常确实与线程安全混淆,这是不正确的。

--您需要以其他方式保证线程安全。但是,atomic可以保证,如果您尝试读取数据,则肯定会获得某种合法数据。

非原子

--另一方面,您可能会猜到,非原子意味着“不要做原子的事情”。

--您所失去的是保证您总是能得到一些回报。

--如果尝试在写入过程中进行读取,则可能会获取垃圾数据。

--但是,另一方面,您走得更快。

--因为原子属性必须做一些魔术(递归锁)才能保证您将获得一个值,所以它们要慢一些。

--如果这是您经常访问的属性,则可能需要降低为非原子属性,以确保不会造成速度损失。

分析atomic为什么不是线程安全

其实现在一想很奇怪,为什么要把atomic和线程安全联系在一起去探究;atomic只是对属性的getter/setter方法进行了加锁操作,这种安全仅仅是get/set的读写安全,仅此之一,但是线程安全还有除了读写的其他操作,比如:当一个线程正在get/set时,另一个线程同时进行release操作,可能会直接crash。很明显atomic的读写锁不能保证线程安全。 下面两个例子写的就挺好,挺简单:

eg1:如果定义属性NSInteger i是原子的,对i进行i = i + 1操作就是不安全的; 因为原子性只能保证读写安全,而该表达式需要三步操作:

1、读取i的值存入寄存器;

2、将i加1;

3、修改i的值;

如果在第一步完成的时候,i被其他线程修改了,那么表达式执行的结果就与预期的不一样,也就是不安全的

 eg2:


结果可能是[10000,20000]之间的某个值,而我们想要的结果是20000;很明显这个例子就会引起线程隐患,而atomic并不能防止这个问题;所以我们说atomic不是线程安全;


扩展:探索nonatomic非线程安全的原因

为什么nonatomic是非线程安全的,我们来看看runtime的源码:


runtime-get


runtime-set

根据源码,我们可以看到,getter是不会对属性进行retain的,假设当getter执行后,切换到另一个线程,执行setter,setter会对oldValue release,导致oldValue释放。再切回执行getter的线程,getter用到的是已经释放的oldValue。就会发生EXC_BAD_ACCESS的crash。

一般情况下,getter执行后,会在外部对getter获取的属性进行retain,也就是调用objc_retain。但是也许就在getter发生之后,objc_retain之前其他线程执行了setter。这时候,就会导致objc_retain产生EXC_BAD_ACCESS。

那么atomic会不会发生问题呢?根据源码,在获取到属性时,atomic下getter会立即对value进行retain,即使setter对oldValue release了。由于getter已经进行retain,属性不会立即释放。只有使用完成之后才会释放。所以atomic在操作属性的时候可以保证不会crash。


再次来个总结:

nonatomic在线程间切换操作属性的时候容易造成crash,是不安全的。

atomic在线程间切换操作属性可以保证不会crash,也会get到合法的有效数据,但是并不能保证获取的数据就是你的预期值。也是不安全的。


借鉴文章:

谈nonatomic非线程安全问题

从源代码理解atomic为什么不是线程安全

atomic 与 nonatomic 与 线程安全到底什么关系?

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容