在这个网站介绍了多线程的安全隐患http://blog.youkuaiyun.com/u012745229/article/details/50939252
买票问题
使用互斥锁:
@interface ViewController ()
//总票数
@property(nonatomic,assign)int tickets;
@end
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
//剩余20张票
self.tickets=20;
//增加子线程
NSThread *threadA=[[NSThread alloc] initWithTarget:self selector:@selector(saleTickes) object:nil];
threadA.name=@"买票员A";
[threadA start];
NSThread *threadB=[[NSThread alloc] initWithTarget:self selector:@selector(saleTickes) object:nil];
threadB.name=@"买票员B";
[threadB start];
}
/*
加锁,互斥锁
加锁,锁定的代码尽量少
加锁范围内的代码,同意四件只运行一个线程执行
互斥锁的参数,任何继承NSObject *对象都可以,
有保证这个锁,所以得线程都能访问到,而且是所有线程访问的是同一个锁
*/
-(void)saleTickes
{
while (YES)
{
//模拟一下延时,买票一张休息1秒
[NSThread sleepForTimeInterval:1.0];
//苹果不推荐我们使用 因为加了锁性能会很差
/*
优缺点
有点可以解决数据访问的资源共享问题
缺点;需要消耗大量的CPU资源
*/
@synchronized(self)//在哪个对象创建一把锁<----
{
//判断是否还有票
if (self.tickets>0)
{
//2.如果有票,就买一张
self.tickets--;
NSLog(@"剩余的票数--%d--%@",self.tickets,[NSThread currentThread]);
}
else
{
NSLog(@"没有票");
break;
}
}
}
}
为什么在开发中不常使用互斥锁呢
一般买票的时候票数是通过服务器访问数据库查询的来的
除非你把互斥锁加到服务器上
就是你在手机应用上加锁互斥锁带其他通过安卓手机或者网站访问的没有互斥锁
所以苹果建议我们使用“自旋锁”
@interface ViewController ()
//总票数
@property(nonatomic,assign)int tickets;
@property(atomic,strong)NSObject *obj;
// nonatomic 非原子属性
//atomic 原子属性默认属性
//原子属性就是针对多线程设计的,原子属性实现单(线程)写多(线程)读
//因为写的安全级别有钱更高,读的要求低一点,可以多度几次保证正确性
@end
@synthesize obj=_obj;
-(NSObject *)obj
{
return _obj;
}
/*
线程安全的概念
就是在多个线程同时执行的时候,能够保证资源的信息的准确性
“UI线程---主线程”
UIKit绝大部分的类,都不是“线程安全”的
怎么解决这个线程不安全的问题?
苹果约定,所以程序的更新UI都在主线程进行 所以得UI都在主线程更新这就不会同时改变一个资源
在主线程更新UI,的好处
1.只在主线程更新UI,一就不会出现多线程同时改变同一个UI控件
2.主线程的优先级最高,也就意味着UI的更新优先级高,会让用户感觉和流畅
*/
//atomic情况下,只要写了set方法,getter也的重写
-(void)setObj:(NSObject *)obj
{
//原子苏醒内部使用的 自旋锁
//自旋锁和互斥锁
//共同点;都可以缩短一段代码,同一时间,只有线程能执行这对锁定的代码
//区别:互斥锁,在锁定的时候,其他线程进入睡眠,等待条件满足在唤醒
//自旋锁:在锁定的时候,其他线程做死循环,一直正待这个条件满足,一旦满足里面执行,少了唤醒
@synchronized(self)
{
_obj=obj;
}
}