多线程
主线程:当程序开始执行的时候,系统会为我们自动开启一个线程,这个线程就叫做主线程
子线程:程序猿手动开辟的线程
线程存在的意义:执行耗时操作的任务
子线程在执行完耗时操作后会自动销毁
开启线程的三种方式
1 创建一个线程
NSThread*thread = [[NSThreadalloc]initWithTarget:selfselector:@selector(haoshiCaozuo)object:@"789"];
thread.name=@"asfsdf";
[threadstart]; 线程开始start 线程取消cancel 线程作为主线程main
2 快捷创建
[NSThreaddetachNewThreadSelector:@selector(haoshiCaozuo)toTarget:selfwithObject:nil];
3隐式开启线程
[selfperformSelectorInBackground:@selector(haoshiCaozuo)withObject:nil];
多线程的分类
pthread的简单认识 使用前导入框架#import
pthread_create(线程指针,线程的一些属性,函数指针(用于执行方法),线程的传值)
函数指针--》执行方法
void*run(void*papapa)
{
for(NSIntegeri =0; i <10000; i++) {
NSLog(@"sdgfd");
}//开辟多线程区执行代码
returnNULL;
}
pthread_t pthread;
pthread_create(&pthread, NULL, run, NULL);
线程的主要方式
前两种 pthread NSThread(如上所示)
第三种 NSoperation
NSOperation 是一个抽象的类,我们一般不是直接使用它,一般使用的时他的两个子类
NSInvocationOPeration(只封装了target) 和 NSblockOperation(封装了@select方法)
一般情况下,如果他们单独使用的话,一般都是在主线程执行的,只有当和队列一起执行的时候才会在子线程执行
1 创建线程
线程1 NSInvocationOperation*opreation1 = [[NSInvocationOperationalloc]initWithTarget:selfselector:@selector(operationAction1)object:nil];
线程2 NSInvocationOperation*operation2 = [[NSInvocationOperationalloc]initWithTarget:selfselector:@selector(operationAction2)object:nil];
线程3NSBlockOperation*operation3 = [NSBlockOperationblockOperationWithBlock:^{
for(NSIntegeri =20; i <30; i++) {
NSLog(@"aaa");
}
}];
正常情况下,线程创建完成后需要【Operation start]才能执行 但是加入队列就不一样了
操作队列的目的
是将我们的任务放在一个队列执行任务:执行在主线程还是在子线程全部都是由我们的队列决定的好处:不用开启在队列中就可以直接开启了可以没有[opreation1 start];
加入队列后线程的执行顺序
加入到队列(排队先加的先执行后加的后执行但是执行的时间不一定可能后执行的比先执行的先执行完但是执行代码的时候不确定了方法肯定是先加先运行)
2 创建队列两种方式
NSOperationQueue *queue = [NSIOperationQueue mainqueue] 创建主队列
NSoperationQueue *queue = [[NSOperationQueue alloc] init] 创建其他队列
3 设置队列最大执行的线程数目 如果为0 则不会执行
queue.maxConcurrentOperationCount=3;
将线程加入到队列内 先加先执行 后加后执行 但是线程执行的时间可能不一样,可能后执行的线程先执行完。
第四种 GCD
全称 Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法 伟大的中枢调度器
概念:异步-不在同一个线程上执行 同步-在同一个线程上执行 串行-串在一起执行(糖葫芦串) 并行-一起执行(走正步)
并行队列global dispatch queue,通过dispatch_get_global_queue获取,由系统创建三个不同优先级的dispatch queue。并行队列的执行顺序与其加入队列的顺序相同
串行队列serial queues一般用于按顺序同步访问,可创建任意数量的串行队列,各个串行队列之间是并发的
当想要任务按照某一个特定的顺序执行时,串行队列是很有用的。串行队列在同一个时间只执行一个任务。我们可以使用串行队列代替锁去保护共享的数据。和锁不同,一个串行队列可以保证任务在一个可预知的顺序下执行。
主要有六种情况
1 同步 + 主队列 (错误的演示,主队类也是一种串行,既然是串行,又怎么能同步呢)
线程的安全问题(卖票问题)
本意:就是开辟多个线程,但是多个线程执行的都是同一个事件,但是这个事件的执行线程之间并不知道,所以就产生线程安全问题
解决方案就是在事件加线程锁,让每一个线程按照顺序执行事件,但是执行顺序是随机的
1 创建多个线程
NSThread *thread1 =[[NSThreadalloc]initWithTarget:selfselector:@selector(saleTicket)object:nil];
NSThread *thread2 =[[NSThreadalloc]initWithTarget:selfselector:@selector(saleTicket)object:nil];
NSThread *thread3 =[[NSThreadalloc]initWithTarget:selfselector:@selector(saleTicket)object:nil];
2 添加触发方法(这个根据实际情况来设定)
这个方法也是UIResponder里面的,UIResponder类有很多的方法,响应事件的方法
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent*)event
{
[thread1start];
[thread2start];
[thread3start];
}
3 卖票的方法(加线程锁)
- (void)saleTicket
{
NSLog(@"%@",self);self是本类的意思 因为之前在ViewController上建立的 所以self打印出出来是viewController
while(1) {
NSObject *object = [[NSObject alloc] init];
线程锁唯一的只能有一把通常token写成self
@synchronized(self) { (self)是在什么地方加入线程锁, 固定写法
NSIntegercount =self.TicketCount; count是剩余票的数目
if(count >0) {
self.TicketCount= count -1;
[NSThreadsleepForTimeInterval:1];
NSLog(@"%@ %zd",[NSThreadcurrentThread],self.TicketCount);
}else{
NSLog(@"票卖完了");
break;
}
}
}
}