· NSThread 可以直接操作線程
· GCD: Grand Central Dispatch (GCD)是Apple開發(fā)的一個多核編程的較新的解決方法狸捅。它主要用于優(yōu)化應用程序以支持多核處理器以及其他對稱多處理系統(tǒng)茅撞。它是一個在線程池模式的基礎上執(zhí)行的并行任務成畦。
· NSOperation 在GCD之上的封裝,更適合添加操作之間的依賴關(guān)系。
NSThread 常用點
- setName 可以定義線程的名字悯搔,方便跟蹤和調(diào)試
- [NSThread currentThread] 可以看當前操作的線程
NSThread *thread = [[NSThread alloc] initWithTarget:self
selector:@selector(threadTest)
object:nil];
[thread setName:@"EasyIOSThread"];
[thread start];
3.最厲害的一點思灌,他可以直接讓線程死亡俺叭,也就是當前沒做完的操作立馬終止
[thread exit];
GCD
- dispatch queue
任務間執(zhí)行的方式
DISPATCH_QUEUE_CONCURRENT 并行
DISPATCH_QUEUE_SERIAL_INACTIVE 串行
同步異步
dispatch_async 開啟異步隊列,具備開啟線程的能力
dispatch_sync 開啟同步隊列泰偿,不會開辟新的線程
1.并行異步
dispatch_queue_t queue = dispatch_queue_create("gcd1.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
for (int index = 0; index < 10; index++) {
NSLog(@"gcd1.queue %@",[NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for (int index = 0; index < 10; index++) {
NSLog(@"gcd2.queue %@",[NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for (int index = 0; index < 10; index++) {
NSLog(@"gcd3.queue %@",[NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for (int index = 0; index < 10; index++) {
NSLog(@"gcd4.queue %@",[NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for (int index = 0; index < 10; index++) {
NSLog(@"gcd5.queue %@",[NSThread currentThread]);
}
});
執(zhí)行結(jié)果
1.gcd1 gcd2 gcd3 gcd4 gcd5 會隨機的打印熄守,也就說是同時執(zhí)行
2.[NSThread currentThread] 不是主線程,且有多個線程
dispatch_async 會從當前的線程切換到新的線程甜奄, DISPATCH_QUEUE_CONCURRENT 并發(fā)執(zhí)行柠横,異步并發(fā)的線程會開啟多條線程,線程的數(shù)量由任務數(shù)量课兄、系統(tǒng)可分配線程數(shù)共同決定
串行異步
dispatch_queue_t queue = dispatch_queue_create("gcd1.queue", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
for (int index = 0; index < 100; index++) {
NSLog(@"gcd1.queue");
}
});
dispatch_async(queue, ^{
for (int index = 0; index < 100; index++) {
NSLog(@"gcd2.queue");
}
});
執(zhí)行結(jié)果
1.gcd1 打印完成后才接著打印gcd2
2.不是在主線程牍氛,線程打印輸出 <NSThread: 0x60400047f500>{number = 8, name = null}
并行同步
dispatch_queue_t queue = dispatch_queue_create("gcd1.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(queue, ^{
for (int index = 0; index < 100; index++) {
NSLog(@"gcd1.queue %@",[NSThread currentThread]);
}
});
dispatch_sync(queue, ^{
for (int index = 0; index < 100; index++) {
NSLog(@"gcd2.queue %@",[NSThread currentThread]);
}
});
串行同步
dispatch_queue_t queue = dispatch_queue_create("gcd1.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(queue, ^{
for (int index = 0; index < 100; index++) {
NSLog(@"gcd1.queue %@",[NSThread currentThread]);
}
});
dispatch_sync(queue, ^{
for (int index = 0; index < 100; index++) {
NSLog(@"gcd2.queue %@",[NSThread currentThread]);
}
});
執(zhí)行結(jié)果
1. 都是在當前線程執(zhí)行紫皇,調(diào)試的時候是在主線程睦刃,所以打印顯示的是 mian 線程
2. 任務是順序打印的
因為是同步任務,所以不會從線程池獲取線程隙姿,只是使用當前線程,任務就只能一個執(zhí)行完成后在執(zhí)行其他的任務
小結(jié)
隊列執(zhí)行方式
串行隊列是一個任務一個任務順序執(zhí)行
并行隊列是可以同時調(diào)度多個任務
任務開啟方式
同步執(zhí)行:不會到線程池里邊獲取子線程
異步執(zhí)行:只要有任務唉擂,就會去獲取新線程 【主隊列只有一條線程餐屎,除外】
兩個重要的隊列
dispatch_get_global_queue 全局隊列,他是一個并發(fā)的隊列
dispatch_get_main_queue() 主隊列玩祟,他是串行的隊列【有且只有主線程】
for (int index = 0; index < 5; index ++) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"dispatch_async %@ %d",[NSThread currentThread],index);
});
dispatch_sync(dispatch_get_global_queue(0, 0), ^{
NSLog(@"dispatch_sync %@ %d",[NSThread currentThread],index);
});
NSLog(@"come here %d",index);
}
運行結(jié)果
1. dispatch_sync 是在當前線程執(zhí)行的 線程打印為<NSThread: 0x604000072980>{number = 1, name = main}
2. dispatch_async 不是在當前線程執(zhí)行的腹缩,線程打印為 <NSThread: 0x60000047ed00>{number = 3, name = (null) 和 <NSThread: 0x604000660340>{number = 4, name = (null)
3. come here 的調(diào)用順序始終在dispatch_sync之后
4. dispatch_sync 和 dispatch_async 打印隨機,也就是說主線程和其他線程交替執(zhí)行
單看 dispatch_async
異步的多個dispatch_get_global_queue 可以在多條線程并發(fā)執(zhí)行
同步的只能在當前線程執(zhí)行 (come here 總是在 dispatch_sync)
dispatch_get_main_queue() 常用地方 - 從別的線程回到主線程
// to main
dispatch_async(dispatch_get_main_queue(), ^{
});
GCD 線程切換注意點:不能用同步的方式切換到同一個串行隊列
例如:
// current queue is main queue
dispatch_sync(dispatch_get_main_queue(), ^{
});
// 如果是非主隊列也如此
dispatch_queue_t queue = dispatch_queue_create("gcd", DISPATCH_QUEUE_SERIAL); dispatch_async(queue, ^{
NSLog(@"外邊的1 %@",[NSThread currentThread]);
dispatch_sync(queue, ^{
NSLog(@"里邊的 %@",[NSThread currentThread]);
});
NSLog(@"外邊的2 %@",[NSThread currentThread]);
});
//但是并發(fā)的隊列不會死鎖
dispatch_queue_t queue = dispatch_queue_create("gcd", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue, ^{
NSLog(@"外邊的1 %@",[NSThread currentThread]);
dispatch_sync(queue, ^{
NSLog(@"里邊的 %@",[NSThread currentThread]);
});
NSLog(@"外邊的2 %@",[NSThread currentThread]);
});
原因
- 串行隊列的任務是順序執(zhí)行的空扎,需要等到前面已經(jīng)入隊的任務執(zhí)行完然后在執(zhí)行后續(xù)任務
- 同步執(zhí)行是在當前的隊列立馬執(zhí)行任務
- 在串行的隊列里邊執(zhí)行同步任務藏鹊,這個同步任務是在隊列的中間插入的,從隊列的執(zhí)行順序看转锈,這個同步任務需要等到他前面的任務執(zhí)行完成后在執(zhí)行盘寡,但是同步任務自身又是不能等待的,他要立馬執(zhí)行撮慨。兩者就產(chǎn)生了死鎖竿痰。
- 從dispatch_sync(dispatch_get_main_queue(), ^{}); 產(chǎn)生死鎖我們也可以確定主隊列是串行的
重要方法 1. dispatch_group_t group, 在dispatch_group_notify 可以讓任務完成后返回
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_queue_create("download_queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_async(group, queue, ^{
for (int index = 0; index < 3; index ++) {
NSLog(@"first task %d",index);
}
});
dispatch_group_async(group, queue, ^{
for (int index = 0; index < 3; index ++) {
NSLog(@"second task %d",index);
}
});
dispatch_group_notify(group, queue, ^{
NSLog(@"task finish");
});
[第280行]: second task 0
[第275行]: first task 0
[第280行]: second task 1
[第275行]: first task 1
[第280行]: second task 2
[第275行]: first task 2
[第284行]: task finish
dispatch_barrier_sync 和 dispatch_barrier_async 柵欄函數(shù)
dispatch_queue_t queue = dispatch_queue_create("gcd1.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
for (int index = 0; index < 10; index++) {
NSLog(@"11111");
}
});
dispatch_async(queue, ^{
for (int index = 0; index < 10; index++) {
NSLog(@"22222");
}
});
dispatch_barrier_sync(queue, ^{
for (int index = 0; index < 10; index++) {
NSLog(@"dispatch_barrier_sync %@",[NSThread currentThread]);
}
return ;
});
NSLog(@"----");
dispatch_async(queue, ^{
for (int index = 0; index < 10; index++) {
NSLog(@"33333");
}
});
dispatch_async(queue, ^{
for (int index = 0; index < 10; index++) {
NSLog(@"44444");
}
});
執(zhí)行結(jié)果
1. 1111 和 2222 隨機打印
2. 打印 dispatch_barrier_sync
3. 打印 ----
4. 33333 和 44444 隨機打印
小結(jié)
dispatch_barrier_sync 和 dispatch_barrier_async 都會將前后的任務隔開,并且要等到前邊的任務執(zhí)行完后砌溺,在執(zhí)行柵欄里邊的任務影涉,然后執(zhí)行后邊的任務。
區(qū)別是 sync 是同步的抚吠, 也就是說當前的線程執(zhí)行到dispatch_barrier_sync 時會去執(zhí)行這個隊列里的任務【如果當前隊列和當前的線程是一個常潮,會死鎖】 dispatch_async 是異步的,不需要切換到該隊列去執(zhí)行
NSOperation 可以很方便管理任務之間的依賴
self.queue = [[NSOperationQueue alloc] init];
[self.queue setName:@"qk.queue.com"];
//第一條線
NSInvocationOperation *firstOperation
= [[NSInvocationOperation alloc]
initWithTarget:self
selector:@selector(firstStep)
object:nil];
[firstOperation setName:@"qk.queue.firstOperation"];
//第二條線
NSInvocationOperation *secondOperation
= [[NSInvocationOperation alloc] initWithTarget:self
selector:@selector(secondStep)
object:nil];
[secondOperation setName:@"qk.queue.secondOperation"];
//前面的要在后邊的執(zhí)行完成后才能夠執(zhí)行
[secondOperation addDependency:firstOperation];
//如果沒有添加依賴關(guān)系 operation 會并發(fā)執(zhí)行
[self.queue addOperation:secondOperation];
[self.queue addOperation:firstOperation];