- 原子属性(线程安全),是针对多线程设计的,是默认属性
- 多个线程在写入原子属性时(调用 setter 方法),能够保证同一时间只有一个线程执行写入操作
- 原子属性是一种单(线程)写多(线程)读的多线程技术
- 原子属性的效率比互斥锁高,不过可能会出现脏数据
- 在定义属性时,必须显示地指定 nonatomic,否则默认为atomic
多线程——atomic nonatomic的区别
-
原子性atomic ,默认属性,编译器会在property上自动添加原子锁
非原子性nonatomic,不考虑多线程情况时使用,提高效率 -
原子属性内部的锁是 自旋锁, 自旋锁的执行效率比互斥锁高
-
atomic本质上就是给get/set方法加锁,即原子锁,以避免线程A还没执行完setter,线程B又开始执行的,导致读取数据错误的问题。
-
atomic一定是线程安全的么?
不一定,首先atomic的释义是原子性,并不是线程安全。原子性这个概念表示一个操作序列就像一个操作一样不被打断,而不像一个操作序列一样中间容许被打断。所以nonatomic一定是线程不安全的,但是atomic却不一定是线程安全的。- 假设线程A执行在对某属性get之前线程B release了该属性,会导致程序崩溃。
原子属性内部的锁是
自旋锁,
自旋锁的执行效率比互斥锁高
2.6.2、自旋锁&互斥锁
1
、共同点
- 都能够保证同一时间,只有一条线程执行锁定范围的代码
2
、不同点
- 互斥锁:如果发现有其他线程正在执行锁定的代码,线程会进入休眠状态,等待其他线程执行完毕,打开锁之后,线程会被唤醒
- 自旋锁:如果发现有其他线程正在执行锁定的代码,线程会以死循环的方式,一直等待锁定代码执行完成。
3
、结论
- 自旋锁更适合执行非常短的代码
- 无论什么锁,都是要付出代价
下面附上代码分析
1
、定义原子属性
@property (nonatomic, strong) NSObject *obj1;
@property (atomic, strong) NSObject *obj2;
// 模拟原子属性
@property (atomic, strong) NSObject *obj3;
2
、模拟原子属性
如果重写了 atomic 属性的 setter方法,就必须重新 getter 方法。
- 如果同时重写了 setter 和 getter 方法,苹果就不再提供_成员变量
- @synthesize
合成指令,用处就是指定属性的 成员变量。
@implementation
ViewController
//
合成指令
@synthesize obj2 = _obj2 ;
@synthesize obj2 = _obj2 ;
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//
记录运行时间
开始和结束
CFAbsoluteTime atatrt = CFAbsoluteTimeGetCurrent();
for
(
int
i =
0
; i <
1000
*
1000
; i++) {
self.obj0 = [[NSObject alloc]init]; //创建对象
}
// 记录结束时间
CFAbsoluteTime end = CFAbsoluteTimeGetCurrent ();
NSLog ( @" 非原子性 %f" ,end - atatrt);
// 记录运行时间 开始和结束
atatrt = CFAbsoluteTimeGetCurrent ();
for ( int i = 0 ; i < 1000 * 1000 ; i++) {
// 记录结束时间
CFAbsoluteTime end = CFAbsoluteTimeGetCurrent ();
NSLog ( @" 非原子性 %f" ,end - atatrt);
// 记录运行时间 开始和结束
atatrt = CFAbsoluteTimeGetCurrent ();
for ( int i = 0 ; i < 1000 * 1000 ; i++) {
self
.
obj1
= [[
NSObject
alloc
]
init
];
}
// 记录结束时间
end = CFAbsoluteTimeGetCurrent ();
NSLog ( @" 原子性 %f" ,end - atatrt);
// 记录运行时间 开始和结束
atatrt = CFAbsoluteTimeGetCurrent ();
for ( int i = 0 ; i < 1000 * 1000 ; i++) {
self . obj2 = [[ NSObject alloc ] init ];
}
// 记录结束时间
end = CFAbsoluteTimeGetCurrent ();
NSLog ( @" 模拟原子性 %f" ,end - atatrt);
}
// 原子性属性 如果自己重新写 setter 方法就不会生成 getter 方法了
// 需要重写 get 方法
- ( void )setObj2:( NSObject *)obj2{
@synchronized ( self ) {
_obj2 = obj2;
}
}
- ( NSObject *)obj2{
return _obj2 ;
// 记录结束时间
end = CFAbsoluteTimeGetCurrent ();
NSLog ( @" 原子性 %f" ,end - atatrt);
// 记录运行时间 开始和结束
atatrt = CFAbsoluteTimeGetCurrent ();
for ( int i = 0 ; i < 1000 * 1000 ; i++) {
self . obj2 = [[ NSObject alloc ] init ];
}
// 记录结束时间
end = CFAbsoluteTimeGetCurrent ();
NSLog ( @" 模拟原子性 %f" ,end - atatrt);
}
// 原子性属性 如果自己重新写 setter 方法就不会生成 getter 方法了
// 需要重写 get 方法
- ( void )setObj2:( NSObject *)obj2{
@synchronized ( self ) {
_obj2 = obj2;
}
}
- ( NSObject *)obj2{
return _obj2 ;
}
附上代码
1
、定义原子属性
@property (nonatomic, strong) NSObject *obj1;
@property (atomic, strong) NSObject *obj2;
// 模拟原子属性
@property (atomic, strong) NSObject *obj3;
2
、模拟原子属性
如果重写了 atomic 属性的 setter方法,就必须重新 getter 方法。
- 如果同时重写了 setter 和 getter 方法,苹果就不再提供_成员变量
- @synthesize
合成指令,用处就是指定属性的 成员变量。
@implementation
ViewController
//
合成指令
@synthesize obj2 = _obj2 ;
@synthesize obj2 = _obj2 ;
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//
记录运行时间
开始和结束
CFAbsoluteTime atatrt = CFAbsoluteTimeGetCurrent();
for
(
int
i =
0
; i <
1000
*
1000
; i++) {
self.obj0 = [[NSObject alloc]init]; //创建对象
}
// 记录结束时间
CFAbsoluteTime end = CFAbsoluteTimeGetCurrent ();
NSLog ( @" 非原子性 %f" ,end - atatrt);
// 记录运行时间 开始和结束
atatrt = CFAbsoluteTimeGetCurrent ();
for ( int i = 0 ; i < 1000 * 1000 ; i++) {
// 记录结束时间
CFAbsoluteTime end = CFAbsoluteTimeGetCurrent ();
NSLog ( @" 非原子性 %f" ,end - atatrt);
// 记录运行时间 开始和结束
atatrt = CFAbsoluteTimeGetCurrent ();
for ( int i = 0 ; i < 1000 * 1000 ; i++) {
self
.
obj1
= [[
NSObject
alloc
]
init
];
}
// 记录结束时间
end = CFAbsoluteTimeGetCurrent ();
NSLog ( @" 原子性 %f" ,end - atatrt);
// 记录运行时间 开始和结束
atatrt = CFAbsoluteTimeGetCurrent ();
for ( int i = 0 ; i < 1000 * 1000 ; i++) {
self . obj2 = [[ NSObject alloc ] init ];
}
// 记录结束时间
end = CFAbsoluteTimeGetCurrent ();
NSLog ( @" 模拟原子性 %f" ,end - atatrt);
}
// 原子性属性 如果自己重新写 setter 方法就不会生成 getter 方法了
// 需要重写 get 方法
- ( void )setObj2:( NSObject *)obj2{
@synchronized ( self ) {
_obj2 = obj2;
}
}
- ( NSObject *)obj2{
return _obj2 ;
// 记录结束时间
end = CFAbsoluteTimeGetCurrent ();
NSLog ( @" 原子性 %f" ,end - atatrt);
// 记录运行时间 开始和结束
atatrt = CFAbsoluteTimeGetCurrent ();
for ( int i = 0 ; i < 1000 * 1000 ; i++) {
self . obj2 = [[ NSObject alloc ] init ];
}
// 记录结束时间
end = CFAbsoluteTimeGetCurrent ();
NSLog ( @" 模拟原子性 %f" ,end - atatrt);
}
// 原子性属性 如果自己重新写 setter 方法就不会生成 getter 方法了
// 需要重写 get 方法
- ( void )setObj2:( NSObject *)obj2{
@synchronized ( self ) {
_obj2 = obj2;
}
}
- ( NSObject *)obj2{
return _obj2 ;
}