2.單線程程序:程序只包含一個線程(主線程),線程中的代碼按順序執行,缺點:可能會造成主線程阻塞(有些任務耗時比較長)
3.多線程程序:程序中包含多個線程,線程是獨立運行的,提高程序運行效率.
4.iOS開發中,所有跟UI有關的操作(繪製,刷新)都必須在主線程中完成.
5.子線程:主線程之外創建的新的線程
△.線程是可以設置優先級的
獲取當前線程,判斷是否是主線程的方法:
NSLog(@"當前線程 %@ ------ 是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
先創建一個多線程測試環境:
-(void)cycle
{
//獲取當前線程,判斷是否是主線程
NSLog(@"當前線程 %@ ------ 是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
int sum = 0;
for (int i=0; i<500; i++) {
sum += i;
// NSLog(@"%d",i);
}
// NSLog(@"%d",sum);
}
一 . 使用NSThread實現多線程 : 創建線程後,自動開啓,無需手動調用開啓
1.第一個參數:線程中需要執行的方法
2.第二個參數:執行方法的對象
3.第三個參數:傳值
[NSThread detachNewThreadSelector:@selector(cycle) toTarget:self withObject:nil];
二 . 使用NSThread實現多線程 : 創建線程後,需要手動開啓
NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(cycle) object:nil];
[thread start];
三 . 使用NSObject類目方法實現多線程(用的比較多)
//隱式創建線程
[self performSelectorInBackground:@selector(cycle) withObject:nil];
//圖片網址
NSString * url = @"http://a.hiphotos.baidu.com/image/pic/item/96dda144ad3459824a56a41a0ef431adcaef845e.jpg";
[self performSelectorInBackground:@selector(downloadImage:) withObject:url];
//在子線程中,同步連接下載圖片
-(void)downloadImage:(NSString *)url
{
//在子線程中,使用同步方式下載圖片. △備註:在子線程中,不要使用異步連接,會出現問題
/*
△注意事項:
1.子線程中沒有自動釋放池,需要手動添加
2.NSThread創建的子線程,默認情況下,任務執行完成後,線程被關閉,銷燬
3.在子線程中,NSTimer默認情況下,不會執行.如果在子線程中使用NSTimer,必須開啓runLoop,方法如下:
4.所有線程都有runLoop,主線程默認是開啓狀態,子線程默認是關閉狀態
5.子線程開啓runLoop後,runLoop不停止,線程無法關閉
*/
//獲取當前線程的runLoop,並開啓
// [[NSRunLoop currentRunLoop] run];
//獲取當前線程的runLoop,並設定運行的時間
// [[NSRunLoop currentRunLoop] runUntilDate:<#(NSDate *)#>];
//獲取當前線程,判斷是否是主線程
NSLog(@"當前線程 %@ ------ 是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
//同步下載圖片
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
//將data轉換成image對象
UIImage *image = [UIImage imageWithData:data];
//△注意:將image在主線程中進行顯示.
// _imageView.image = image;//這句話位置不對,不能寫在這裏
[self performSelectorOnMainThread:@selector(showImage:) withObject:image waitUntilDone:YES];//第三個參數:等待子線程任務執行完成,再回到主線程執行
//直接給imageView附圖片
// [_imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];
}
//在主線程中,將image顯示在imageView上
-(void)showImage:(UIImage *)image
{
//獲取當前線程,判斷是否是主線程
NSLog(@"當前線程 %@ ------ 是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
//參數image是從子線程中返回
_imageView.image = image;
}
四 . NSOperation 是一個操作類(抽象類),封裝了需要執行的任務和數據. 一般不直接使用NSOperation,使用子類:NSInvocationOperation和NSBlockOperation
//操作對象封裝了需要執行的任務和參數
NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(cycle) object:nil];
//開始執行operation對象中封裝的任務(方法)
//start在哪個線程中調用,operation對象中封裝的方法就在哪個線程中執行
[operation start];
五 . block方法:
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"當前線程 %@ ----- 是否是主線程:%d", [NSThread currentThread], [NSThread isMainThread]);
for (int i = 1; i < 500; i++) {
}
}];
[operation start];
六 . NSOperationQueue :
1.NSOperationQueue 操作隊列(先進先出),可以管理多個操作對象.
2.NSOperationQueue 創建的多線程是可以重複使用的,是非脫離線程(線程中的任務完成後,線程進入睡眠狀態,未被銷燬;NSThread創建的線程是脫離線程)
3.NSOperationQueue 先加入隊列的任務,先執行.(即"先進先出")
4.NSOperationQueue 控制的線程是併發執行的. 即:隊列中的任務按照加入隊列的順序進行分派,但是下一個任務不用等待前一個任務完成再開始.多個任務可以同時執行,互不干擾. ("併發"相對的是"串行")
5.什麼叫線程同步? 線程A執行結束後才能執行線程B
6.NSOperationQueue如何實現線程同步? 把最大併發數設置爲1,即:每次只允許一個線程執行任務
7.隊列下載
NSOperationQueue * queue = [[NSOperationQueue alloc]init];
//設置最大併發數
queue.maxConcurrentOperationCount = 1;
//添加10個任務
for (int i=0; i<10; i++) {
NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(cycle) object:nil];
//操作對象添加到隊列裏
[queue addOperation:operation];
}
七 . 使用GCD的隊列實現串行(任務1執行後,任務2再執行) :
1.GCD隊列類型:主隊列,全局隊列,自定義隊列
2.GCD隊列功能:串行,併發
3.能夠實現串行的有兩種隊列:主隊列和自定義串行隊列
4.能夠實現併發的有兩種隊列:全局隊列和自定義併發隊列
//串行隊列 第一種實現:使用主隊列
/*
dispatch_queue_t queue = dispatch_get_main_queue();
//向隊列異步添加任務
dispatch_async(queue, ^{
NSLog(@"第一個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
dispatch_async(queue, ^{
NSLog(@"第二個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
dispatch_async(queue, ^{
NSLog(@"第三個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
dispatch_async(queue, ^{
NSLog(@"第四個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
dispatch_async(queue, ^{
NSLog(@"第五個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
*/
//串行隊列 第二種實現:使用自定義串行隊列
dispatch_queue_t queue = dispatch_queue_create("com.lanou3g.Thread.myQueue", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
NSLog(@"第一個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
dispatch_async(queue, ^{
NSLog(@"第二個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
dispatch_async(queue, ^{
NSLog(@"第三個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
dispatch_async(queue, ^{
NSLog(@"第四個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
dispatch_async(queue, ^{
NSLog(@"第五個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
//釋放(注意:MRC下需要釋放)
// dispatch_release(queue);
八 . GCD併發:任務A,B,C....按照進入隊列順序開始分派執行
//併發隊列 第一種實現:全局隊列
/*
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
NSLog(@"第一個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
dispatch_async(queue, ^{
NSLog(@"第二個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
dispatch_async(queue, ^{
NSLog(@"第三個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
dispatch_async(queue, ^{
NSLog(@"第四個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
dispatch_async(queue, ^{
NSLog(@"第五個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
*/
//併發隊列 第二種實現:使用自定義併發隊列
dispatch_queue_t queue = dispatch_queue_create("com.lanou3g.Thread.myQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"第一個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
dispatch_async(queue, ^{
NSLog(@"第二個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
dispatch_async(queue, ^{
NSLog(@"第三個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
dispatch_async(queue, ^{
NSLog(@"第四個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
dispatch_async(queue, ^{
NSLog(@"第五個任務,所在線程:%@,是否是主線程:%d",[NSThread currentThread],[NSThread isMainThread]);
});
九 . GCD
//在子線程中建立同步連接下載圖片(把任務添加到全局隊列)
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
//建立同步連接下載圖片
//圖片網址
NSString * url = @"http://a.hiphotos.baidu.com/image/pic/item/96dda144ad3459824a56a41a0ef431adcaef845e.jpg";
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
UIImage *image = [UIImage imageWithData:data];
NSLog(@"同步連接下載圖片,當前線程:%@",[NSThread currentThread]);
//在主線程中,顯示下載的圖像
dispatch_async(dispatch_get_main_queue(), ^{
_imageView.image = image;
NSLog(@"顯示下載圖片,當前線程:%@",[NSThread currentThread]);
});
});
十 . 總結:
1.耗費時間的兩種方式:下載(跟網速有關)和處理數據
2. 任務 線程 方法
觸發下載圖片 主線程 didClick....Button
建立同步連接下載圖片 子線程 download
3.
/*
1.每個進程至少包含一個線程,這個默認創建的線程被成爲主線程
2.單線程程序:程序只包含一個線程(主線程),線程中的代碼按順序執行,缺點:可能會造成主線程阻塞(有些任務耗時比較長)
3.多線程程序:程序中包含多個線程,線程是獨立運行的,提高程序運行效率.
4.iOS開發中,所有跟UI有關的操作(繪製,刷新)都必須在主線程中完成.
5.子線程:主線程之外創建的新的線程
△.線程是可以設置優先級的
*/
4.
/*
△注意事項:
1.子線程中沒有自動釋放池,需要手動添加
2.NSThread創建的子線程,默認情況下,任務執行完成後,線程被關閉,銷燬
3.在子線程中,NSTimer默認情況下,不會執行.如果在子線程中使用NSTimer,必須開啓runLoop,方法如下:
4.所有線程都有runLoop,主線程默認是開啓狀態,子線程默認是關閉狀態
5.子線程開啓runLoop後,runLoop不停止,線程無法關閉
*/
//獲取當前線程的runLoop,並開啓
// [[NSRunLoop currentRunLoop] run];
//獲取當前線程的runLoop,並設定運行的時間
// [[NSRunLoop currentRunLoop] runUntilDate:<#(NSDate *)#>];
5.
/*
1.NSOperationQueue 操作隊列(先進先出),可以管理多個操作對象.
2.NSOperationQueue 創建的多線程是可以重複使用的,是非脫離線程(線程中的任務完成後,線程進入睡眠狀態,未被銷燬;NSThread創建的線程是脫離線程)
3.NSOperationQueue 先加入隊列的任務,先執行.(即"先進先出")
4.NSOperationQueue 控制的線程是併發執行的. 即:隊列中的任務按照加入隊列的順序進行分派,但是下一個任務不用等待前一個任務完成再開始.多個任務可以同時執行,互不干擾. ("併發"相對的是"串行")
5.什麼叫線程同步? 線程A執行結束後才能執行線程B
6.NSOperationQueue如何實現線程同步? 把最大併發數設置爲1,即:每次只允許一個線程執行任務
7.隊列下載
*/
6.
△.注意:GCD不等於多線程