目錄
一门坷、多線程簡介
1耘眨、多線程的由來
2、耗時操作的模擬試驗
3夯辖、進程和線程
4、多線程的概念及原理
5劝评、多線程的優(yōu)缺點和一個Tip
6姐直、主線程
7、技術方案
二蒋畜、Pthread
1声畏、函數(shù)
2、參數(shù)和返回值
3姻成、使用
三插龄、NSThread
1、創(chuàng)建一個新的線程
2科展、線程的狀態(tài)
3均牢、線程的屬性
四、互斥鎖
1才睹、訪問共享資源引入問題徘跪!
2、互斥鎖介紹
3砂竖、互斥鎖原理
4、互斥鎖和自旋鎖
五鹃答、GCD
1乎澄、GCD介紹
3、函數(shù)
4测摔、串行隊列和并發(fā)隊列
5置济、主隊列
6、全局隊列
7锋八、GCD總結(jié)
六浙于、NSOperation
1、NSOperation簡介
2挟纱、核心概念
3羞酗、操作步驟
4、NSInvocationOperation
5紊服、NSBlockOperation
七檀轨、案例
一、多線程簡介
1欺嗤、多線程的由來
一個進程(進程)在執(zhí)行一個線程(線程中有很多函數(shù)或方法(后面簡稱Function))的時候参萄,其中有一個Function執(zhí)行的時候需要消耗一些時間,但是這個線程又必須同時執(zhí)行這個Function之后的Function煎饼,問題來了讹挎,一個線程中的任何一個Function都必須等待其執(zhí)行完成后才能執(zhí)行后面的Function,如果要同時執(zhí)行兩個或者多個Function,那么筒溃,就必須多開一個或者多個線程马篮,這就是多線程的產(chǎn)生铡羡。我想多線程最開始的誕生就是由這而來吧积蔚!
2、耗時操作的模擬試驗
2.1 循環(huán)測試
代碼
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"bengin");
for (int i = 0; i < 10000000; i++) {
}
NSLog(@"end");
}
return 0;
}
控制臺
2016-02-16 13:51:54.140 Test[1670:603696] bengin
2016-02-16 13:51:54.160 Test[1670:603696] end
Program ended with exit code: 0
結(jié)論一:循環(huán)一億次耗時0.02秒烦周,計算機的運行速度是非尘”快的
2.2 操作棧區(qū)
代碼
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"bengin");
for (int i = 0; i < 10000000; i++) {
int n = 1;
}
NSLog(@"end");
}
return 0;
}
控制臺
2016-02-16 13:57:37.589 Test[1734:631377] bengin
2016-02-16 13:57:37.612 Test[1734:631377] end
Program ended with exit code: 0
結(jié)論二:對棧區(qū)操作一億次,耗時0.023秒
2.3 操作常量區(qū)
代碼:
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"bengin");
for (int i = 0; i < 10000000; i++) {
NSString *str = @"hellow";
}
NSLog(@"end");
}
return 0;
}
控制臺
2016-02-16 14:03:59.003 Test[1763:659287] bengin
2016-02-16 14:03:59.113 Test[1763:659287] end
Program ended with exit code: 0
結(jié)論三:對常量區(qū)操作一億次读慎,耗時0.11秒
2.4 操作堆區(qū)
代碼
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"bengin");
for (int i = 0; i < 10000000; i++) {
NSString *str = [NSString stringWithFormat:@"%d",I];
}
NSLog(@"end");
}
return 0;
}
控制臺
2016-02-16 14:09:03.673 Test[1786:673719] bengin
2016-02-16 14:09:10.705 Test[1786:673719] end
Program ended with exit code: 0
結(jié)論四:對堆區(qū)操作一億次耗時7秒多一些漱贱,較慢!
2.5 I/O操作
代碼
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"bengin");
for (int i = 0; i < 10000000; i++) {
NSLog(@"%d",i);
}
NSLog(@"end");
}
return 0;
}
控制臺輸出夭委!正在跑中幅狮,一億次!V昃摹崇摄!先看截圖
CPU
再看內(nèi)存
好吧,還在跑慌烧,現(xiàn)在已經(jīng)達到10分鐘了逐抑,怕心疼本本炸掉!stop屹蚊。厕氨。。
結(jié)論五:I/O操作非常慢汹粤,一億次10分鐘也沒能跑完命斧!
最終結(jié)論:通過以上結(jié)論一、二嘱兼、三国葬、四、五得出一個結(jié)論芹壕,各個區(qū)的執(zhí)行效率:棧區(qū)>常量區(qū)>堆區(qū)>I/O操作胃惜。同時也說明了一個問題,執(zhí)行不同的方法會產(chǎn)什么耗時操作哪雕。這是船殉,為了解決耗時操作問題,多線程閃亮誕生斯嚎!
3利虫、進程和線程
先說說進程和線程吧挨厚!
3.1 進程
3.1.1 進程的概念:系統(tǒng)中正在運行的應用程序。
3.1.2 進程的特點:每個進程都運行在其專用且受保護的內(nèi)存空間糠惫,不同的進程之間相互獨立疫剃,互不干擾。
3.2 線程
3.2.1 線程的概念:線程是進程的執(zhí)行任務的基本單元硼讽,一個進程的所有任務都是在線程中執(zhí)行的巢价。(每一個進程至少要有一條線程)。
3.2.2 線程的特點:線程在執(zhí)行任務的時候是按順序執(zhí)行的固阁。如果要讓一條線程執(zhí)行多個任務壤躲,那么只能一個一個地并且按順序執(zhí)行這些任務。也就是說备燃,在同一時間碉克,一條線程只能執(zhí)行一個任務。
我們可以通過Mac中的活動監(jiān)視器查看進程和線程并齐,下圖漏麦!
4、多線程的概念及原理
4.1 多線程概念:1個進程可以開啟多條線程况褪,多條線程可以同時執(zhí)行不同的任務撕贞。
4.2 多線程原理:
前提是在單核CPU的情況下,同一時間测垛,CPU只能處理一條線程捏膨,也就是說只有一條線程在執(zhí)行任務。多線程同時執(zhí)行赐纱,那是不可能的脊奋!但是是CPU快速地在多條線程之間進行調(diào)度和切換執(zhí)行任務熬北。如果CPU調(diào)度線程的速度足夠快疙描,就會造成多條線程同時執(zhí)行任務的”假象”,這種假象讶隐,就被美譽為:多線程!
5起胰、多線程的優(yōu)缺點和一個Tip
5.1 多線程的優(yōu)點
可以適當提高程序的執(zhí)行效率
-
也可以適當提高資源的利用率(CPU、內(nèi)存利用率)
5.2 多線程的缺點
開啟一條線程需要占用一定的內(nèi)存空間(默認情況下巫延,每一條線程都占用512KB)效五,如果開啟大量的線程,會占用大量的內(nèi)存空間炉峰,從而降低程序的性能畏妖。
線程越多,CPU在調(diào)度和切換線程上的開銷就會越大疼阔。
-
線程數(shù)越多戒劫,程序的設計會越復雜半夷。
5.3 Tip
-
開啟新的線程就會消耗資源,但是卻可以提高用戶體驗迅细。在保證良好的用戶體驗的前提下巫橄,可以適當?shù)亻_線程,一般開3-6條茵典。
842039-20161007133703785-321985059.jpg
開啟一條新的線程湘换,默認情況下,一條線程都是占用512KB统阿,但是官方的文檔里面給出的說明卻不是彩倚,為了得出真相,下面做個小小的測試砂吞!
代碼
int main(int argc, const char * argv[]) {
@autoreleasepool {
/** 操作主線程 /
NSLog(@"主線程默認 %tu", [NSThread currentThread].stackSize / 1024);
// 設置主線程的stackSize
[NSThread currentThread].stackSize = 1024 1024;
NSLog(@"主線程修改 %tu", [NSThread currentThread].stackSize / 1024);
/** 操作子線程 */
NSThread *thread = [[NSThread alloc] init];
NSLog(@"thread默認 %tu", thread.stackSize / 1024);
// 設置子線程的stackSize
thread.stackSize = 8 * 1024;
NSLog(@"thread修改 %tu", thread.stackSize / 1024);
[thread start];
}
return 0;
}
控制臺
2016-02-17 08:36:02.652 Test[609:110129] 主線程默認 512
2016-02-17 08:36:02.654 Test[609:110129] 主線程修改 1024
2016-02-17 08:36:02.654 Test[609:110129] thread默認 512
2016-02-17 08:36:02.654 Test[609:110129] thread修改 8
結(jié)論七:證明了署恍,不管什么線程,默認都是512蜻直,最小為8.可能是官方文檔沒有及時更新吧盯质!
6、主線程
6.1 主線程的概念:
一個應用程序在啟動運行后概而,系統(tǒng)會自動開啟1條線程呼巷,這條稱為”主線程”。
6.2 主線程的作用:主線程的作用主要用于處理UI界面刷新和UI時間赎瑰!
6.3 結(jié)論:主線程上不能執(zhí)行耗時操作王悍,這樣會造成界面卡頓,給用戶一種不好的體驗餐曼。
7压储、技術方案
二、Pthread
1源譬、函數(shù)
pthread_create(pthread_t *restrict, const pthread_attr_t *restrict, void *(*)(void *), void *restrict)
2集惋、參數(shù)和返回值
pthread_t *restrict 線程編號的地址
const pthread_attr_t *restrict 線程的屬性
-
void ()(void ) 線程要執(zhí)行的函數(shù)void * () (void *)
- int * 指向int類型的指針 void * 指向任何類型的指針 有點類似OC中的id
void *restrict 要執(zhí)行的函數(shù)的參數(shù)
返回值 int類型 0是成功 非0 是失敗
3、使用
代碼
#import <Foundation/Foundation.h>
#import <pthread/pthread.h>
void *demo(void *param) {
NSString *name = (__bridge NSString *)(param);
NSLog(@"hello %@ %@",name,[NSThread currentThread]);
return NULL;
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
//創(chuàng)建子線程
pthread_t pthread; //線程編號
NSString *test = @"test";
int result = pthread_create(&pthread, NULL, demo, (__bridge void *)(test));
NSLog(@"Began %@",[NSThread currentThread]);
if (result == 0) {
NSLog(@"成功");
}else {
NSLog(@"失敗");
}
}
return 0;
}
控制臺
2016-02-16 22:00:57.401 Test[888:42585] Began <NSThread: x100502d70>{number = 1, name = main}
2016-02-16 22:00:57.403 Test[888:42615] hello test <NSThread: x100102a30>{number = 2, name = (null)}
2016-02-16 22:00:57.403 Test[888:42585] 成功
-
__bridge 橋接踩娘,把OC中的對象刮刑,傳遞給c語言的函數(shù),使用__bridge
三养渴、NSThread
1雷绢、創(chuàng)建一個新的線程
-
方式一
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(demo) object:nil];
方式二
[NSThread detachNewThreadSelector:@selector(demo) toTarget:self withObject:nil];
方式三
[self performSelectorInBackground:@selector(demo) withObject:nil];
2、線程的狀態(tài)
線程狀態(tài)分為五種
- 創(chuàng)建 New
- 就緒 Runnable
- 運行 Running
- (void)start;
- 阻塞(暫停) Blocked
+ (void)sleepUntilDate:(NSDate *)date; + (void)sleepForTimeInterval:(NSTimeInterval)ti;</pre>
- 死亡 Dead
+ (void)exit;
3理卑、線程的屬性
3翘紊、線程的屬性
線程有兩個重要的屬性:名稱和優(yōu)先級
3.1 名稱 name
設置線程名用于記錄線程,在出現(xiàn)異常時可以DeBug
3.2 優(yōu)先級藐唠,也叫做“服務質(zhì)量”帆疟。threadPriority孵滞,取值0到1.
優(yōu)先級或者服務質(zhì)量高的,可以優(yōu)先調(diào)用鸯匹,只是說會優(yōu)先調(diào)用坊饶,但是不是百分之百的優(yōu)先調(diào)用,這里存在一個概率問題殴蓬,內(nèi)核里的算法調(diào)度線程的時候匿级,只是把優(yōu)先級作為一個考慮因素,還有很多個因數(shù)會決定哪個線程優(yōu)先調(diào)用染厅。這點得注意注意6灰铩!肖粮!
下面是測試代碼
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
//新建狀態(tài)
NSThread *test1 = [[NSThread alloc] initWithTarget:self selector:@selector(demo) object:nil];
test1.name = @"test1";
//線程的優(yōu)先級
test1.threadPriority = 1.0;
//就緒狀態(tài)
[test1 start];
//新建狀態(tài)
NSThread *test2= [[NSThread alloc] initWithTarget:self selector:@selector(demo) object:nil];
test2.name = @"test2";
test2.threadPriority = 0;
//就緒狀態(tài)
[test2 start];
}
//線程執(zhí)行完成之后會自動銷毀
- (void)demo {
for (int i = 0; i < 20; i++) {
NSLog(@"%d--%@",i,[NSThread currentThread]);
}
}
控制臺
2016-02-16 22:43:28.182 05-線程狀態(tài)[1241:78688] 0--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.182 05-線程狀態(tài)[1241:78689] 0--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.182 05-線程狀態(tài)[1241:78688] 1--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.182 05-線程狀態(tài)[1241:78688] 2--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.182 05-線程狀態(tài)[1241:78689] 1--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.183 05-線程狀態(tài)[1241:78688] 3--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.183 05-線程狀態(tài)[1241:78689] 2--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.183 05-線程狀態(tài)[1241:78688] 4--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.183 05-線程狀態(tài)[1241:78688] 5--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.183 05-線程狀態(tài)[1241:78689] 3--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.183 05-線程狀態(tài)[1241:78688] 6--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.183 05-線程狀態(tài)[1241:78688] 7--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.183 05-線程狀態(tài)[1241:78689] 4--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.183 05-線程狀態(tài)[1241:78688] 8--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.184 05-線程狀態(tài)[1241:78688] 9--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.184 05-線程狀態(tài)[1241:78688] 10--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.184 05-線程狀態(tài)[1241:78689] 5--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.184 05-線程狀態(tài)[1241:78688] 11--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.184 05-線程狀態(tài)[1241:78689] 6--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.184 05-線程狀態(tài)[1241:78688] 12--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.184 05-線程狀態(tài)[1241:78688] 13--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.184 05-線程狀態(tài)[1241:78689] 7--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.184 05-線程狀態(tài)[1241:78688] 14--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.184 05-線程狀態(tài)[1241:78688] 15--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.185 05-線程狀態(tài)[1241:78688] 16--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.184 05-線程狀態(tài)[1241:78689] 8--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.185 05-線程狀態(tài)[1241:78688] 17--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.185 05-線程狀態(tài)[1241:78688] 18--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.185 05-線程狀態(tài)[1241:78689] 9--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.185 05-線程狀態(tài)[1241:78688] 19--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.185 05-線程狀態(tài)[1241:78689] 10--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.186 05-線程狀態(tài)[1241:78689] 11--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.186 05-線程狀態(tài)[1241:78689] 12--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.186 05-線程狀態(tài)[1241:78689] 13--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.186 05-線程狀態(tài)[1241:78689] 14--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.187 05-線程狀態(tài)[1241:78689] 15--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.187 05-線程狀態(tài)[1241:78689] 16--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.187 05-線程狀態(tài)[1241:78689] 17--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.187 05-線程狀態(tài)[1241:78689] 18--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.187 05-線程狀態(tài)[1241:78689] 19--<NSThread: x7fead050a250>{number = 3, name = test2}
結(jié)論六:優(yōu)先級高孤页,不一定先執(zhí)行,只能說明先執(zhí)行的概率要大一些I荨P惺!
四魂那、互斥鎖
1蛾号、訪問共享資源引入問題!
1.1 問題涯雅?
不同的線程要訪問共享的資源鲜结,而且對共享的資源做操作,由于上面結(jié)論六
得出服務質(zhì)量和優(yōu)先級不能決定線程執(zhí)行的先后順序活逆,那么問題來了精刷,一個線程對共享資源做了修改,而另外一個線程拿到的是未被修改之前資源蔗候,這是這個線程也對該資源做了修改怒允,現(xiàn)在請問,兩個線程都對該資源做了不同的修改琴庵,那么這個修改應該算誰的误算?Q雒馈迷殿?!這就是問題所在?г印G焖隆!
1.2 問題分析
1.3 問題解決
這個文檔里盜的圖诉字!
解決方案很簡單懦尝,就是用一把鎖鎖住共享資源知纷,等待線程1對其操作完畢后再打開,讓線程2來執(zhí)行陵霉,這就是傳說中的互斥鎖
@旁!踊挠!
2乍桂、互斥鎖介紹
2.1 互斥鎖代碼
@synchronized(鎖對象) { 需要鎖定的代碼 }
2.2 互斥鎖的作用
可以防止因多線程執(zhí)行順序不定導致的搶奪資源造成的數(shù)據(jù)安全的問題
2.3 真相:互斥鎖其實就是同步的意思,也就是按順序執(zhí)行效床!
3睹酌、互斥鎖原理
每個NSObject對象內(nèi)部都有一把鎖,當線程要進入synchronized到對象的時候就要判斷剩檀,鎖是否被打開憋沿,如果打開,進入執(zhí)行沪猴,如果鎖住辐啄,繼續(xù)等待,這就是互斥鎖的原理运嗜!
4则披、互斥鎖和自旋鎖
自旋鎖就是atomic!
4.1 原子屬性和非原子屬性(nonatomic 和 atomic)
- nonatomic:非原子屬性洗出,不會為 setter 方法加鎖士复。
- atomic: 原子屬性,為 setter 方法加鎖(默認就是atomic)翩活。
- 通過給 setter 加鎖阱洪,可以保證同一時間只有一個線程能夠執(zhí)行寫入操作(setter),但是同一時間允許多個線程執(zhí)行讀取操作(getter)菠镇。atomic本身就有一把自旋鎖冗荸。
這個特點叫做”單寫多讀”: 單個線程寫入,多個線程讀取利耍。 - atomic 只能保證寫入數(shù)據(jù)的時候是安全的蚌本,但不能保證同時讀寫的時候是安全的。所以隘梨,不常使用程癌!
- 通過給 setter 加鎖阱洪,可以保證同一時間只有一個線程能夠執(zhí)行寫入操作(setter),但是同一時間允許多個線程執(zhí)行讀取操作(getter)菠镇。atomic本身就有一把自旋鎖冗荸。
4.2 nonatomic 和 atomic 的對比
atomic:線程安全(執(zhí)行setter方法的時候),需要消耗大量的資源轴猎。
nonatomic:非線程安全嵌莉,適合內(nèi)存小的移動設備。
4.3 互斥鎖和自旋鎖的區(qū)別
互斥鎖
如果發(fā)現(xiàn)其它線程正在執(zhí)行鎖定代碼捻脖,線程會進入休眠(阻塞狀態(tài))锐峭,等其它線程時間片到了打開鎖后中鼠,線程就會被喚醒(執(zhí)行)。
自旋鎖
如果發(fā)現(xiàn)有其它線程正在執(zhí)行鎖定代碼沿癞,線程會以死循環(huán)的方式援雇,一直等待鎖定的代碼執(zhí)行完成。
五椎扬、GCD
1熊杨、GCD介紹
全稱Grand Central Dispatch,可翻譯為”牛逼的中樞調(diào)度器”
純C語言開發(fā),是蘋果公司為多核的并行運算提出的解決方案盗舰,會自動利用更多的CPU內(nèi)核(比如雙核晶府、四核),可以自動管理線程的生命周期(創(chuàng)建線程钻趋、調(diào)度任務川陆、銷毀線程)。
2蛮位、GCD的兩個核心
2.1 任務
- 執(zhí)行的操作,在GCD中较沪,任務是通過 block來封裝的。并且任務的block沒有參數(shù)也沒有返回值失仁。
2.2 隊列
- 存放任務
包括
- 串行隊列
- 并發(fā)隊列
- 主隊列
- 全局隊列
隊列的類型
3尸曼、函數(shù)
3.1 GCD函數(shù)
3.1.1 同步 dispatch_sync
同步:任務會在當前線程執(zhí)行,因為同步函數(shù)不具備開新線程的能力萄焦。
void dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
3.1.2 異步 dispatch_async
異步:任務會在子線程執(zhí)行控轿,因為異步函數(shù)具備開新線程的能力。
void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
3.2 GCD使用步驟:
創(chuàng)建隊列拂封,或則獲取隊列
創(chuàng)建任務
將任務添加到隊列中
GCD會自動將隊列中的任務取出茬射,放到對應的線程中執(zhí)行
任務取出遵循隊列的FIFO原則:先進先出,后進后出
示例代碼
// 1. 獲取全局隊列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
// 2. 創(chuàng)建任務
dispatch_block_t task = ^ {
NSLog(@"hello %@", [NSThread currentThread]);
};
// 3. 將任務添加到隊列冒签,并且指定執(zhí)行任務的函數(shù)
dispatch_async(queue, task);
通常寫成一句代碼
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"hello %@", [NSThread currentThread]);
});
4在抛、串行隊列和并發(fā)隊列
4.1 串行隊列 (Serial Dispatch Queue)
4.1.1 特點
先進先出,按照順序執(zhí)行,并且一次只能調(diào)用一個任務
無論隊列中所指定的執(zhí)行任務的函數(shù)是同步還是異步萧恕,都必須等待前一個任務執(zhí)行完畢才可以調(diào)用后面的人
4.1.2 創(chuàng)建一個串行隊列
方法一
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL);
方法二
dispatch_queue_t queue = dispatch_queue_create("test", NULL);
4.1.3 串行隊列刚梭,同步執(zhí)行
代碼:
// 1、創(chuàng)建串行隊列
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL);
// 2票唆、將任務添加到隊列朴读,并且指定同步執(zhí)行
for (int i = 0; i < 10; i++) {
dispatch_sync(queue, ^{
NSLog(@"%@--%d",[NSThread currentThread],i);
});
}
打印結(jié)果:
2016-02-25 16:31:07.849 test[1924:376468] <NSThread: 0x7ff040404370>{number = 1, name = main}--0
2016-02-25 16:31:07.849 test[1924:376468] <NSThread: 0x7ff040404370>{number = 1, name = main}--1
2016-02-25 16:31:07.849 test[1924:376468] <NSThread: 0x7ff040404370>{number = 1, name = main}--2
2016-02-25 16:31:07.849 test[1924:376468] <NSThread: 0x7ff040404370>{number = 1, name = main}--3
2016-02-25 16:31:07.849 test[1924:376468] <NSThread: 0x7ff040404370>{number = 1, name = main}--4
2016-02-25 16:31:07.849 test[1924:376468] <NSThread: 0x7ff040404370>{number = 1, name = main}--5
2016-02-25 16:31:07.850 test[1924:376468] <NSThread: 0x7ff040404370>{number = 1, name = main}--6
2016-02-25 16:31:07.850 test[1924:376468] <NSThread: 0x7ff040404370>{number = 1, name = main}--7
2016-02-25 16:31:07.850 test[1924:376468] <NSThread: 0x7ff040404370>{number = 1, name = main}--8
2016-02-25 16:31:07.850 test[1924:376468] <NSThread: 0x7ff040404370>{number = 1, name = main}--9
結(jié)論:串行隊列,同步執(zhí)行惰说,不開新線程磨德,按順序執(zhí)行
4.1.4 串行隊列缘回,異步執(zhí)行
代碼:
// 1吆视、創(chuàng)建串行隊列
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL);
// 2典挑、將任務添加到隊列,并且指定同步執(zhí)行
for (int i = 0; i < 10; i++) {
dispatch_async(queue, ^{
NSLog(@"%@--%d",[NSThread currentThread],i);
});
}
打印結(jié)果:
2016-02-25 17:08:32.167 test[1959:391722] <NSThread: 0x7fbb98d24fa0>{number = 2, name = (null)}--0
2016-02-25 17:08:32.168 test[1959:391722] <NSThread: 0x7fbb98d24fa0>{number = 2, name = (null)}--1
2016-02-25 17:08:32.168 test[1959:391722] <NSThread: 0x7fbb98d24fa0>{number = 2, name = (null)}--2
2016-02-25 17:08:32.168 test[1959:391722] <NSThread: 0x7fbb98d24fa0>{number = 2, name = (null)}--3
2016-02-25 17:08:32.168 test[1959:391722] <NSThread: 0x7fbb98d24fa0>{number = 2, name = (null)}--4
2016-02-25 17:08:32.168 test[1959:391722] <NSThread: 0x7fbb98d24fa0>{number = 2, name = (null)}--5
2016-02-25 17:08:32.169 test[1959:391722] <NSThread: 0x7fbb98d24fa0>{number = 2, name = (null)}--6
2016-02-25 17:08:32.169 test[1959:391722] <NSThread: 0x7fbb98d24fa0>{number = 2, name = (null)}--7
2016-02-25 17:08:32.169 test[1959:391722] <NSThread: 0x7fbb98d24fa0>{number = 2, name = (null)}--8
2016-02-25 17:08:32.169 test[1959:391722] <NSThread: 0x7fbb98d24fa0>{number = 2, name = (null)}--9
結(jié)論:串行隊列啦吧,異步執(zhí)行您觉,開啟一條新的線程,按順序執(zhí)行
4.2 并發(fā)隊列 (Concurrent Dispatch Queue)
4.2.1 特點
并發(fā)同時調(diào)度隊列中的任務去執(zhí)行
如果當前調(diào)度的任務是同步執(zhí)行的授滓,會等待當前任務執(zhí)行完畢后琳水,再調(diào)度后續(xù)的任務
如果當前調(diào)度的任務是異步執(zhí)行的,同時底層線程池有可用的線程資源般堆,就不會等待當前任務在孝,直接調(diào)度任務到新線程去執(zhí)行。
4.2.2 創(chuàng)建并發(fā)隊列
dispatch_queue_t q = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
4.2.3 并發(fā)隊列淮摔,同步執(zhí)行
代碼:
// 1. 創(chuàng)建并發(fā)隊列
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
// 2. 將任務添加到隊列, 并且指定同步執(zhí)行
for (int i = 0; i < 10; i++) {
dispatch_sync(queue, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
});
}
輸出:
2016-02-25 17:18:38.039 test[1979:399667] <NSThread: 0x7ffef86024b0>{number = 1, name = main} 0
2016-02-25 17:18:38.040 test[1979:399667] <NSThread: 0x7ffef86024b0>{number = 1, name = main} 1
2016-02-25 17:18:38.040 test[1979:399667] <NSThread: 0x7ffef86024b0>{number = 1, name = main} 2
2016-02-25 17:18:38.040 test[1979:399667] <NSThread: 0x7ffef86024b0>{number = 1, name = main} 3
2016-02-25 17:18:38.040 test[1979:399667] <NSThread: 0x7ffef86024b0>{number = 1, name = main} 4
2016-02-25 17:18:38.040 test[1979:399667] <NSThread: 0x7ffef86024b0>{number = 1, name = main} 5
2016-02-25 17:18:38.040 test[1979:399667] <NSThread: 0x7ffef86024b0>{number = 1, name = main} 6
2016-02-25 17:18:38.040 test[1979:399667] <NSThread: 0x7ffef86024b0>{number = 1, name = main} 7
2016-02-25 17:18:38.040 test[1979:399667] <NSThread: 0x7ffef86024b0>{number = 1, name = main} 8
2016-02-25 17:18:38.041 test[1979:399667] <NSThread: 0x7ffef86024b0>{number = 1, name = main} 9
結(jié)論:并發(fā)隊列私沮,同步執(zhí)行,不開線程和橙,順序執(zhí)行
4.2.4 并發(fā)隊列仔燕,異步執(zhí)行
代碼:
// 1. 創(chuàng)建并發(fā)隊列
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
// 2. 將任務添加到隊列, 并且指定同步執(zhí)行
for (int i = 0; i < 10; i++) {
dispatch_async(queue, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
});
}
輸出:
2016-02-25 17:22:59.357 test[1992:403694] <NSThread: 0x7fe531c1a9b0>{number = 7, name = (null)} 6
2016-02-25 17:22:59.356 test[1992:403684] <NSThread: 0x7fe531d18fa0>{number = 3, name = (null)} 1
2016-02-25 17:22:59.356 test[1992:403689] <NSThread: 0x7fe534300610>{number = 5, name = (null)} 3
2016-02-25 17:22:59.356 test[1992:403683] <NSThread: 0x7fe531e94d80>{number = 2, name = (null)} 0
2016-02-25 17:22:59.356 test[1992:403692] <NSThread: 0x7fe531e9df80>{number = 6, name = (null)} 4
2016-02-25 17:22:59.356 test[1992:403693] <NSThread: 0x7fe531d18f40>{number = 8, name = (null)} 5
2016-02-25 17:22:59.356 test[1992:403695] <NSThread: 0x7fe5343015e0>{number = 9, name = (null)} 7
2016-02-25 17:22:59.357 test[1992:403688] <NSThread: 0x7fe531c16e30>{number = 4, name = (null)} 2
2016-02-25 17:22:59.357 test[1992:403694] <NSThread: 0x7fe531c1a9b0>{number = 7, name = (null)} 9
2016-02-25 17:22:59.357 test[1992:403696] <NSThread: 0x7fe531c237a0>{number = 10, name = (null)} 8
結(jié)論:開啟足夠多的線程,不按照順序執(zhí)行
CPU在調(diào)度的時候以最高效的方式調(diào)度和執(zhí)行任務魔招,所以會開啟多條線程晰搀,因為并發(fā),執(zhí)行順序不一定
5办斑、主隊列
5.1 主隊列
主隊列是系統(tǒng)提供的外恕,無需自己創(chuàng)建,可以通過dispatch_get_main_queue()函數(shù)來獲取乡翅。
5.2 特點
添加到主隊列的任務只能由主線程來執(zhí)行吁讨。
-
先進先出的,只有當主線程的代碼執(zhí)行完畢后峦朗,主隊列才會調(diào)度任務到主線程執(zhí)行
5.3 主隊列 異步執(zhí)行
代碼
// 1. 獲取主隊列
dispatch_queue_t q = dispatch_get_main_queue();
// 2. 將任務添加到主隊列, 并且指定異步執(zhí)行
for (int i = 0; i < 10; i++) {
dispatch_async(q, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
});
}
// 先執(zhí)行完這句代碼, 才會執(zhí)行主隊列中的任務
NSLog(@"hello %@", [NSThread currentThread]);
打印
2016-02-25 21:10:43.293 test[773:786816] hello <NSThread: 0x7ff158c05940>{number = 1, name = main}
2016-02-25 21:10:43.295 test[773:786816] <NSThread: 0x7ff158c05940>{number = 1, name = main} 0
2016-02-25 21:10:43.295 test[773:786816] <NSThread: 0x7ff158c05940>{number = 1, name = main} 1
2016-02-25 21:10:43.296 test[773:786816] <NSThread: 0x7ff158c05940>{number = 1, name = main} 2
2016-02-25 21:10:43.296 test[773:786816] <NSThread: 0x7ff158c05940>{number = 1, name = main} 3
2016-02-25 21:10:43.296 test[773:786816] <NSThread: 0x7ff158c05940>{number = 1, name = main} 4
2016-02-25 21:10:43.296 test[773:786816] <NSThread: 0x7ff158c05940>{number = 1, name = main} 5
2016-02-25 21:10:43.296 test[773:786816] <NSThread: 0x7ff158c05940>{number = 1, name = main} 6
2016-02-25 21:10:43.296 test[773:786816] <NSThread: 0x7ff158c05940>{number = 1, name = main} 7
2016-02-25 21:10:43.296 test[773:786816] <NSThread: 0x7ff158c05940>{number = 1, name = main} 8
2016-02-25 21:10:43.296 test[773:786816] <NSThread: 0x7ff158c05940>{number = 1, name = main} 9
打印結(jié)果得出的一些結(jié)論
在主線程順序執(zhí)行建丧,不開啟新的線程
主隊列的特點:只有當主線程空閑時,主隊列才會調(diào)度任務到主線程執(zhí)行
主隊列就算是異步執(zhí)行也不會開啟新的線程
主隊列相當于一個全局的串行隊列
主隊列和串行隊列的區(qū)別
串行隊列:必須等待一個任務執(zhí)行完畢波势,才會調(diào)度下一個任務翎朱。
主隊列:如果主線程上有代碼執(zhí)行,主隊列就不調(diào)度任務尺铣。
5.4 主隊列 同步執(zhí)行(死鎖)
代碼
NSLog(@"begin");
// 1. 獲取主隊列
dispatch_queue_t q = dispatch_get_main_queue();
// 2. 將任務添加到主隊列, 并且指定同步執(zhí)行
// 死鎖
for (int i = 0; i < 10; i++) {
dispatch_sync(q, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
});
}
NSLog(@"end");
打印
2016-02-25 21:19:25.986 test[791:790967] begin
打印結(jié)果可以看出拴曲,不是想要的結(jié)果,這時候發(fā)生了死鎖
在主線程執(zhí)行凛忿,主隊列同步執(zhí)行任務澈灼,會發(fā)生死鎖,主線程和主隊列同步任務相互等待,造成死鎖
解決辦法
代碼
NSLog(@"begin");
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"--- %@", [NSThread currentThread]);
// 1. 獲取主隊列
dispatch_queue_t q = dispatch_get_main_queue();
// 2. 將任務添加到主隊列, 并且指定同步執(zhí)行
// 死鎖
for (int i = 0; i < 10; i++) {
dispatch_sync(q, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
});
}
});
NSLog(@"end");
打印
2016-02-25 21:23:23.205 test[803:794826] begin
2016-02-25 21:23:23.206 test[803:794826] end
2016-02-25 21:23:23.206 test[803:794866] --- <NSThread: 0x7f8830514cb0>{number = 2, name = (null)}
2016-02-25 21:23:23.209 test[803:794826] <NSThread: 0x7f8830507dd0>{number = 1, name = main} 0
2016-02-25 21:23:23.209 test[803:794826] <NSThread: 0x7f8830507dd0>{number = 1, name = main} 1
2016-02-25 21:23:23.209 test[803:794826] <NSThread: 0x7f8830507dd0>{number = 1, name = main} 2
2016-02-25 21:23:23.209 test[803:794826] <NSThread: 0x7f8830507dd0>{number = 1, name = main} 3
2016-02-25 21:23:23.209 test[803:794826] <NSThread: 0x7f8830507dd0>{number = 1, name = main} 4
2016-02-25 21:23:23.210 test[803:794826] <NSThread: 0x7f8830507dd0>{number = 1, name = main} 5
2016-02-25 21:23:23.210 test[803:794826] <NSThread: 0x7f8830507dd0>{number = 1, name = main} 6
2016-02-25 21:23:23.210 test[803:794826] <NSThread: 0x7f8830507dd0>{number = 1, name = main} 7
2016-02-25 21:23:23.210 test[803:794826] <NSThread: 0x7f8830507dd0>{number = 1, name = main} 8
2016-02-25 21:23:23.210 test[803:794826] <NSThread: 0x7f8830507dd0>{number = 1, name = main} 9
打印結(jié)果可以看出叁熔,當我們將主隊列同步執(zhí)行任務放到子線程去執(zhí)行委乌,就不會出現(xiàn)死鎖。由于將主隊列同步放到了子線程中執(zhí)行荣回,主隊列同步任務無法阻塞主線程執(zhí)行代碼遭贸,因此主線程可以將主線程上的代碼執(zhí)行完畢。當主線程執(zhí)行完畢之后心软,就會執(zhí)行主隊列里面的任務壕吹。
6、全局隊列
全局隊列是系統(tǒng)提供的删铃,無需自己創(chuàng)建耳贬,可以直接通過dispatch_get_global_queue(long identifier, unsigned long flags);函數(shù)來獲取。
6.1 全局隊列 異步執(zhí)行
代碼
// 1. 獲取全局隊列
dispatch_queue_t q = dispatch_get_global_queue(0, 0);
// 2. 將任務添加到全局隊列, 異步執(zhí)行
for (int i = 0; i < 10; i++) {
dispatch_async(q, ^{
NSLog(@"%d %@", i, [NSThread currentThread]);
});
}
打印輸出
2016-02-25 21:29:06.978 test[816:799523] 1 <NSThread: 0x7fd428e15760>{number = 3, name = (null)}
2016-02-25 21:29:06.978 test[816:799530] 4 <NSThread: 0x7fd428d2fbb0>{number = 6, name = (null)}
2016-02-25 21:29:06.978 test[816:799522] 0 <NSThread: 0x7fd428f094e0>{number = 2, name = (null)}
2016-02-25 21:29:06.978 test[816:799529] 3 <NSThread: 0x7fd428c0e1b0>{number = 5, name = (null)}
2016-02-25 21:29:06.978 test[816:799532] 6 <NSThread: 0x7fd428f06740>{number = 7, name = (null)}
2016-02-25 21:29:06.978 test[816:799533] 7 <NSThread: 0x7fd428d37be0>{number = 8, name = (null)}
2016-02-25 21:29:06.978 test[816:799531] 5 <NSThread: 0x7fd428e0c490>{number = 9, name = (null)}
2016-02-25 21:29:06.978 test[816:799526] 2 <NSThread: 0x7fd428d3e4b0>{number = 4, name = (null)}
2016-02-25 21:29:06.979 test[816:799534] 8 <NSThread: 0x7fd428d36ab0>{number = 10, name = (null)}
2016-02-25 21:29:06.979 test[816:799523] 9 <NSThread: 0x7fd428e15760>{number = 3, name = (null)}
特點:
1猎唁、全局隊列的工作特性跟并發(fā)隊列一致效拭。 實際上,全局隊列就是系統(tǒng)為了方便程序員胖秒,專門提供的一種特殊的并發(fā)隊列缎患。
2、全局隊列和并發(fā)隊列的區(qū)別:
- 全局隊列沒有名稱阎肝,無論ARC還是MRC都不需要考慮內(nèi)存釋放魁巩,日常開發(fā)侮繁,建議使用全局隊列
- 并發(fā)隊列有名稱,如果在MRC開發(fā)中,需要使用dispatch_release來釋放相應的對象信粮,dispatch_barrier 必須使用自定義的并發(fā)隊列搀菩,開發(fā)第三方框架缕题,建議使用并發(fā)隊列
3摄狱、函數(shù)
dispatch_get_global_queue(long identifier, unsigned long flags);
這個函數(shù)中有兩個參數(shù):
第一個參數(shù): identifier
iOS7.0,表示的是優(yōu)先級:
DISPATCH_QUEUE_PRIORITY_HIGH = 2; 高優(yōu)先級
DISPATCH_QUEUE_PRIORITY_DEFAULT = 0; 默認優(yōu)先級
DISPATCH_QUEUE_PRIORITY_LOW = -2; 低優(yōu)先級
DISPATCH_QUEUE_PRIORITY_BACKGROUND = INT16_MIN; 后臺優(yōu)先級
iOS8.0開始摇肌,推薦使用服務質(zhì)量(QOS):
QOS_CLASS_USER_INTERACTIVE = 0x21; 用戶交互
QOS_CLASS_USER_INITIATED = 0x19; 用戶期望
QOS_CLASS_DEFAULT = 0x15; 默認
QOS_CLASS_UTILITY = 0x11; 實用工具
QOS_CLASS_BACKGROUND = 0x09; 后臺
QOS_CLASS_UNSPECIFIED = 0x00; 未指定
通過對比可知: 第一個參數(shù)傳入0擂红,可以同時適配iOS7及iOS7以后的版本。
服務質(zhì)量和優(yōu)先級是一一對應的:
DISPATCH_QUEUE_PRIORITY_HIGH: QOS_CLASS_USER_INITIATED
DISPATCH_QUEUE_PRIORITY_DEFAULT: QOS_CLASS_DEFAULT
DISPATCH_QUEUE_PRIORITY_LOW: QOS_CLASS_UTILITY
DISPATCH_QUEUE_PRIORITY_BACKGROUND: QOS_CLASS_BACKGROUND
第二個參數(shù): flags
為未來保留使用的围小,始終傳入0昵骤。
Reserved for future use.
7、GCD總結(jié)
1肯适、開不開線程变秦,由執(zhí)行任務的函數(shù)決定
- 同步執(zhí)行不開線程
- 異步執(zhí)行開線程
2、異步執(zhí)行任務框舔,開幾條線程由隊列決定
- 串行隊列蹦玫,只會開一條線程赎婚,因為一條就足夠了
- 并發(fā)隊列,可以開多條線程樱溉,具體開幾條由線程池決定
對主隊列而言挣输,不管是同步執(zhí)行還是異步執(zhí)行,都不會開線程饺窿。
最后盜圖總結(jié)一張
六歧焦、NSOperation
1移斩、NSOperation簡介
1.1 NSOperation與GCD的區(qū)別:
- OC語言中基于 GCD 的面向?qū)ο蟮姆庋b;
- 使用起來比 GCD 更加簡單;
- 提供了一些用 GCD 不好實現(xiàn)的功能;
- 蘋果推薦使用肚医,使用 NSOperation 程序員不用關心線程的生命周期
1.2NSOperation的特點
- NSOperation 是一個抽象類,抽象類不能直接使用,必須使用它的子類
- 抽象類的用處是定義子類共有的屬性和方法
2向瓷、核心概念
將操作添加到隊列肠套,異步執(zhí)行。相對于GCD創(chuàng)建任務猖任,將任務添加到隊列你稚。
將NSOperation添加到NSOperationQueue就可以實現(xiàn)多線程編程
3、操作步驟
- 先將需要執(zhí)行的操作封裝到一個NSOperation對象中
- 然后將NSOperation對象添加到NSOperationQueue中
- 系統(tǒng)會自動將NSOperationQueue中的NSOperation取出來
- 將取出的NSOperation封裝的操作放到一條新線程中執(zhí)行
4朱躺、NSInvocationOperation
No1.
代碼
- (void)viewDidLoad {
[super viewDidLoad];
//創(chuàng)建操作刁赖,然后調(diào)用操作的start方法
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(demo) object:nil];
NSLog(@"%d",op.isFinished);
[op start];
NSLog(@"%d",op.isFinished);
}
- (void)demo {
NSLog(@"hello %@",[NSThread currentThread]);
}
打印輸出
2016-02-25 22:12:30.054 test[892:834660] 0
2016-02-25 22:12:30.054 test[892:834660] hello <NSThread: 0x7fad12704f80>{number = 1, name = main}
2016-02-25 22:12:30.054 test[892:834660] 1
結(jié)論:[op start]在主線程中調(diào)用的,所以執(zhí)行的線程也會是在主線程執(zhí)行长搀! 重復調(diào)用start也只會執(zhí)行一次宇弛,因為NSOperation會有一個屬性去記住,是否已經(jīng)完成了該操作源请!
No2.
代碼
- (void)viewDidLoad {
[super viewDidLoad];
// 創(chuàng)建操作枪芒,將操作添加到NSOperationQueue中,然后就會異步的自動執(zhí)行
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(demo) object:nil];
//隊列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//把操作添加到隊列
[queue addOperation:op];
}
- (void)demo {
NSLog(@"hello %@",[NSThread currentThread]);
}
打印
2016-02-25 22:21:44.999 test[912:842412] hello <NSThread: 0x7fab92610080>{number = 2, name = (null)}
將操作添加到NSOperationQueue中谁尸,然后就會異步的自動執(zhí)行
## 5舅踪、NSBlockOperation
**NSBlockOperation 中使用block的方式讓所有代碼邏輯在一起,使用起來更加簡便良蛮。**
### NO1.
代碼
//創(chuàng)建操作
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"hello %@",[NSThread currentThread]);
}];
//更新op的狀態(tài)抽碌,執(zhí)行main方法,不會開新線程
[op start];
輸出
2016-02-25 22:25:30.442 test[923:846208] hello <NSThread: 0x7fd410d055a0>{number = 1, name = main}
NO2.
代碼
// 創(chuàng)建隊列决瞳,創(chuàng)建操作咬展,將操作添加到隊列中執(zhí)行
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"hello %@",[NSThread currentThread]);
}];
[queue addOperation:op];
輸出
2016-02-25 22:26:48.064 test[934:848038] hello <NSThread: 0x7fc6bbb24c80>{number = 2, name = (null)}
NO3.
代碼
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock:^{
NSLog(@"hello %@",[NSThread currentThread]);
}];
2016-02-25 22:27:56.445 test[945:850128] hello <NSThread: x7f98dbc2cae0>{number = 2, name = (null)}
創(chuàng)建隊列,添加block形式的操作
七瞒斩、案例
線程之間的通信問題
技術方案:NSOperation
[self.queue addOperationWithBlock:^{
NSLog(@"異步下載圖片");
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSLog(@"回到主線程破婆,更新UI");
}];
}];
技術方案:GCD
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"下載圖片---%@",[NSThread currentThread]);
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"回到主線程刷新圖片的顯示 -%@",[NSThread currentThread]);
});
});