一、基本概念
- 進(jìn)程:系統(tǒng)中正在運(yùn)行的應(yīng)用程序。每個(gè)程序都是相互獨(dú)立的,并且運(yùn)行在一塊獨(dú)有的受保護(hù)的內(nèi)存中
- 線程:進(jìn)程基本執(zhí)行路徑。一個(gè)進(jìn)程想要執(zhí)行任務(wù),就必須通過線程來執(zhí)行。單條的線程通過串行的方式執(zhí)行任務(wù),也就是說任務(wù)是一個(gè)一個(gè)按順序的執(zhí)行
- 多線程:開啟多條線程,讓任務(wù)并發(fā)執(zhí)行。(原理:在同一時(shí)間內(nèi),CPU 只會(huì)處理一條線程,多線程并發(fā)執(zhí)行其實(shí)是,cpu在不同的線程之間快速的切換處理,只要cpu切換的足夠快,就會(huì)給人多線程并發(fā)執(zhí)行任務(wù)的假象)
補(bǔ)充:并行指的是任務(wù)一起執(zhí)行,強(qiáng)調(diào)的是過程;并發(fā)指的是任務(wù)以一起執(zhí)行的方式開始執(zhí)行,強(qiáng)調(diào)的是任務(wù)開始執(zhí)行的方式。
二、多線程的優(yōu)缺點(diǎn)
優(yōu)點(diǎn)
- 可提高程序的執(zhí)行效率
- 可合理提高cpu和內(nèi)存的利用率
缺點(diǎn)
- 開啟一條線程所占用的內(nèi)存較大(主線程 1M ;子線程 512KB)
- 線程多時(shí),cpu在在切換線程上的開銷較大,影響性能
- 線程間的通訊和數(shù)據(jù)共享等會(huì)將大程序設(shè)計(jì)的復(fù)雜度
三、多線程的實(shí)現(xiàn)方案
1. NSThread
此方案是經(jīng)過蘋果封裝后完全面向?qū)ο蟮模梢灾苯幽玫骄€程對(duì)象進(jìn)行操作,很直觀、便捷。但是缺點(diǎn)就是需手動(dòng)管理線程生命周期,所以不經(jīng)常使用
1.1 創(chuàng)建(3種方式)
// 1.手動(dòng)啟動(dòng)線程,可拿到線程對(duì)象進(jìn)行額外的設(shè)置
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(addThread:) object:@"hahaha"];
[thread start];
// 2.分離出子線程 - 自動(dòng)啟動(dòng)線程
[NSThread detachNewThreadSelector:@selector(addChildThread:) toTarget:self withObject:@"子線程"];
// 3.后臺(tái)線程 - 自動(dòng)啟動(dòng)線程
[self performSelectorInBackground:@selector(addBackgroundThread:) withObject:@"后臺(tái)線程"];
1.2 NSThread 常涉及到的方法
[thread cancel]; //取消線程
[NSThread exit];
[NSThread sleepForTimeInterval:3.0]; //阻塞線程
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:3.0]];
[NSThread currentThread]; //獲取當(dāng)前線程
[NSThread mainThread]; //獲取主線程
[NSThread isMultiThreaded]; //是否是多線程,返回BOOL值
1.3 線程間通信
- (void)viewDidLoad {
[super viewDidLoad];
// 創(chuàng)建子線程
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(addThread:) object:@"hahaha"];
[thread start];
}
- (void)addThread:(NSString *)name {
NSLog(@"%@",[NSThread currentThread]);
// 在子線程中回到主線程的兩種方式
[self performSelectorOnMainThread:@selector(goBackMainThread:) withObject:@"main" waitUntilDone:YES];
[self performSelector:@selector(goBackMainThread:) onThread:[NSThread mainThread] withObject:@"test" waitUntilDone:YES];
}
- (void)goBackMainThread:(NSString *)name {
NSLog(@"%@",[NSThread currentThread]);
}
打印結(jié)果
2016-08-01 14:20:30.253 demo[66988:3541822] <NSThread: 0x79e71ab0>{number = 2, name = (null)}
2016-08-01 14:20:30.258 demo[66988:3541733] <NSThread: 0x79e72a30>{number = 1, name = main}
2016-08-01 14:20:30.259 demo[66988:3541733] <NSThread: 0x79e72a30>{number = 1, name = main}
1.4 線程安全
當(dāng)多個(gè)線程訪問同一塊資源時(shí)會(huì)發(fā)生數(shù)據(jù)安全問題,也稱為線程同步 ,這時(shí)候就需要加互斥鎖 @synchronized(self){}
2. GCD
蘋果為多核并行運(yùn)算開發(fā)的解決方案,它可以自動(dòng)的利用cpu的內(nèi)核,并且系統(tǒng)自動(dòng)管理線程的生命周期
開發(fā)者要做的是將任務(wù)添加到隊(duì)列中,系統(tǒng)會(huì)自動(dòng)將隊(duì)列中的任務(wù)按FIFO的原則取出任務(wù)(FIFO:先進(jìn)先出,后進(jìn)后出,如果以并發(fā)方式執(zhí)行任務(wù),則先出的任務(wù)還沒結(jié)束前下一個(gè)的任務(wù)可以出列)
2.1 任務(wù)和隊(duì)列的理解
任務(wù):決定能不能開啟新線程,分同步和異步任務(wù)兩種
-同步:任務(wù)只能在當(dāng)前的線程執(zhí)行,不具備開啟新線程的能力(同步任務(wù)比較霸道,必須在當(dāng)前的分配任務(wù)執(zhí)行完,才算把分配任務(wù)的任務(wù)結(jié)束,和后面說的死鎖有關(guān)聯(lián))
-異步:任務(wù)可以在其它線程中執(zhí)行,具備有開啟新線程的能力
// 同步任務(wù)
dispatch_sync(dispatch_get_global_queue(0, 0), ^{
});
// 異步任務(wù)
dispatch_async(dispatch_get_global_queue(0, 0), ^{
});
隊(duì)列:決定任務(wù)將以什么方式執(zhí)行,分串行和并發(fā)隊(duì)列兩種
-串行:任務(wù)將一個(gè)接一個(gè)的執(zhí)行(一個(gè)任務(wù)執(zhí)行完才開始下一個(gè)任務(wù))
-并發(fā):多個(gè)任務(wù)可以并發(fā)(同時(shí))執(zhí)行,要在異步任務(wù)函數(shù)中才能有效
隊(duì)列的創(chuàng)建
-串行:系統(tǒng)提供兩種方式
// 1.系統(tǒng)提供的主隊(duì)列
dispatch_queue_t mainQueue = dispatch_get_main_queue();
// 2.創(chuàng)建新的串行隊(duì)列(參數(shù)1:隊(duì)列名字,apple推薦使用com.example.myQueue的規(guī)則來命名隊(duì)列,用于debug的時(shí)候追蹤隊(duì)列以便于調(diào)試,可以為空;
// 參數(shù)2:可以傳人NULL或DISPATCH_QUEUE_SERIAL表示串行隊(duì)列)
dispatch_queue_t queue = dispatch_queue_create("com.hhh.eatShit", NULL);
- 并發(fā):系統(tǒng)提供兩種方式
// 1.系統(tǒng)提供的全局隊(duì)列(參數(shù)1:隊(duì)列的優(yōu)先級(jí);參數(shù)2:傳0即可)
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 2.創(chuàng)建新的并發(fā)隊(duì)列
dispatch_queue_t queue = dispatch_queue_create("com.hhh.eatShit", DISPATCH_QUEUE_CONCURRENT);
2.2 GCD使用方式(任務(wù)和隊(duì)列的結(jié)合方式)
- 異步任務(wù)+并發(fā)隊(duì)列:使用頻率高,開啟多線程并發(fā)的執(zhí)行任務(wù)
- 異步任務(wù)+串行隊(duì)列:使用頻率高,開啟一條新線程,串行執(zhí)行任務(wù)
- 同步任務(wù)+并發(fā)隊(duì)列:基本不用,不開線程在當(dāng)前線程串行執(zhí)行任務(wù)我
- 同步任務(wù)+串行隊(duì)列:基本不用,不開線程在當(dāng)前線程串行執(zhí)行任務(wù)我
- 異步任務(wù)+主隊(duì)列:不開線程,在主線程中串行執(zhí)行任務(wù)我
- 同步任務(wù)+主隊(duì)列:不開線程,在主線程中串行執(zhí)行任務(wù)我(注意死鎖)
注意:在當(dāng)前的串行隊(duì)列中添加同步任務(wù)到當(dāng)前隊(duì)列會(huì)發(fā)生死鎖
- (void)viewDidLoad {
[super viewDidLoad];
// 主隊(duì)列是串行的,在主隊(duì)里中往主隊(duì)列添加同步任務(wù),發(fā)生死鎖,無(wú)法執(zhí)行打印內(nèi)容
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"快把我打印出來");
});
}
2.3 ??演示GCD的使用
- 異步任務(wù)+并發(fā)隊(duì)列
- (void)viewDidLoad {
[super viewDidLoad];
// 由系統(tǒng)決定開幾條線程
dispatch_queue_t queue = dispatch_queue_create("com.demo.bingfa", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"任務(wù)1---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任務(wù)2---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任務(wù)3---%@",[NSThread currentThread]);
});
}
打印
2016-08-01 17:27:01.793 demo[79533:3667100] 任務(wù)1---<NSThread: 0x79858c40>{number = 2, name = (null)}
2016-08-01 17:27:01.793 demo[79533:3667104] 任務(wù)3---<NSThread: 0x7865da50>{number = 4, name = (null)}
2016-08-01 17:27:01.794 demo[79533:3667103] 任務(wù)2---<NSThread: 0x79a5a540>{number = 3, name = (null)}
2.異步任務(wù)+串行隊(duì)列
- (void)viewDidLoad {
[super viewDidLoad];
// 只開一條新線程
dispatch_queue_t queue = dispatch_queue_create("com.demo.chuanxing", NULL);
dispatch_async(queue, ^{
NSLog(@"任務(wù)1---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任務(wù)2---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任務(wù)3---%@",[NSThread currentThread]);
});
}
打印
2016-08-01 17:29:13.092 demo[79710:3669166] 任務(wù)1---<NSThread: 0x7a236720>{number = 2, name = (null)}
2016-08-01 17:29:13.093 demo[79710:3669166] 任務(wù)2---<NSThread: 0x7a236720>{number = 2, name = (null)}
2016-08-01 17:29:13.094 demo[79710:3669166] 任務(wù)3---<NSThread: 0x7a236720>{number = 2, name = (null)}
3.同步任務(wù)+并發(fā)隊(duì)列
- (void)viewDidLoad {
[super viewDidLoad];
// 不開新線程,當(dāng)前是主線程,所以任務(wù)1、2、3在主線程中執(zhí)行
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_async(queue, ^{
NSLog(@"任務(wù)1---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任務(wù)2---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任務(wù)3---%@",[NSThread currentThread]);
});
}
打印
2016-08-01 17:57:04.133 demo[81692:3691446] 任務(wù)1---<NSThread: 0x7a2314b0>{number = 1, name = main}
2016-08-01 17:57:04.134 demo[81692:3691446] 任務(wù)2---<NSThread: 0x7a2314b0>{number = 1, name = main}
2016-08-01 17:57:04.134 demo[81692:3691446] 任務(wù)3---<NSThread: 0x7a2314b0>{number = 1, name = main}
4.同步任務(wù)+串行隊(duì)列
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_queue_t queue = dispatch_queue_create("com.demo.chuanxing", NULL);
dispatch_async(queue, ^{
NSLog(@"新開的子線程---%@",[NSThread currentThread]);
// 在新開的子線程中,在queue隊(duì)列中測(cè)試
dispatch_queue_t queue1 = dispatch_queue_create("com.demo.chuanxing", NULL);
dispatch_sync(queue1, ^{
NSLog(@"任務(wù)1---%@",[NSThread currentThread]);
});
dispatch_sync(queue1, ^{
NSLog(@"任務(wù)2---%@",[NSThread currentThread]);
});
dispatch_sync(queue1, ^{
NSLog(@"任務(wù)3---%@",[NSThread currentThread]);
});
});
}
打印
2016-08-01 17:53:10.405 demo[81376:3688029] 新開的子線程---<NSThread: 0x78e7fe80>{number = 2, name = (null)}
2016-08-01 17:53:10.406 demo[81376:3688029] 任務(wù)1---<NSThread: 0x78e7fe80>{number = 2, name = (null)}
2016-08-01 17:53:10.407 demo[81376:3688029] 任務(wù)2---<NSThread: 0x78e7fe80>{number = 2, name = (null)}
2016-08-01 17:53:10.407 demo[81376:3688029] 任務(wù)3---<NSThread: 0x78e7fe80>{number = 2, name = (null)}
5.異步任務(wù)+主隊(duì)列(同3)
6.同步任務(wù)+主隊(duì)列(切記不能在主隊(duì)列中使用這種方式)
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_queue_t queue = dispatch_queue_create("com.demo.chuanxing", NULL);
dispatch_async(queue, ^{
NSLog(@"新開的子線程---%@",[NSThread currentThread]);
// 在新開的子線程中,任務(wù)1、2、3在主線程中執(zhí)行
dispatch_queue_t queue1 = dispatch_get_main_queue();
dispatch_sync(queue1, ^{
NSLog(@"任務(wù)1---%@",[NSThread currentThread]);
});
dispatch_sync(queue1, ^{
NSLog(@"任務(wù)2---%@",[NSThread currentThread]);
});
dispatch_sync(queue1, ^{
NSLog(@"任務(wù)3---%@",[NSThread currentThread]);
});
});
}
打印
2016-08-01 17:59:57.794 demo[81900:3693593] 新開的子線程---<NSThread: 0x79745ab0>{number = 2, name = (null)}
2016-08-01 17:59:57.798 demo[81900:3693419] 任務(wù)1---<NSThread: 0x79843a10>{number = 1, name = main}
2016-08-01 17:59:57.799 demo[81900:3693419] 任務(wù)2---<NSThread: 0x79843a10>{number = 1, name = main}
2016-08-01 17:59:57.800 demo[81900:3693419] 任務(wù)3---<NSThread: 0x79843a10>{number = 1, name = main}
2.4 GCD其它函數(shù)
- 柵欄函數(shù) dispatch_barrier_async(queue, ^{ });
在任務(wù)前面的異步任務(wù)都執(zhí)行完后才會(huì)執(zhí)行它,并且等它執(zhí)行完后,后面的異步任務(wù)才能開始執(zhí)行
注意:
1.>此函數(shù)加入全局隊(duì)列示無(wú)效的,即queue不能是全劇隊(duì)列
2.>如果任務(wù)是同步的則會(huì)在當(dāng)前的線程中執(zhí)行,異步的話在新線程中執(zhí)行
??
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_queue_t queue = dispatch_queue_create("com.demo.bingfa", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"任務(wù)1---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任務(wù)2---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任務(wù)3---%@",[NSThread currentThread]);
});
dispatch_barrier_async(queue, ^{
NSLog(@"任務(wù)4---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任務(wù)5---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任務(wù)6---%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任務(wù)7---%@",[NSThread currentThread]);
});
}
打印(任務(wù)4總是在任務(wù)1、2、3和5、6、7的中間)
2016-08-01 20:55:44.075 demo[85715:3735784] 任務(wù)2---<NSThread: 0x7a8746e0>{number = 3, name = (null)}
2016-08-01 20:55:44.075 demo[85715:3735778] 任務(wù)1---<NSThread: 0x7a96ff10>{number = 2, name = (null)}
2016-08-01 20:55:44.075 demo[85715:3735777] 任務(wù)3---<NSThread: 0x7a67a470>{number = 4, name = (null)}
2016-08-01 20:55:44.077 demo[85715:3735777] 任務(wù)4---<NSThread: 0x7a67a470>{number = 4, name = (null)}
2016-08-01 20:55:44.078 demo[85715:3735777] 任務(wù)5---<NSThread: 0x7a67a470>{number = 4, name = (null)}
2016-08-01 20:55:44.078 demo[85715:3735778] 任務(wù)6---<NSThread: 0x7a96ff10>{number = 2, name = (null)}
2016-08-01 20:55:44.078 demo[85715:3735784] 任務(wù)7---<NSThread: 0x7a8746e0>{number = 3, name = (null)}
信號(hào)量的使用 --- 但以上任務(wù)2中存在其它異步并發(fā)任務(wù),如網(wǎng)絡(luò)請(qǐng)求的時(shí):
dispatch_queue_t queue = dispatch_queue_create("com.demo.bingfa", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
// 創(chuàng)建一個(gè)信號(hào)量為0的信號(hào)(紅燈)
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
dispatch_queue_t queue2 = dispatch_queue_create("com.demo.bing", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue2, ^{
[NSThread sleepForTimeInterval:2];
// 使信號(hào)的信號(hào)量+1,這里的信號(hào)量本來為0,+1信號(hào)量為1(綠燈)
dispatch_semaphore_signal(sema);
NSLog(@"任務(wù)2---%@",[NSThread currentThread]);
});
NSLog(@"任務(wù)2---%@",[NSThread currentThread]);
// 開啟信號(hào)等待,設(shè)置等待時(shí)間為永久,直到信號(hào)的信號(hào)量大于等于1(綠燈)
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
});
dispatch_async(queue, ^{
NSLog(@"任務(wù)3---%@",[NSThread currentThread]);
});
dispatch_barrier_async(queue, ^{
NSLog(@"任務(wù)4---%@",[NSThread currentThread]);
});
2.隊(duì)列組
能實(shí)現(xiàn)在一個(gè)或則多個(gè)任務(wù)執(zhí)行完之后,在執(zhí)行特定的任務(wù)。例如:A任務(wù)和B任務(wù)并發(fā)執(zhí)行,C任務(wù)需要在A任務(wù)和B任務(wù)都執(zhí)行完之后再執(zhí)行,這時(shí)候就可以通過隊(duì)列組來實(shí)現(xiàn)
??
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"任務(wù)1---%@",[NSThread currentThread]);
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"任務(wù)2---%@",[NSThread currentThread]);
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"任務(wù)3---%@",[NSThread currentThread]);
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"任務(wù)4---%@",[NSThread currentThread]);
});
dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"任務(wù)5---%@",[NSThread currentThread]);
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"任務(wù)6---%@",[NSThread currentThread]);
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"任務(wù)7---%@",[NSThread currentThread]);
});
}
打印: 你會(huì)發(fā)現(xiàn)任務(wù)5永遠(yuǎn)都是隊(duì)列組中最后執(zhí)行的一個(gè)
2016-08-01 22:10:55.218 demo[90162:3774195] 任務(wù)1---<NSThread: 0x7af959d0>{number = 2, name = (null)}
2016-08-01 22:10:55.218 demo[90162:3774194] 任務(wù)2---<NSThread: 0x7b1346f0>{number = 3, name = (null)}
2016-08-01 22:10:55.218 demo[90162:3774216] 任務(wù)6---<NSThread: 0x7b06cf00>{number = 6, name = (null)}
2016-08-01 22:10:55.218 demo[90162:3774215] 任務(wù)4---<NSThread: 0x7af95fe0>{number = 5, name = (null)}
2016-08-01 22:10:55.218 demo[90162:3774199] 任務(wù)3---<NSThread: 0x7ae30250>{number = 4, name = (null)}
2016-08-01 22:10:55.219 demo[90162:3774217] 任務(wù)7---<NSThread: 0x7b135bb0>{number = 7, name = (null)}
2016-08-01 22:10:55.220 demo[90162:3774217] 任務(wù)5---<NSThread: 0x7b135bb0>{number = 7, name = (null)}
3.NSOperation
3.1 概念
NSOperation是對(duì)GCD的封裝;本身是一個(gè)抽象類,只能使用它的三個(gè)子類;和NSOperationQueue結(jié)合使用實(shí)現(xiàn)多線程并發(fā)
3.2 NSOperation和NSOperationQueue的理解
NSOperation三個(gè)子類
-NSInvocationOperation
- (void)viewDidLoad {
[super viewDidLoad];
// 不加入隊(duì)列執(zhí)行開始操作
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(addOperation:) object:@"NEW"];
[operation start];
}
- (void)addOperation:(NSString *)name {
// 在主線程中執(zhí)行,沒有意義
NSLog(@"%@",[NSThread currentThread]);
}
-NSBlockOperation
創(chuàng)建操作時(shí)攜帶的任務(wù)在主線程,操作后面額外添加的任務(wù),系統(tǒng)自動(dòng)開啟線程執(zhí)行
- (void)viewDidLoad {
[super viewDidLoad];
// 不加入隊(duì)列執(zhí)行開始操作
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
// 在主線程中執(zhí)行
NSLog(@"任務(wù)1---%@",[NSThread currentThread]);
}];
[operation addExecutionBlock:^{
// 系統(tǒng)根據(jù)需要自動(dòng)開啟線程
NSLog(@"任務(wù)2---%@",[NSThread currentThread]);
}];
[operation addExecutionBlock:^{
// 系統(tǒng)根據(jù)需要自動(dòng)開啟線程
NSLog(@"任務(wù)3---%@",[NSThread currentThread]);
}];
[operation addExecutionBlock:^{
// 系統(tǒng)根據(jù)需要自動(dòng)開啟線程
NSLog(@"任務(wù)4---%@",[NSThread currentThread]);
}];
[operation start];
}
-自定義NSOperation
一般操作過于復(fù)雜時(shí)可以使用自定義NSOperation,具有隱蔽性和可重復(fù)利用的好處
#import "JYOperation.h"
@implementation JYOperation
- (void)main {
NSLog(@"%@",[NSThread currentThread]);
}
@end
- (void)viewDidLoad {
[super viewDidLoad];
// 不添加到隊(duì)列的話,任務(wù)在主線程執(zhí)行,沒有意義
JYOperation *operation = [[JYOperation alloc] init];
[operation start];
}
NSOperationQueue
- 主隊(duì)列
添加到主隊(duì)列中的任務(wù)都在主線程中執(zhí)行
-非主隊(duì)列
任務(wù)在子線程中執(zhí)行,控制任務(wù)以串行或并發(fā)的方式執(zhí)行,具體通過設(shè)置隊(duì)列的maxConcurrentOperationCount(最大并發(fā)數(shù))屬性來控制
注意:
1.maxConcurrentOperationCount必須在操作添加到隊(duì)列之前設(shè)置才有效
2.maxConcurrentOperationCount 默認(rèn)為-1,即默認(rèn)任務(wù)是并發(fā)執(zhí)行;等于0時(shí),不執(zhí)行任務(wù),無(wú)意義;等于1時(shí),串行執(zhí)行任務(wù);等于n時(shí),并發(fā)數(shù)為n,允許n個(gè)任務(wù)是同時(shí)執(zhí)行的
- (void)viewDidLoad {
// 2.非主隊(duì)列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 3;
[queue addOperationWithBlock:^{
NSLog(@"任務(wù)1---%@",[NSThread currentThread]);
}];
[queue addOperationWithBlock:^{
NSLog(@"任務(wù)2---%@",[NSThread currentThread]);
}];
[queue addOperationWithBlock:^{
NSLog(@"任務(wù)3---%@",[NSThread currentThread]);
}];
[queue addOperationWithBlock:^{
NSLog(@"任務(wù)4---%@",[NSThread currentThread]);
}];
[queue addOperationWithBlock:^{
NSLog(@"任務(wù)5---%@",[NSThread currentThread]);
}];
[queue addOperationWithBlock:^{
NSLog(@"任務(wù)6---%@",[NSThread currentThread]);
}];
}
打印
2016-08-02 10:10:56.874 demo[99820:3887770] 任務(wù)1---<NSThread: 0x7a98b340>{number = 2, name = (null)}
2016-08-02 10:10:56.874 demo[99820:3887814] 任務(wù)3---<NSThread: 0x7a71c690>{number = 4, name = (null)}
2016-08-02 10:10:56.874 demo[99820:3887769] 任務(wù)2---<NSThread: 0x7a71c450>{number = 3, name = (null)}
2016-08-02 10:10:56.875 demo[99820:3887814] 任務(wù)5---<NSThread: 0x7a71c690>{number = 4, name = (null)}
2016-08-02 10:10:56.876 demo[99820:3887810] 任務(wù)6---<NSThread: 0x7a71c840>{number = 5, name = (null)}
2016-08-02 10:10:56.876 demo[99820:3887770] 任務(wù)4---<NSThread: 0x7a98b340>{number = 2, name = (null)}
3.3 操作和隊(duì)列結(jié)合(兩種方式)
- (void)viewDidLoad {
// 方式1:將操作加入隊(duì)列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"任務(wù)1---%@",[NSThread currentThread]);
}];
[queue addOperation:operation];
// 方式2:通過隊(duì)列直接加操作
[queue addOperationWithBlock:^{
NSLog(@"任務(wù)2---%@",[NSThread currentThread]);
}];
}
補(bǔ)充(暫停、恢復(fù)和取消)
- (void)viewDidLoad {
self.queue = [[NSOperationQueue alloc] init];
// 任務(wù)暫停后可以恢復(fù)執(zhí)行
if (self.queue.isSuspended) {
self.queue.suspended = NO;
}
// 任務(wù)取消后不可在恢復(fù)執(zhí)行
[self.queue cancelAllOperations];
}
3.4 設(shè)置操作依賴
通過調(diào)用操作[operation addDependency:]方法,可實(shí)現(xiàn)不同操作按指定的順序執(zhí)行
- (void)viewDidLoad {
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"操作1---");
}];
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"操作2---");
}];
// operation1依賴operation2,operation2執(zhí)行完才能執(zhí)行operation1
[operation1 addDependency:operation2];
[queue addOperation:operation1];
[queue addOperation:operation2];
}
打印
2016-08-02 11:02:19.161 demo[3839:3930104] 操作2---
2016-08-02 11:02:19.162 demo[3839:3930104] 操作1---
??有一種需求:前兩個(gè)異步任務(wù)都執(zhí)行完之后才開始執(zhí)行第三個(gè)
任務(wù)
- (void)viewDidLoad {
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"操作1---");
}];
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"操作2---");
}];
NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"操作3---");
}];
[operation3 addDependency:operation1];
[operation3 addDependency:operation2];
[queue addOperation:operation1];
[queue addOperation:operation2];
[queue addOperation:operation3];
}
打印
2016-08-02 11:05:21.480 demo[4099:3932866] 操作2---
2016-08-02 11:05:21.480 demo[4099:3932865] 操作1---
2016-08-02 11:05:21.482 demo[4099:3932865] 操作3---
4 總結(jié)
以上主要涉及到開發(fā)中常用的一些內(nèi)容,另外至于GCD和NSOperation線程間的通信,其實(shí)常用到的是異步操作后回到主線程,只要將需要回到主線程的任務(wù)添加到主隊(duì)列即可