多线程
1.多线程
pthread
NSThread
NSOPeration
GCD--支持多核
2.NSThread
(1)
//NSThread多线程的使用
//1.创建线程
#pragma mark - 1.创建线程 -(void)createThread{ //*******顺序执行(串行执行)*/ // [self taskA]; // [self taskB]; //*******并行执行(多个任务同时执行)********/ //创建新的线程 //方式一(创建之后不会立即执行) NSThread *thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(taskA) object:nil]; [thread1 start]; //方式二(创建之后立即执行) //需设置Object:thread1 --> 线程之间的控制与通信 [NSThread detachNewThreadSelector:@selector(taskB:) toTarget:self withObject:thread1]; }
-(void)taskA{ for(int i=0;i<20;i++){ NSLog(@"A = %d",i); // 每次检测是否应该取消 if([NSThread currentThread].isCancelled){ //取出当前线程--> 是否取消(若是,exit线程) [NSThread exit]; //退出线程 } [NSThread sleepForTimeInterval:0.25]; } } -(void)taskB:(NSThread *)thread{ for(int i=0;i<20;i++){ NSLog(@"B = %d",i); if(i==10){ [thread cancel]; //线程B,发送cancel消息 // NSLog(@"tadkB: %@ , thread = %@",[NSThread currentThread],thread); } [NSThread sleepForTimeInterval:0.25]; } }
(2)为何使用多线程,解决什么问题
#pragma mark - 2.为何使用多线程,解决什么问题 -(void)whyUseThread{ //本质: 多线程主要解决 执行耗时任务时出现的UI界面阻塞的问题 // 或同时执行多个任务(如 迅雷) //使用场景: 大麦网 -- 下载数据(耗时5s),图片(耗时10s) // 迅雷加载视频文件 UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem]; [btn setTitle:@"耗时任务" forState:UIControlStateNormal]; btn.frame = CGRectMake(100, 100, 100, 30); [btn addTarget:self action:@selector(startTask:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:btn]; } -(void)startTask:(id)sender{ //http://10.3.8.8/download/真机调试.tar.gz NSString *urlString = @"http://10.3.8.8/download/真机调试.tar.gz"; //只能放在子线程,会卡 NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:urlString]]; NSLog(@"size = %u",data.length); }
(3)使用通知监听线程结束
//3.使用通知监听线程结束 // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dealTheardExit) name:NSThreadWillExitNotification object:nil];
#pragma mark - 3.使用通知监听线程结束 -(void)dealTheardExit{ NSLog(@"线程结束"); }
(4)线程的控制和通信
//4.线程的控制和通信 // A --> i=10时,B stop
(5)
//5.线程的同步锁 //多个线程访问同一块内存 --> 解决(NSLock 锁) _lock = [[NSLock alloc] init]; // [NSThread detachNewThreadSelector:@selector(add) toTarget:self withObject:nil]; // [NSThread detachNewThreadSelector:@selector(sub) toTarget:self withObject:nil];
#pragma mark - 5.线程的同步锁 -(void)add{ for(int i=0;i<1000;i++){ [_lock lock]; //加锁 _num++; NSLog(@"add = %d",_num); [_lock unlock]; //解锁 } } -(void)sub{ for(int i=0;i<1000;i++){ [_lock lock]; _num--; NSLog(@"sub = %d",_num); [_lock unlock]; } }
(6)
//6.子线程如何更新UI(very import) //限制 : UI线程--> 主线程 // 其他创建的线程--子线程 // 注:不要在子线程直接操作UI--> 让主线程操作 //下载进度更新 // [NSThread detachNewThreadSelector:@selector(downloadNetWorkData) toTarget:self withObject:nil]; // [self downloadNetWorkData]; _progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(10, 200, 300, 20)]; [self.view addSubview:_progressView];
#pragma mark - 6. -(void)downloadNetWorkData{ for(int i=0;i<100;i++){ [self performSelectorOnMainThread:@selector(updateUI) withObject:nil waitUntilDone:YES]; //在主线程里改变UI [NSThread sleepForTimeInterval:0.1]; // } }
3.NSOperation
//************************NSOperation使用************************/ //***1.NSOperation --> NSThread类似,实现多线程的机制。。更抽象,加入了block,更简单易用 //***2.NSOperation抽象类-->NSInvocationOperation,NSBlockOperation //NSInvocationOperation NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task1) object:nil]; // [invocationOperation start]; //创建之后需要执行-->start ,默认同步执行 //NSBlockOperation NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{ for(int i=0;i<20;i++){ NSLog(@"B = %d",i); } }]; // [blockOperation start]; //同上,默认同步执行 //NSOperationQueue --> 操作队列,任务列表(注:异步平行执行) NSOperationQueue *queue = [[NSOperationQueue alloc] init]; [queue addOperation:invocationOperation]; //添加队列 [queue addOperation:blockOperation];
4.GCD
//*****GCD的使用 --> Grand Central Dispatch *******/ // 好处: 1.支持多核; 2.C和block,易于使用 ; 3.较晚出现,功能强大,使用多 //1.GCD 创建异步任务 // [self createAsyncTask]; //2.模拟网络下载 // [self simulateNetWorkDownload]; //3.只执行一次 [self runOnce]; //4.延迟执行 [self delayRun]; //5.同时执行多个任务,等待所有任务执行完成进行处理 //eg: 迅雷所有任务完成自动关机 [self groupRun];
#pragma mark - 5.同时执行多个任务,等待所有任务执行完成进行处理 -(void)groupRun{ //group dispatch_group_t group = dispatch_group_create(); //添加到group //添加任务 7s dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ for(int i=0;i<100;i++){ NSLog(@"A = %d",i); [NSThread sleepForTimeInterval:0.07]; } }); // 5s dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ for(int i=0;i<100;i++){ NSLog(@"B = %d",i); [NSThread sleepForTimeInterval:0.05]; } }); // 10s dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ for(int i=0;i<100;i++){ NSLog(@"C = %d",i); [NSThread sleepForTimeInterval:0.1]; } }); // dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSLog(@"自动关机"); }); } #pragma mark - 4.延迟执行 -(void)delayRun{ //延迟5s 执行 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSLog(@"he he he"); }); } #pragma mark - 3.只执行一次 -(void)runOnce{ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSLog(@"只执行一次的代码"); }); } #pragma mark - 2.模拟网络下载 -(void)simulateNetWorkDownload{ UIProgressView *progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(10, 100, 300, 20)]; [self.view addSubview:progressView]; //GCD开启最简单的异步任务下载 主线程 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(queue, ^{ //在子线程中执行 for(int i=0;i<100;i++){ //返回主线程执行 dispatch_async(dispatch_get_main_queue() , ^{ progressView.progress += 0.01; NSLog(@"progress = %f",progressView.progress); }); [NSThread sleepForTimeInterval:0.1]; } //最后显示对话框(子线程--> 需要切回main) dispatch_async(dispatch_get_main_queue(), ^{ UIAlertView *alert = [[UIAlertView alloc] init]; alert.message = @"下载完成"; [alert addButtonWithTitle:@"取消"]; [alert show]; }); }); } #pragma mark - 1.GCD 创建异步任务 -(void)createAsyncTask{ //参数1: dispatch_queue_t queue --> 有3种queue // mian_queue 主队列(主线程), glabel_queue 全局队列(工作线程),自定义queue //参数2: ^(void)block dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //执行异步任务 dispatch_async(queue, ^{ for(int i=0;i<20;i++){ NSLog(@"A = %d",i); } }); dispatch_async(queue, ^{ for(int i=0;i<20;i++){ NSLog(@"B = %d",i); } }); }