前言
共享状态,多线程共同访问某个对象的property,在iOS编程里是很普遍的使用场景,我们就从Property的多线程安全说起。
Property
当我们讨论property多线程安全的时候,很多人都知道给property加上atomic attribute之后,可以一定程度的保障多线程安全,类似:
@property (atomic, strong) NSString* userName;
事情并没有看上去这么简单,要分析property在多线程场景下的表现,需要先对property的类型做区分。
我们可以简单的将property分为值类型和对象类型,值类型是指primitive type,包括int, long, bool等非对象类型,另一种是对象类型,声明为指针,可以指向某个符合类型定义的内存区域。
上述代码中userName明显是个对象类型,当我们访问userName的时候,访问的有可能是userName本身,也有可能是userName所指向的内存区域。
比如:
self.userName = @"peak";
是在对指针本身进行赋值。而
[self.userName rangeOfString:@"peak"];
是在访问指针指向的字符串所在的内存区域,这二者并不一样。
所以我们可以大致上将property分为三类:

分完类之后,我们需要明白这三类property的内存模型。
Memory Layout
当我们讨论多线程安全的时候,其实是在讨论多个线程同时访问一个内存区域的安全问题。针对同一块区域,我们有两种操作,读(load)和写(store),读和写同时发生在同一块区域的时候,就有可能出现多线程不安全。所以展开讨论之前,先要明白上述三种property的内存模型,可用如下图示:

以64位系统为例,指针NSString*是8个字节的内存区域,int count是个4字节的区域,而@“Peak”是一块根据字符串长度而定的内存区域。
当我们访问property的时候,实际上是访问上图中三块内存区域。
self.userName = @"peak";
是修改第一块区域。
self.count = 10;
是在修改第二块区域。
[self.userName rangeOfString:@"peak"];
是在读取第三块区域。
不安全的定义
明白了property的类型以及他们对应的内存模型,我们再来看看不安全的定义。Wikipedia如是说:










