二、
安全
一旦線程中止死亡了,就不能再啓動。因此線程NSThread不能爲全局變量多線程
1.第一種方法:直接建立,手動啓動 NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(download:) object:@"www.baidu.com"]; [thread start]; 2.第二種方法:建立後當即啓動 [NSThread detachNewThreadSelector:@selector(download) toTarget:self withObject:@"www.baidu.com"]; 3.第三種方法:隱式建立 //主線程 [self performSelector:@selector(download:) withObject:@"www.baidu.com"]; //子線程 [self performSelectorInBackground:@selector(download:) withObject:@"www.baidu.com"]; object是selector方法傳遞的參數 -(void)download:(NSString *)url { NSLog(@"download-- %@ %@",url,[NSThread currentThread]); }
延遲執行不要勇sleep,壞處:卡住主線程 1.第一種 [NSThread sleepForTimeInterval:5.0]; 2.第二種 NSDate *date = [NSDate dateWithTimeIntervalSinceNow:3.0]; [NSThread sleepUntilDate:date];
+(void)exit
+(NSThread *)mainThread; +(NSThread *)currentThread -(BOOL)isMainThread; +(BOOL)isMainThread;
在1個進程中,線程每每不是孤立存在的,多個線程之間須要常常進行通訊。體如今兩個方面:一,1個線程的數據傳遞給另外一個線程。二,在1個線程中執行完特定任務後,轉到另外一個線程繼續執行任務
併發
-(void)download:(NSString *)url { NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]]; UIImage *image = [UIImage imageWithData:data]; [self performSelectorOnMainThread:@selector(pic:) withObject:image waitUntilDone:YES]; } -(void)pic:(UIImage *)image { NSLog(@"pic:%@",image); self.imageView.image = image; } -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [self performSelector:@selector(download:) withObject:@"http://g.hiphotos.baidu.com/image/h%3D200/sign=f23ec3ed1fd8bc3ed90801cab289a6c8/7a899e510fb30f24dc189ad4ce95d143ac4b0362.jpg"]; }
同步:只能在當前線程中執行任務,不具有開啓新線程的能力異步
異步:能夠在新的線程中執行任務,具有開啓新線程的能力async
併發:可讓多個任務併發(同時)執行,自動開啓多線程。只有在異步下才有效atom
串行:讓任務一個接一個地執行url
-(void)asyncGlobalQueue { //得到全局的併發隊列 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //第一個參數是優先級 //異步並行。自動建立多條線程 dispatch_async(queue, ^{ NSLog(@"將任務放到全局隊列中執行 %@", [NSThread currentThread]); dispatch_async(queue, ^{ NSLog(@"異步並行1 %@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"異步並行2 %@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"異步並行3 %@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"異步並行4 %@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"異步並行5 %@", [NSThread currentThread]); }); }); } -(void)asyncSerialQueue { //異步串行,自動會建立線程,但只開1條 dispatch_queue_t queue = dispatch_queue_create("cn.wx", NULL); dispatch_async(queue, ^{ NSLog(@"異步串行1 %@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"異步串行2 %@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"異步串行3 %@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"異步串行4 %@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"異步串行5 %@", [NSThread currentThread]); }); } -(void)syncGlobalQueue { dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //同步並行。不會建立線程,使用主線程 dispatch_sync(queue, ^{ NSLog(@"同步並行1 %@", [NSThread currentThread]); NSLog(@"同步並行2 %@", [NSThread currentThread]); NSLog(@"同步並行3 %@", [NSThread currentThread]); NSLog(@"同步並行4 %@", [NSThread currentThread]); NSLog(@"同步並行5 %@", [NSThread currentThread]); }); } -(void)syncSerialQueue { dispatch_queue_t queue = dispatch_queue_create("cn.wx", NULL); //同步串行。不會建立線程,使用主線程 dispatch_sync(queue, ^{ NSLog(@"同步並行1 %@", [NSThread currentThread]); NSLog(@"同步並行2 %@", [NSThread currentThread]); NSLog(@"同步並行3 %@", [NSThread currentThread]); NSLog(@"同步並行4 %@", [NSThread currentThread]); NSLog(@"同步並行5 %@", [NSThread currentThread]); }); }
-(void)mainQueue { dispatch_queue_t queue = dispatch_get_main_queue(); dispatch_async(queue, ^{ NSLog(@"雖然是異步,可是是在主線程執行,因此不會開線程"); }); // dispatch_sync(queue, ^{ // NSLog(@"不能在串行上使用主隊列,不然會阻塞"); // }); }
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(queue, ^{ NSLog(@"子線程進行操做"); dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"回主線程加載圖片"); }); });
不要使用sleep,會卡住主線程spa
第一種: [self performSelector:@selector(down) withObject:@"abv" afterDelay:3]; 第二種: dispatch_queue_t queue = dispatch_get_main_queue(); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), queue, ^{ NSLog(@"xx");//回到主線程 }); dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), queue, ^{ NSLog(@"xx");//回到子線程 });
static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSLog(@"xx"); })
先將須要執行的操做封裝到一個NSOperation對象,一個對象就至關於GCD的一個block線程
而後將NSOperation對象添加到NSOperationQueue中code
系統會自動將NSOperationQueue中的NSOperation取出來
將取出的NSOperation封裝的操做放到一條線程中執行
NSOperation是個抽象類,不具有封裝的能力,必須使用它的子類
1>NSInvocationOperation
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download) object:nil]; /* [operation start]; 若是直接start,那麼將會在當前線程(主線程)同步執行 */ //添加操做到隊列中 [queue addOperation:operation];
2>NSBlockOperation
第一種狀況:同步 NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"下載一 %@",[NSThread currentThread]); }]; [operation start]; // 若是直接start,那麼將會在當前線程(主線程)同步執行 第二種狀況:異步 NSBlockOperation *operation = [[NSBlockOperation alloc] init]; //operation操做添加多個操做 [operation addExecutionBlock:^{ NSLog(@"下載一 %@",[NSThread currentThread]); }]; [operation addExecutionBlock:^{ NSLog(@"下載二 %@",[NSThread currentThread]); }]; [operation addExecutionBlock:^{ NSLog(@"下載三 %@",[NSThread currentThread]); }]; [operation start]; ps:NSBlockOperation還能夠直接建立使用對象 NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"下載一 %@",[NSThread currentThread]); }];
3>自定義子類繼承NSOperation
1>.基本使用
//1.建立一個隊列(非主隊列) NSOperationQueue *queue = [[NSOperationQueue alloc] init]; //設置最大併發數 queue.maxConcurrentOperationCount = 2; //2.建立操做 NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"下載圖片1 -- %@",[NSThread currentThread]); }]; NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"下載圖片2 -- %@",[NSThread currentThread]); }]; NSInvocationOperation *operation3 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(down) object:nil]; //操做完後立刻執行另外一個操做 [operation1 setCompletionBlock:^{ NSLog(@"下載圖片222"); }]; //操做依賴,注意不能相互依賴 [operation2 addDependency:operation1]; [operation3 addDependency:operation2]; //3.添加操做到隊列中(自動異步執行任務,併發) [queue addOperation:operation1]; [queue addOperation:operation2]; [queue addOperation:operation3];
2>其餘用法
[queue cancelAllOperations]; //取消隊列的全部操做。也能夠直接調用NSOperation的cancel [queue setSuspended:YES]; //暫停和恢復隊列。yes爲暫停 經常使用場景: -(void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; [queue cancelAllOperations]; } -(void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView { [queue setSuspended:YES]; } -(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { [queue setSuspended:NO]; }
NSOperationQueue *queue = [[NSOperationQueue alloc] init]; [queue addOperationWithBlock:^{ //1.異步下載圖片 NSURL *url = [NSURL URLWithString:@"www.baidu.com"]; NSData *data = [NSData dataWithContentsOfURL:url]; UIImage *image = [UIImage imageWithData:data]; //2.回到主線程設置圖片 [[NSOperationQueue mainQueue] addOperationWithBlock:^{ self.imageView.image = image; }]; }];
self.obj = [[NSObject alloc] init]; //鎖任意對象,而且須要是惟一一把,因此須要創建個全局變量對象 @synchronized(self.obj) { }
2.atomic:線程安全,須要消耗大量的資源。不建議須要
1.不要同時開太多線材(1~3條線材便可,不要超過5條)
2.線程概念
1>主線程:UI線程,顯示、刷新UI界面,處理UI控件的事件
2>子線程:後臺線程,異步線程
3.不要把耗時的操做放在主線程,要放在子線程中執行