atomic & nonatomic

2021-07-21  本文已影响0人  小李不木

什么是线程安全???

线程安全:多线程操作共享数据不会出现想不到的结果就是线程安全的,否则,是线程不安全的。

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

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

atomic属性的setter/getter方法都被加了spinlock自旋锁,需要注意的是spinlock已经由于存在优先级反转问题被弃用并用os_unfair_lock替代。

atomic所说的线程安全只是保证了getter和setter存取方法的线程安全,并不能保证整个对象是线程安全的。

给set和get方法加了锁,锁并不能『保证线程安全』,这样紧紧只是保证了读写线程安全,但是真正的线程安全还要包含其他的操作,比如release。如果在当前线程访问另一个线程已经release的变量,可能会crash掉的,那么很明显,atomic并不能真的保证线程安全。

省略atomic 的情况下,默认就是atomic。 

而atomic 和 nonatomic 的区别在于,系统自动生成的getter 和 setter 方法不一样。如果我们自己实现getter/setter方法,那么 atomic/nonatomic/retain/assign/copy等这些关键字只起到提示作用,写不写都是一样的。 

对于atomic 的属性,系统生成的getter/setter会保证get/set操作的完整性,不受其他线程影响。如果有多个线程同时调用setter的话,不同线程上的操作都将依次顺序执行,如果一个线程正在执行getter/setter,其他线程就得等待。因此,属性是读写安全的,可以保证数据的完整性。

比如,线程A的getter方法运行到一半,线程 B 调用了setter,那么线程A的getter 还是能得到一个完好无损的对象(可以保证数据的完整性),但这个对象在多线程的情况下是不能确定的,因为你不知道多线程的调用顺序,也就无法判断最终的值是什么。

举例来说,如果线程A调用getter的同时,线程B、线程C都在调用setter,那么线程Aget 到的值有三种可能:可能线程A先执行,那么获取到的就是线程B、C set 之前的值;也可能是B 线程 set 的值; 也可能是 线程 C set 的值。

但是,如果有另一个线程D 同时再调[name release],会并发执行,那可能就会crash,因为release 不受getter/setter 操作的限制。也就是说,这个属性只能说是读/写安全的,但并不是线程安全的,因为别的线程还能进行读写之外的其他操作。线程安全需要开发者自己来保证,我们还要为对象线程添加lock来确保线程的安全。

如果是 nonatomic的,那么上面的所有线程都可以同时执行,可能导致无法预料的结果。

nonatimic属性的set方法,ARC环境下,如果有两个线程同时给属性设置值时,就会同时把属性给release释放两次。过渡释放造成崩溃

属性是atomic时,不会崩溃,里面加了同步锁,set,get方法只能串行执行。

三、查看 atomic 底层代码

有一个 objc-accessors.mm 文件。

(一)setter 方法的底层实现

可以查看 objc_setProperty(***) 方法 ,这个对应的是 setter 方法

在set方法中可以看到 reallySetProperty(***) 方法

可以看到 有一个 是否 使用了atomic 的 if 判断语句

sette加锁

如果不是 atomic,也就是 如果用的是 nonatomic

*slot = newValue; 代码的意思 : 直接将最新的值赋值给 *slot

*slot 可以认为是内存地址

如果是 atomic

有一个自旋锁 : spinlock_t

加锁操作

代码赋值

解锁操作

(二)getter 方法底层实现

getter加锁
上一篇 下一篇

猜你喜欢

热点阅读