
基本概念
進程: 一個具有一定獨立功能的程序關(guān)于某個數(shù)據(jù)集合的一次運行活動??梢岳斫獬梢粋€運行中的應(yīng)用程序。
線程: 程序執(zhí)行流的最小單元,線程是進程中的一個實體。
同步: 只能在當前線程按先后順序依次執(zhí)行,不開啟新線程。
異步: 可以在當前線程開啟多個新線程執(zhí)行,可不按順序執(zhí)行。
隊列: 裝載線程任務(wù)的隊形結(jié)構(gòu)。
并發(fā): 線程執(zhí)行可以同時一起進行執(zhí)行。
串行: 線程執(zhí)行只能依次逐一先后有序的執(zhí)行。一個進程可以有多個線程,也可以有多個隊列。
iOS多線程對比
NSThread
每個NSThread對象對應(yīng)一個線程,真正最原始的線程。
1)優(yōu)點:NSThread 輕量級最低,相對簡單。
2)缺點:手動管理所有的線程活動,如生命周期、線程同步、睡眠等。NSOperation
自帶線程管理的抽象類。
1)優(yōu)點:自帶線程周期管理,操作上可更注重自己邏輯。
2)缺點:面向?qū)ο蟮某橄箢悾荒軐崿F(xiàn)它或者使用它定義好的兩個子類:NSInvocationOperation 和 NSBlockOperation。GCD
Grand Central Dispatch (GCD)是Apple開發(fā)的一個多核編程的解決方法。
1)優(yōu)點:最高效,避開并發(fā)陷阱。
2)缺點:基于C實現(xiàn)。選擇小結(jié)
1)簡單而安全的選擇NSOperation實現(xiàn)多線程即可。
2)處理大量并發(fā)數(shù)據(jù),又追求性能效率的選擇GCD。
3)NSThread用的少。
1. NSThread 創(chuàng)建方法一
- (void)viewDidLoad {
[super viewDidLoad];
// 創(chuàng)建線程
NSThread *thread = [[NSThread alloc]initWithTarget:self selector: @selector(run:) object:@"hehe"];
//線程名字
thread.name = @"wang";
//開啟線程
[thread start];
}
- (void)run:(NSString*)str
{
//d[2177:95263] -----run-----hehe--<NSThread: 0x60000026e440>{number = 3, name = wang}
NSLog(@"-----run-----%@--%@", str, [NSThread currentThread]);
}
2. NSThread 其他創(chuàng)建方法
//方法二
[self performSelectorInBackground:@selector(run:) withObject:@"wang"];
//方法三
[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"wang"];
3. 線程的狀態(tài)

4. 線程安全
//self 是鎖對象
@synchronized(self) {
//執(zhí)行多線程操作
}
5. NSThread的其他api
// 獲得主線程
+ (NSThread *)mainThread;
// 是否為主線程
- (BOOL)isMainThread;
// 是否為主線程
+ (BOOL)isMainThread;
//獲得當前線程
NSThread *current = [NSThread currentThread];
//線程的名字
- (void)setName:(NSString *)n;
- (NSString *)name;
//啟動線程,進入就緒狀態(tài) -> 運行狀態(tài)。當線程任務(wù)執(zhí)行完畢,自動進入死亡狀態(tài)
- (void)start;
//阻塞(暫停)線程
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
//強制停止線程進入死亡狀態(tài)一旦線程停止(死亡)了,就不能再次開啟任務(wù)
+ (void)exit;
//線程間通信常用方法
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait;
6. GCD的任務(wù)和隊列

- 異步函數(shù) + 并發(fā)隊列:可以同時開啟多條線程
/**
* 異步函數(shù) + 并發(fā)隊列:可以同時開啟多條線程
*/
- (void)asyncConcurrent
{
// 1.創(chuàng)建一個并發(fā)隊列
// label : 相當于隊列的名字
// attr : 并行 DISPATCH_QUEUE_CONCURRENT 串行 DISPATCH_QUEUE_SERIAL == NULL
// dispatch_queue_t queue = dispatch_queue_create("wang", DISPATCH_QUEUE_CONCURRENT);
// 1.獲得全局的并發(fā)隊列
//#define DISPATCH_QUEUE_PRIORITY_HIGH 2
//#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
//#define DISPATCH_QUEUE_PRIORITY_LOW (-2)
//#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 2.將任務(wù)加入隊列
dispatch_async(queue, ^{
for (NSInteger i = 0; i<2; i++) {
NSLog(@"1-----%@", [NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for (NSInteger i = 0; i<2; i++) {
NSLog(@"2-----%@", [NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for (NSInteger i = 0; i<2; i++) {
NSLog(@"3-----%@", [NSThread currentThread]);
}
});
// 2017-03-28 17:10:40.609 07-GCD的基本使用[5361:272988] 3-----<NSThread: 0x60800026b9c0>{number = 5, name = (null)}
// 2017-03-28 17:10:40.609 07-GCD的基本使用[5361:272971] 1-----<NSThread: 0x60800026ba80>{number = 3, name = (null)}
// 2017-03-28 17:10:40.609 07-GCD的基本使用[5361:272973] 2-----<NSThread: 0x60800026be40>{number = 4, name = (null)}
// 2017-03-28 17:10:40.614 07-GCD的基本使用[5361:272988] 3-----<NSThread: 0x60800026b9c0>{number = 5, name = (null)}
// 2017-03-28 17:10:40.615 07-GCD的基本使用[5361:272971] 1-----<NSThread: 0x60800026ba80>{number = 3, name = (null)}
// 2017-03-28 17:10:40.615 07-GCD的基本使用[5361:272973] 2-----<NSThread: 0x60800026be40>{number = 4, name = (null)}
}
- 同步函數(shù) + 并發(fā)隊列:不會開啟新的線程
/**
* 同步函數(shù) + 并發(fā)隊列:不會開啟新的線程
*/
- (void)syncConcurrent
{
// 1.獲得全局的并發(fā)隊列
//#define DISPATCH_QUEUE_PRIORITY_HIGH 2
//#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
//#define DISPATCH_QUEUE_PRIORITY_LOW (-2)
//#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 2.將任務(wù)加入隊列
dispatch_sync(queue, ^{
NSLog(@"1-----%@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"2-----%@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"3-----%@", [NSThread currentThread]);
});
// 2017-03-28 17:13:31.051 07-GCD的基本使用[5403:275128] 1-----<NSThread: 0x608000263940>{number = 1, name = main}
// 2017-03-28 17:13:31.053 07-GCD的基本使用[5403:275128] 2-----<NSThread: 0x608000263940>{number = 1, name = main}
// 2017-03-28 17:13:31.054 07-GCD的基本使用[5403:275128] 3-----<NSThread: 0x608000263940>{number = 1, name = main}
}
- 異步函數(shù) + 串行隊列:會開啟新的線程,但是任務(wù)是串行的,執(zhí)行完一個任務(wù),再執(zhí)行下一個任務(wù)
/**
* 異步函數(shù) + 串行隊列:會開啟新的線程,但是任務(wù)是串行的,執(zhí)行完一個任務(wù),再執(zhí)行下一個任務(wù)
*/
- (void)asyncSerial
{
// 1.創(chuàng)建串行隊列
//#define DISPATCH_QUEUE_SERIAL NULL
dispatch_queue_t queue = dispatch_queue_create("wang", NULL);
// 2.將任務(wù)加入隊列
dispatch_async(queue, ^{
NSLog(@"1-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"2-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"3-----%@", [NSThread currentThread]);
});
// 2017-03-28 17:16:02.187 07-GCD的基本使用[5495:278209] 1-----<NSThread: 0x608000262440>{number = 3, name = (null)}
// 2017-03-28 17:16:02.187 07-GCD的基本使用[5495:278209] 2-----<NSThread: 0x608000262440>{number = 3, name = (null)}
// 2017-03-28 17:16:02.188 07-GCD的基本使用[5495:278209] 3-----<NSThread: 0x608000262440>{number = 3, name = (null)}
}
- 同步函數(shù) + 串行隊列:不會開啟新的線程,在當前線程執(zhí)行任務(wù)。任務(wù)是串行的,執(zhí)行完一個任務(wù),再執(zhí)行下一個任務(wù)
/**
* 同步函數(shù) + 串行隊列:不會開啟新的線程,在當前線程執(zhí)行任務(wù)。任務(wù)是串行的,執(zhí)行完一個任務(wù),再執(zhí)行下一個任務(wù)
*/
- (void)syncSerial
{
// 1.創(chuàng)建串行隊列
dispatch_queue_t queue = dispatch_queue_create("wang", DISPATCH_QUEUE_SERIAL);
// 2.將任務(wù)加入隊列
dispatch_sync(queue, ^{
NSLog(@"1-----%@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"2-----%@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"3-----%@", [NSThread currentThread]);
});
// 2017-03-28 17:17:25.275 07-GCD的基本使用[5527:279554] 1-----<NSThread: 0x6000000757c0>{number = 1, name = main}
// 2017-03-28 17:17:25.275 07-GCD的基本使用[5527:279554] 2-----<NSThread: 0x6000000757c0>{number = 1, name = main}
// 2017-03-28 17:17:25.275 07-GCD的基本使用[5527:279554] 3-----<NSThread: 0x6000000757c0>{number = 1, name = main}
}
- 異步函數(shù) + 主隊列:只在主線程中執(zhí)行任務(wù)
/**
* 異步函數(shù) + 主隊列:只在主線程中執(zhí)行任務(wù)
*/
- (void)asyncMain
{
// 1.獲得主隊列
dispatch_queue_t queue = dispatch_get_main_queue();
// 2.將任務(wù)加入隊列
dispatch_async(queue, ^{
NSLog(@"1-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"2-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"3-----%@", [NSThread currentThread]);
});
// 2017-03-28 17:20:38.682 07-GCD的基本使用[5591:282861] 1-----<NSThread: 0x600000065a40>{number = 1, name = main}
// 2017-03-28 17:20:38.683 07-GCD的基本使用[5591:282861] 2-----<NSThread: 0x600000065a40>{number = 1, name = main}
// 2017-03-28 17:20:38.683 07-GCD的基本使用[5591:282861] 3-----<NSThread: 0x600000065a40>{number = 1, name = main}
}
- 同步函數(shù) + 主隊列:堵塞主線程,禁用
/**
* 同步函數(shù) + 主隊列:
*/
- (void)syncMain
{
NSLog(@"syncMain ----- begin");
// 1.獲得主隊列
dispatch_queue_t queue = dispatch_get_main_queue();
// 2.將任務(wù)加入隊列
dispatch_sync(queue, ^{
NSLog(@"1-----%@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"2-----%@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"3-----%@", [NSThread currentThread]);
});
NSLog(@"syncMain ----- end");
}
7. GCD線程間的通信
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//執(zhí)行異步操作
// 回到主線程
dispatch_async(dispatch_get_main_queue(), ^{
//刷新UI
});
});
8. GCD延時執(zhí)行
/**
* 延遲執(zhí)行
*/
- (void)delay
{
//方法1
[self performSelector:@selector(run) withObject:nil afterDelay:2.0];
//方法2
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"延遲執(zhí)行");
});
//方法3
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:NO];
}
8. GCD只執(zhí)行1次的代碼dispatch_once
- (void)once
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"只執(zhí)行1次的代碼dispatch_once");
});
}
9. GCD的dispatch_barrier柵欄
- (void)barrier
{
dispatch_queue_t queue = dispatch_queue_create("12312312", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"----1-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----2-----%@", [NSThread currentThread]);
});
dispatch_barrier_async(queue, ^{
NSLog(@"----barrier-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----3-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----4-----%@", [NSThread currentThread]);
});
// 2017-03-29 10:20:17.716 [1321:43448] ----1-----<NSThread: 0x608000264740>{number = 3, name = (null)}
// 2017-03-29 10:20:17.716 [1321:43722] ----2-----<NSThread: 0x60800007f7c0>{number = 4, name = (null)}
// 2017-03-29 10:20:17.716 [1321:43722] ----barrier-----<NSThread: 0x60800007f7c0>{number = 4, name = (null)}
// 2017-03-29 10:20:17.717 [1321:43722] ----3-----<NSThread: 0x60800007f7c0>{number = 4, name = (null)}
// 2017-03-29 10:20:17.717 [1321:43448] ----4-----<NSThread: 0x608000264740>{number = 3, name = (null)}
}
10. GCD的dispatch_apply
- (void)apply
{
NSMutableArray *arr = [NSMutableArray array];
for (int i=0; i<10; i++) {
[arr addObject:@(i)];
}
dispatch_queue_t queue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(arr.count, queue1, ^(size_t index) {
NSLog(@"%ld",index);
});
// 2017-03-29 10:44:58.489 [1877:73243] 2
// 2017-03-29 10:44:58.489 [1877:73244] 1
// 2017-03-29 10:44:58.489 [1877:73213] 0
// 2017-03-29 10:44:58.489 [1877:73246] 3
// 2017-03-29 10:44:58.489 [1877:73243] 4
// 2017-03-29 10:44:58.489 [1877:73244] 5
// 2017-03-29 10:44:58.489 [1877:73213] 6
// 2017-03-29 10:44:58.489 [1877:73246] 7
// 2017-03-29 10:44:58.489 [1877:73243] 8
// 2017-03-29 10:44:58.490 [1877:73244] 9
}
11. GCD的dispatch_group
- (void)group
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 創(chuàng)建一個隊列組
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{
NSLog(@"1");
});
dispatch_group_async(group, queue, ^{
NSLog(@"2");
});
dispatch_group_notify(group, queue, ^{
NSLog(@"完成了");
});
// 2017-03-29 10:48:53.947 [1939:76156] 2
// 2017-03-29 10:48:53.947 [1939:76157] 1
// 2017-03-29 10:48:53.947 [1939:76157] 完成了
}
11. NSOperation的使用
- (void)blockOperation
{
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
// 在主線程
NSLog(@"下載1------%@", [NSThread currentThread]);
}];
// 添加額外的任務(wù)(在子線程執(zhí)行)
[op addExecutionBlock:^{
NSLog(@"下載2------%@", [NSThread currentThread]);
}];
[op addExecutionBlock:^{
NSLog(@"下載3------%@", [NSThread currentThread]);
}];
[op addExecutionBlock:^{
NSLog(@"下載4------%@", [NSThread currentThread]);
}];
[op start];
}
- (void)invocationOperation
{
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
[op start];
}
- (void)run
{
NSLog(@"------%@", [NSThread currentThread]);
}
12. NSOperationQueue的使用
NSOperationQueue *queue = [[NSOperationQueue alloc] init];是可以開啟線程的,串行和并行通過maxConcurrentOperationCount設(shè)置,為1的時候就是串行。[NSOperationQueue mainQueue]是在主線程執(zhí)行任務(wù)。串行的
- (void)operationQueue1
{
// 創(chuàng)建隊列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 創(chuàng)建操作(任務(wù))
// 創(chuàng)建NSInvocationOperation
NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download1) object:nil];
// 創(chuàng)建NSBlockOperation
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"download3 --- %@", [NSThread currentThread]);
}];
[op3 addExecutionBlock:^{
NSLog(@"download4 --- %@", [NSThread currentThread]);
}];
// 添加任務(wù)到隊列中
[queue addOperation:op1]; // [op1 start]
[queue addOperation:op3]; // [op3 start]
}
- (void)operationQueue2
{
// 創(chuàng)建隊列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock:^{
NSLog(@"download1 --- %@", [NSThread currentThread]);
}];
[queue addOperationWithBlock:^{
NSLog(@"download2 --- %@", [NSThread currentThread]);
}];
}
- (void)opetationQueue3
{
// 創(chuàng)建隊列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 設(shè)置最大并發(fā)操作數(shù)
// queue.maxConcurrentOperationCount = 2;
queue.maxConcurrentOperationCount = 1; // 就變成了串行隊列
// 添加操作
[queue addOperationWithBlock:^{
NSLog(@"download1 --- %@", [NSThread currentThread]);
}];
[queue addOperationWithBlock:^{
NSLog(@"download2 --- %@", [NSThread currentThread]);
}];
}
- (void)suspend
{
if (self.queue.isSuspended) {
// 恢復(fù)隊列,繼續(xù)執(zhí)行
self.queue.suspended = NO;
} else {
// 暫停(掛起)隊列,暫停執(zhí)行
self.queue.suspended = YES;
}
//取消任務(wù)
[self.queue cancelAllOperations];
}
12. 自定義NSOperation的使用
@interface MyOperation : NSOperation
@end
@implementation MyOperation
/**
* 需要執(zhí)行的任務(wù)
*/
- (void)main
{
NSLog(@"需要執(zhí)行的任務(wù)");
}
@end
13. 任務(wù)之間添加依賴addDependency
- (void) addDependency{
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"download1----%@", [NSThread currentThread]);
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"download2----%@", [NSThread currentThread]);
}];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"download3----%@", [NSThread currentThread]);
}];
NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
for (NSInteger i = 0; i<10; i++) {
NSLog(@"download4----%@", [NSThread currentThread]);
}
}];
NSBlockOperation *op5 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"download5----%@", [NSThread currentThread]);
}];
op5.completionBlock = ^{
NSLog(@"op5執(zhí)行完畢---%@", [NSThread currentThread]);
};
// 設(shè)置依賴
[op3 addDependency:op1];
[op3 addDependency:op2];
[op3 addDependency:op4];
[queue addOperation:op1];
[queue addOperation:op2];
[queue addOperation:op3];
[queue addOperation:op4];
[queue addOperation:op5];
}
13. 線程之間的通信
/**
* 線程之間的通信
*/
- (void)test
{
[[[NSOperationQueue alloc] init] addOperationWithBlock:^{
// 圖片的網(wǎng)絡(luò)路徑
NSURL *url = [NSURL URLWithString:@"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg"];
// 加載圖片
NSData *data = [NSData dataWithContentsOfURL:url];
// 生成圖片
UIImage *image = [UIImage imageWithData:data];
// 回到主線程
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.imageView.image = image;
}];
}];
}