nonatomic 带来的线程安全问题
一、结论
一个对象对外暴露的读写属性,如果这个属性在多个线程中访问,可能会出现crash。因此对外暴露的属性一定要考虑线程安全问题。
二、看下面的代码
#import "ViewController.h" #import <malloc/malloc.h> #import <objc/runtime.h> @interface ViewController () @property (nonatomic,copy) NSString *name; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. dispatch_queue_t queue = dispatch_queue_create("abcde", DISPATCH_QUEUE_CONCURRENT); for (int i = 0 ; i < 10000; i ++) { dispatch_async(queue, ^{ NSLog(@"%@",[NSThread currentThread]); self.name = [NSString stringWithFormat:@"我%d",i]; }); } } @end
分析:
属性的set方法,ARC环境下,如果有两个线程同时给属性设置值时,就会同时把属性给release释放两次。过渡释放造成崩溃
属性是atomic时,不会崩溃,里面加了同步锁,set,get方法只能串行执行。
三、现象
产生的现象是一个线程访问这个对象的时候,这个对象已经释放,可能是错误的内存、野指针等情况。
其他解决方式:
其一:改为串行队列
dispatch_queue_t queue = dispatch_queue_create("abcde", DISPATCH_QUEUE_SERIAL); for (int i = 0 ; i < 10000; i ++) { dispatch_async(queue, ^{ NSLog(@"%@",[NSThread currentThread]); self.name = [NSString stringWithFormat:@"我%d",i]; }); }
其二:改为同步执行
dispatch_queue_t queue = dispatch_queue_create("abcde", DISPATCH_QUEUE_CONCURRENT); for (int i = 0 ; i < 10000; i ++) { dispatch_sync(queue, ^{ NSLog(@"%@",[NSThread currentThread]); self.name = [NSString stringWithFormat:@"我%d",i]; }); }
其三:加锁
NSLock *lock = [[NSLock alloc] init]; dispatch_queue_t queue = dispatch_queue_create("abcde", DISPATCH_QUEUE_CONCURRENT); for (int i = 0 ; i < 10000; i ++) { [lock lock]; dispatch_async(queue, ^{ NSLog(@"%@",[NSThread currentThread]); self.name = [NSString stringWithFormat:@"我%d",i]; [lock unlock]; }); }
其四:将字符串改为短的,变为标记指针 NSTaggedPointerString 类型,retain/release不起作用。如果字符串长度大于9或者如果有中文或其他特殊符号(可能是非 ASCII 字符)存在的话则会直接成为 __NSCFString 类型,__NSCFString与其他oc对象一样维护retainCount
dispatch_queue_t queue = dispatch_queue_create("abcde", DISPATCH_QUEUE_CONCURRENT); for (int i = 0 ; i < 10000; i ++) { dispatch_async(queue, ^{ NSLog(@"%@",[NSThread currentThread]); self.name = [NSString stringWithFormat:@"%d",i]; }); }
其五:将字符串改为 __NSCFConstantString 类型,retain/release不起作用(程序中内容相同的常量字符串只有一个)
dispatch_queue_t queue = dispatch_queue_create("abcde", DISPATCH_QUEUE_CONCURRENT); for (int i = 0 ; i < 10000; i ++) { dispatch_async(queue, ^{ self.name = @"哈哈哈哈哈哈哈哈哈哈哈哈"; }); }
在北京的灯中,有一盏是我家的。这个梦何时可以实现?哪怕微微亮。北京就像魔鬼训练营,有能力的留,没能力的走……
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性