iOS核心笔记——多线程-原子/非原子属性
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS核心笔记——多线程-原子/非原子属性相关的知识,希望对你有一定的参考价值。
1、原子属性:
1-1、nonatomic与atomic:
nonatomic
: 非原子属性;
atomic
: 原子属性;
- 线程安全的,针对多线程设计的属性修饰符,是默认值.
- 保证同一时间只有一个线程能够写入,但是同一个时间多个线程都可以读取;
- 单写多读 : 单个线程写入
write
,多个线程可以读取read
; atomic
本身就有一把锁,自旋锁
。
1-2、nonatomic
和atomic
对比:
nonatomic
: 非线程安全,适合内存小的移动设备;
atomic
: 线程安全,需要消耗大量的资源.性能比非原子属性要差。
1-3、ios开发的建议:
- 所有属性都声明为
nonatomic
,性能更高; - 尽量避免多线程抢夺同一块资源;
- 尽量将加锁、资源抢夺的业务逻辑交给服务器端处理,减小移动客户端的压力。
2、模拟原子属性:
2-1、定义属性:
1./// 非原子属性
[email protected] (nonatomic,strong) NSObject *obj1;
3./// 原子属性:内部有"自旋锁"
[email protected] (atomic,strong) NSObject *obj2;
5./// 模拟原子属性
[email protected] (atomic,strong) NSObject *obj3;
?了解:
重写非原子属性的setter
和getter
方法:
?了解:
1、重写了原子属性的setter
方法之后,会覆盖原子属性内部的自旋锁
,使其失效;然后我们加入互斥锁
,来模拟单写多读
。
?了解:
2、重写了属性的setter
和getter
方法之后,系统就不会再帮我们生成待下划线的成员变量;使用合成指令@synthesize
,就可以手动的生成带下划线的成员变量。
示例程序:
1.// 合成指令
[email protected] obj3 = _obj3;
3.
4./// obj3的setter方法
5.- (void)setObj3:(NSObject *)obj3
6.{
7. @synchronized(self) {
8. _obj3 = obj3;
9. }
10.}
11.
12./// obj3的getter方法
13.- (NSObject *)obj3
14.{
15. return _obj3;
16.}
2-2、性能测试:
1./// 测试"非原子属性","互斥锁","自旋锁"的性能
2.- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
3.{
4. NSInteger largeNum = 1000*1000;
5.
6. NSLog(@"非原子属性");
7. CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
8. for (int i = 0; i < largeNum; i++) {
9. self.obj1 = [[NSObject alloc] init];
10. }
11. NSLog(@"非原子属性 => %f",CFAbsoluteTimeGetCurrent()-start);
12.
13. NSLog(@"原子属性");
14. start = CFAbsoluteTimeGetCurrent();
15. for (int i = 0; i < largeNum; i++) {
16. self.obj2 = [[NSObject alloc] init];
17. }
18. NSLog(@"原子属性 => %f",CFAbsoluteTimeGetCurrent()-start);
19.
20. NSLog(@"模拟原子属性");
21. start = CFAbsoluteTimeGetCurrent();
22. for (int i = 0; i < largeNum; i++) {
23. self.obj3 = [[NSObject alloc] init];
24. }
25. NSLog(@"模拟原子属性 => %f",CFAbsoluteTimeGetCurrent()-start);
26.}
3、互斥锁和自旋锁对比:
3-1、共同点:
- 都能够保证同一时间,只有一条线程执行锁定范围的代码
3-2、不同点:
互斥锁
:如果发现有其他线程正在执行锁定的代码,线程会进入休眠
状态,等待其他线程执行完毕,打开锁之后,线程会重新进入就绪
状态;等待被CPU重新调度。
自旋锁
:如果发现有其他线程正在执行锁定的代码,线程会以死循环
的方式;一直等待锁定代码执行完成。
4、开发建议:
- 所有属性都声明为
nonatomic
,原子属性和非原子属性的性能几乎一样。
- 尽量避免多线程抢夺同一块资源。
- 要实现线程安全,必须要用到
锁
;无论什么锁,都是有性能消耗的。
- 自旋锁更适合执行非常短的代码,死循环内部不适合写复杂的代码。
- 尽量将加锁,资源抢夺的业务逻辑交给服务器端处理,减小移动客户端的压力。
- 为了流畅的用户体验,UIKit类库的线程都是不安全的;所以我们需要在主线程(UI线程)上更新UI。
- 所有包含
NSMutable
的类都是线程不安全的,在做多线程开发的时候,需要注意多线程同时操作可变对象的线程安全问题。
以上是关于iOS核心笔记——多线程-原子/非原子属性的主要内容,如果未能解决你的问题,请参考以下文章
阿里年薪80W架构师2W字多线程进阶(线程池原子性并发工具类)超详细笔记