简介
修饰属性的关键字中,有一对描述原子性的关键字,即atomic
和nonatomic
。这两个关键字用于表示属性的getter/setter
过程是否为原子性操作。所谓原子性,即线程安全与否。多线程环境下,一段代码在执行过程中,不能被其他代码打断,则是原子性的。
主要看一下在MRC环境下,atomic
与nonatomic
的不同。
nonatomic
@property (nonatomic, retain) NSString *name;
//setter
- (void)setName:(NSString *)obj {
if (name != obj) {
[name release];
name = [obj retain];
}
}
//getter
- (NSString *)name {
return name;
}
atomic
@property (retain) NSString *name;
//setter
- (void)setName:(NSString *)obj {
[_lock lock];
if (name != obj) {
[name release];
name = [obj retain];
}
[_lock unlock];
}
//getter
- (NSString *)name {
[_lock lock];
NSString *tmp = [[name retain] autorelease];
[_lock unlock];
//在return tmp之前,已经unlock解锁了,此时很有可能name指向的内存被释放掉
//所以这里做了一个retain + autorelease的操作
//保证在执行return tmp代码时,name所指向的那块儿内存没有被释放掉
//autorelease则会在return执行完毕后,自动释放。
return tmp;
}
atomic线程不安全
看了很多资料都说atomic
线程不安全,所以就很好奇既然线程不安全,为什么还要说atomic
是原子性的呢?
首先要搞清楚的一点:atomic是保证对一个实例变量的getter/setter过程是原子性的
就是只针对读、写这两个操作是线程安全的。但是也只能保证读和写这两个过程不被打断。
所谓的atomic
线程不安全,先来看一下很多博客用来举例的代码:
@property (retain) NSString *name;
...
//thread A
self.name = @"a";
//thread B
self.name = @"b";
//thread A
NSLog(@"%@", self.name);
上述例子,最后得到的结果肯定是name = b。即在线程A写完name的之后,被线程B将name的值更新了,然后线程A再读取时,读到的是被线程B更新过的值,即线程不安全。
但是通过这个问题来证明atomic
是不安全的,其实有点冤枉atomic
了,因为atomic
的作用只是保证self.name = @"x"
这个过程不被打断,对于线程之间把name作为共享变量,并且想要保证线程安全,自然要单独做互斥操作了。