什么是线程安全?
多线程操作共享数据的时候不会出现意想不到的结果就叫线程安全,否则,就是线程不安全。
原⼦属性是线程安全的吗?
原⼦属性只能保障set 或者 get的读写安全,但我们在使⽤属性的时候,往往既有set⼜有get,所以
说原⼦属性并不是线程安全的。
⾃旋锁和互斥锁的区别
⾃旋锁: 在访问被锁的资源的时候,调⽤者线程不会休眠,⽽是不停循环在那⾥,直到被锁资源释
放锁。(忙等)
互斥锁: 在访问被锁资源时,调⽤者线程会休眠,此时cpu可以调度其他线程⼯作。直到被锁的资
源释放锁。然后再唤醒休眠线程。(闲等)
⾃旋锁的优点在于,因为⾃旋锁不会引起调⽤者线程休眠,所以不会进⾏线程调度,cpu时间⽚轮
转等⼀些耗时的操作。所以如果能在很短的时间内获得锁,⾃旋锁的效率远⾼于互斥锁。
⾃旋锁缺点在于,⾃旋锁⼀直占⽤CPU,在未获得锁的情况下,⼀直⾃旋,相当于死循环,会⼀直
占⽤着CPU,如果不能在很短的时间内获得锁,这⽆疑会使CPU效率降低。 ⽽且⾃旋锁不能实现递归
调⽤ 。
⾃旋锁优先级反转的bug
当多个线程有优先级的时候,如果⼀个优先级低的线程先去访问某个数据,此时使⽤⾃旋锁进⾏了
加锁,然后⼀个优先级⾼的线程⼜去访问这个数据,那么优先级⾼的线程因为优先级⾼会⼀直占着
CPU资源,此时优先级低的线程⽆法与优先级⾼的线程争夺 CPU 时间,从⽽导致任务迟迟完不
成、锁⽆法释放。
由于⾃旋锁本身存在的这个问题,所以苹果在iOS10以后已经废弃了OSSpinLock。
也就是说除⾮⼤家能保证访问锁的线程全部都处于同⼀优先级,否则 iOS 系统中的⾃旋锁就不要去使⽤了。
NSCondition存在的虚假唤醒
当线程从等待已发出信号的条件变量中醒来,却发现它等待的条件不满⾜时,就会发⽣虚假唤醒。
之所以称为虚假,是因为该线程似乎⽆缘⽆故地被唤醒了。但是虚假唤醒不会⽆缘⽆故发⽣:它们
通常是因为在发出条件变量信号和等待线程最终运⾏之间,另⼀个线程运⾏并更改了条件。线程之
间存在竞争条件,典型的结果是有时,在条件变量上唤醒的线程⾸先运⾏,赢得竞争,有时它运⾏
第⼆,失去竞争。
在许多系统上,尤其是多处理器系统上,虚假唤醒的问题更加严重,因为如果有多个线程在条件变
量发出信号时等待它,系统可能会决定将它们全部唤醒,将每个signal( )唤醒⼀个线程视为
broadcast( )唤醒所有这些,从⽽打破了信号和唤醒之间任何可能预期的 1:1 关系。如果有 10 个线
程在等待,那么只有⼀个会获胜,另外 9 个会经历虚假唤醒。
读写锁
读写锁的⽬的:
多读单写:在同⼀时刻可以被多条线程进⾏读取数据的操作,但是在同⼀时刻只能有⼀条线程
在写⼊数据。
读写互斥:在同以时刻,读和写不能同时进⾏。
⽤GCD实现读写锁:
//写
-(void)lg_write:(NSDictionary *)dic {
dispatch_barrier_async(self.iQueue, ^{
[self.dataDic setDictionary:dic];
});
}
//读
-(NSString *)lg_read {
__block NSString *ret;
dispatch_sync(self.iQueue, ^{
ret = self.dataDic[@"name"];
});
NSLog(@"%@",ret);
return ret;
}