多線程概念詳解
什么是進(jìn)程?
- 簡(jiǎn)單的說進(jìn)程就是我們電腦上運(yùn)行的一個(gè)個(gè)應(yīng)用程序,每一個(gè)程序就是一個(gè)進(jìn)程,并且每個(gè)進(jìn)程之間是獨(dú)立的,每個(gè)進(jìn)程運(yùn)行在其專用受保護(hù)的內(nèi)存空間內(nèi)(window系統(tǒng)可以通過任務(wù)管理器進(jìn)行查看,Mac系統(tǒng)中可以通過活動(dòng)監(jiān)視器對(duì)其進(jìn)行查看)
什么是線程?
- 通過上面的介紹我們知道了什么是進(jìn)程,那么如何讓進(jìn)程運(yùn)行起來,這個(gè)時(shí)候就要有線程了,也就是說每個(gè)應(yīng)用程序想要跑起來,最少也要有一條線程存在,其實(shí)應(yīng)用程序啟動(dòng)的時(shí)候我們的系統(tǒng)就會(huì)默認(rèn)幫我們的應(yīng)用程序開啟一條線程,這條線程也叫做'主線程',或者'UI線程'
進(jìn)程和線程之間的關(guān)系
- 線程是進(jìn)行的執(zhí)行單元,進(jìn)程的所有任務(wù)都在線程中執(zhí)行,舉例來說:進(jìn)程就好比公司中的一個(gè)個(gè)部門,線程則代表著部門中的同事,而主線程當(dāng)然是我們的老板了,一個(gè)公司部能沒有老板,一個(gè)程序不能沒有線程其實(shí)都是一個(gè)道理.
什么是CPU?
- CPU(中央處理器,Central Processing Unit)是一塊超大規(guī)模的集成電路,只要用來解釋計(jì)算機(jī)指令以及處理計(jì)算機(jī)軟件中的數(shù)據(jù).
多線程的原理
- 同一時(shí)間,CPU值能處理一個(gè)線程,只有一條線程在執(zhí)行,多線程指的就是多條線程同時(shí)執(zhí)行,其實(shí)就是CPU快速的在多條線程之間的切換,如果CPU調(diào)度線程的時(shí)間足夠快,那么就會(huì)造成多線程并發(fā)執(zhí)行的假象,而當(dāng)線程特別多的時(shí)候,那么CPU在多條切換的效率也就會(huì)下降,同時(shí)消耗大量的CPU資源,線程的執(zhí)行效率也就會(huì)下降.
多線程優(yōu)點(diǎn)
- 能適當(dāng)提高程序的執(zhí)行效率
- 能適當(dāng)提高資源的利用率
多線程的缺點(diǎn)
- 開啟線程需要占用一定的內(nèi)存空間,如果開啟大量的線程,則會(huì)占用大量的內(nèi)存空間,降低程序的性能
- 線程越多,CPU在調(diào)度線程上得開銷就越大,程序的設(shè)計(jì)上也就更加的復(fù)雜,因此不推薦開啟太多的線程,一般開啟2~5條為最佳(且用且珍惜);
主線程
- 也就是應(yīng)用程序啟動(dòng)的時(shí)候,系統(tǒng)默認(rèn)幫我們創(chuàng)建的線程,稱之為'主線程'或者是'UI線程';
- 主線程的作用一般都是用來顯示或者刷新UI界面例如:點(diǎn)擊,滾動(dòng),拖拽等事件
IOS中多線程的實(shí)現(xiàn)方案
方案 | 簡(jiǎn)介 | 語言 | 線程生命周期 | 使用頻率 |
---|---|---|---|---|
pthread | <ul><li>一套通用的多線程API</li><li>適用于 Unix / Linux / Windows 等系統(tǒng)</li><li>跨平臺(tái)\可移植</li><li>使用難度大</li></ul> | C | 程序員管理 | 幾乎不用 |
NSThread | <ul><li>使用更加面向?qū)ο?lt;/li><li>簡(jiǎn)單易用猬腰,可直接操作線程對(duì)象</li></ul> | OC | 程序員管理 | 偶爾使用 |
GCD | <ul><li>旨在替代NSThread等線程技術(shù)</li><li>充分利用設(shè)備的多核</li></ul> | C | 自動(dòng)管理 | 經(jīng)常使用 |
NSOperation | <ul><li>基于GCD(底層是GCD)</li><li>比GCD多了一些更簡(jiǎn)單實(shí)用的功能</li><li>使用更加面向?qū)ο?lt;/li></ul> | OC | 自動(dòng)管理 | 經(jīng)常使用 |
NSThread使用
創(chuàng)建線程的種方式
- 通過NSThread的對(duì)象方法
- 通過NSThread的類方法
- 通過NSObject
NSThread 是iOS提供的輕量級(jí)開發(fā),使用起來也相對(duì)簡(jiǎn)單
為什么要使用NSThread ?
- 在開發(fā)中我們經(jīng)常去網(wǎng)絡(luò)上下載資源,由于網(wǎng)絡(luò)原因,有的時(shí)候我們很難保證下載很快就能完成,這時(shí)候使用NSThread將下載的過程交給線程,那么在下載的同時(shí)我們的程序并不需要等待,可以繼續(xù)操作界面,程序體驗(yàn)會(huì)更好.
NSThread-Demo:
//點(diǎn)擊下載圖片
- (IBAction)downLoadButton:(id)sender {
//通過NSThread對(duì)象方法
//[self objectMethod];
//通過NSThread類方法
//[self classMethod];
//通過NSObject的方法
[self extendedMethod];
}
//通過NSObject的方法去下載圖片
- (void)extendedMethod{
//通過NSObject分類方法
[self performSelectorInBackground:@selector(downLoadImage) withObject:nil];
}
//通過NSThread類方法去下載圖片
- (void)classMethod{
//NSThread類方法
[NSThread detachNewThreadSelector:@selector(downLoadImage) toTarget:self withObject:nil];
}
//通過NSThread對(duì)象方法去下載圖片
- (void)objectMethod{
//創(chuàng)建一個(gè)程序去下載圖片
NSThread *thread=[[NSThread alloc]initWithTarget:self selector:@selector(downLoadImage) object:nil];
NSLog(@"downLoadButton:%@",[NSThread currentThread]);//主線程
//開啟線程
[thread start];
}
//下載圖片
- (void)downLoadImage{
//請(qǐng)求圖片資源
NSURL *url=[NSURL URLWithString:@"http://pic7.nipic.com/20100515/2001785_115623014419_2.jpg"];
//模擬下載延遲
[NSThread sleepForTimeInterval:10];
//將資源轉(zhuǎn)換為二進(jìn)制
NSData *data=[NSData dataWithContentsOfURL:url];
NSLog(@"downLoadImage:%@",[NSThread currentThread]);//在子線程中下載圖片
//在主線程更新UI
[self performSelectorOnMainThread:@selector(updateImage:) withObject:data waitUntilDone:YES];
}
//更新imageView
- (void)updateImage:(NSData *)data{
NSLog(@"updateImage:%@",[NSThread currentThread]);//在主線程中更新UI
//將二進(jìn)制數(shù)據(jù)轉(zhuǎn)換為圖片
UIImage *image=[UIImage imageWithData:data];
//設(shè)置image
self.imageView.image=image;
}
以上就是對(duì)NSThread三種使用的一個(gè)簡(jiǎn)單的Demo
線程狀態(tài)
-
新建
- 實(shí)例化線程對(duì)象
-
就緒
- 向線程對(duì)象發(fā)送 start 消息颓帝,線程對(duì)象被加入 可調(diào)度線程池 等待 CPU 調(diào)度
- detachNewThreadSelector 方法和 performSelectorInBackground 方法會(huì)直接實(shí)例化一個(gè)線程對(duì)象并加入 可調(diào)度線程池
-
運(yùn)行
- CPU 負(fù)責(zé)調(diào)度可調(diào)度線程池中線程的執(zhí)行
- 線程執(zhí)行完成之前(死亡之前)扫茅,狀態(tài)可能會(huì)在就緒和運(yùn)行之間來回切換
- 就緒和運(yùn)行之間的狀態(tài)變化由 CPU 負(fù)責(zé)庶喜,程序員不能干預(yù)
-
阻塞
- 當(dāng)滿足某個(gè)預(yù)定條件時(shí)渐溶,可以使用休眠或鎖阻塞線程執(zhí)行
- sleepForTimeInterval:休眠指定時(shí)長(zhǎng)
- sleepUntilDate:休眠到指定日期
- @synchronized(self):互斥鎖
- 當(dāng)滿足某個(gè)預(yù)定條件時(shí)渐溶,可以使用休眠或鎖阻塞線程執(zhí)行
-
死亡
- 正常死亡
- 線程執(zhí)行完畢
- 非正常死亡
- 當(dāng)滿足某個(gè)條件后伊滋,在線程內(nèi)部自己中止執(zhí)行(自殺)
- 當(dāng)滿足某個(gè)條件后饲嗽,在主線程給其它線程打個(gè)死亡標(biāo)記(下圣旨),讓子線程自行了斷.(被逼著死亡)
- 正常死亡
線程的屬性(name)
- 隨著我們以后開發(fā)中項(xiàng)目的日益增大,Bug也就會(huì)相對(duì)的越來越隱藏越來越難查找,這時(shí)候如果是線程問題造成的,那么我們就可以在使用的時(shí)候給每個(gè)線程起一個(gè)名字,這樣一來當(dāng)程序出問題了我們可以很快的找到問題所在的線程并處理它
線程的優(yōu)先級(jí)(threadPriority)
- 當(dāng)多個(gè)線程同時(shí)存在的時(shí)候那么就會(huì)引出一個(gè)問題,到底哪個(gè)線程該先執(zhí)行哪個(gè)線程應(yīng)該最后執(zhí)行,因此也就有了線程的優(yōu)先級(jí),線程優(yōu)先級(jí)是用浮點(diǎn)數(shù)表示的,最高為1.0 最低為0.0 默認(rèn)我們創(chuàng)建出來的線程為0.5.
- 修改線程優(yōu)先級(jí)我們可以提高某個(gè)線程供CPU調(diào)度的可能性,開發(fā)中很少有去修改線程優(yōu)先級(jí)的
棧區(qū)大小(stackSize)
- 默認(rèn)情況下主線程和子線程在棧區(qū)大小都是512k
是否是主線程(isMainThread)
- 開發(fā)中我們判斷某條線程是否是主線程其實(shí)很簡(jiǎn)單,除了通過isMainThread屬性,我們還可以直接在代碼中打印出來[NSThread currentThread],其中會(huì)記錄線程名稱name和編號(hào)number,如果number為1 則為主線程
線程間的通訊
- 其實(shí)從上面的Demo我們不難發(fā)現(xiàn),線程間的通訊簡(jiǎn)單的來說就是把耗時(shí)的操作拿到子線程中執(zhí)行(例如下載一些網(wǎng)絡(luò)資源),最后返回主線程中更新UI.
GCD的使用
- GCD(Grand Central Dispatch)是基于C語言開發(fā)的一套多線程開發(fā)機(jī)制,是完全面向過程的叉趣。
GCD 核心概念
- 將任務(wù)添加到隊(duì)列,并且指定執(zhí)行任務(wù)的函數(shù)
- 任務(wù)使用 block 封裝
- 任務(wù)的 block 沒有參數(shù)也沒有返回值
- 執(zhí)行任務(wù)的函數(shù)
- 異步 dispatch_async
- 不用等待當(dāng)前語句執(zhí)行完畢阵谚,就可以執(zhí)行下一條語句
- 會(huì)開啟線程執(zhí)行 block 的任務(wù)
- 異步是多線程的代名詞
- 同步 dispatch_sync
- 必須等待當(dāng)前語句執(zhí)行完畢烟具,才會(huì)執(zhí)行下一條語句
- 不會(huì)開啟線程
- 在當(dāng)前執(zhí)行 block 的任務(wù)
- 異步 dispatch_async
- 隊(duì)列 - 負(fù)責(zé)調(diào)度任務(wù)
- 串行隊(duì)列
- 一次只能"調(diào)度"一個(gè)任務(wù)
- dispatch_queue_create("queue", NULL);
- 并發(fā)隊(duì)列
- 一次可以"調(diào)度"多個(gè)任務(wù)
- dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
- 主隊(duì)列
- 專門用來在主線程上調(diào)度任務(wù)的隊(duì)列
- 不會(huì)開啟線程
- 在主線程空閑時(shí)才會(huì)調(diào)度隊(duì)列中的任務(wù)在主線程執(zhí)行
- dispatch_get_main_queue();
- 串行隊(duì)列
階段性小結(jié)
- 開不開線程由執(zhí)行任務(wù)的函數(shù)決定
- 異步開朝聋,異步是多線程的代名詞
- 同步不開
- 開幾條線程由隊(duì)列決定
- 串行隊(duì)列開一條線程
-
并發(fā)隊(duì)列開多條線程,具體能開的線程數(shù)量由底層線程池決定
- iOS 8.0 之后翼馆,GCD 能夠開啟非常多的線程
- iOS 7.0 以及之前,GCD 通常只會(huì)開啟 5~6 條線程
- 隊(duì)列的選擇
多線程的目的:將耗時(shí)的操作放在后臺(tái)執(zhí)行金度!
-
串行隊(duì)列应媚,只開一條線程,所有任務(wù)順序執(zhí)行
- 如果任務(wù)有先后執(zhí)行順序的要求
- 效率低 -> 執(zhí)行慢 -> "省電"
- 有的時(shí)候猜极,用戶其實(shí)不希望太快中姜!例如使用 3G 流量,"省錢"
-
并發(fā)隊(duì)列跟伏,會(huì)開啟多條線程丢胚,所有任務(wù)不按照順序執(zhí)行
- 如果任務(wù)沒有先后執(zhí)行順序的要求
- 效率高 -> 執(zhí)行快 -> "費(fèi)電"
- WIFI,包月
實(shí)際開發(fā)中受扳,線程數(shù)量如何決定?
- WIFI 線程數(shù) 6 條
- 3G / 4G 移動(dòng)開發(fā)的時(shí)候携龟,2~3條,再多會(huì)費(fèi)電費(fèi)錢勘高!
同步 & 異步
- 同步:
- 在當(dāng)前線程中執(zhí)行,必須等待當(dāng)前語句執(zhí)行完畢峡蟋,才會(huì)執(zhí)行下一條語句
- 不在當(dāng)前線程中執(zhí)行,不用等待當(dāng)前語句執(zhí)行完畢,就可以執(zhí)行下一條語句
NSThread-Demo
//點(diǎn)擊屏幕調(diào)用
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
NSLog(@"touchesBegan開始執(zhí)行");
//同步調(diào)用
[self start];
//異步調(diào)用
//[self performSelectorInBackground:@selector(start) withObject:nil];
NSLog(@"touchesBegan執(zhí)行結(jié)束");
}
//開始執(zhí)行
- (void)start{
NSLog(@"start開始執(zhí)行");
NSLog(@"start當(dāng)前線程:%@",[NSThread currentThread]);
//延遲5秒調(diào)用
[NSThread sleepForTimeInterval:5];
NSLog(@"start執(zhí)行完畢");
}
執(zhí)行以上代碼,發(fā)現(xiàn)當(dāng)同步的時(shí)候執(zhí)行的結(jié)果為:
2015-11-26 18:17:29.621 GCD同步異步[1267:159851] touchesBegan開始執(zhí)行
2015-11-26 18:17:29.621 GCD同步異步[1267:159851] start開始執(zhí)行
2015-11-26 18:17:29.621 GCD同步異步[1267:159851] start當(dāng)前線程:<NSThread: 0x7fec12e01780>{number = 1, name = main}
2015-11-26 18:17:34.627 GCD同步異步[1267:159851] start執(zhí)行完畢
2015-11-26 18:17:34.627 GCD同步異步[1267:159851] touchesBegan執(zhí)行結(jié)束
執(zhí)行以上代碼,發(fā)現(xiàn)當(dāng)異步的時(shí)候執(zhí)行的結(jié)果為:
2015-11-26 18:23:10.846 GCD同步異步[1282:163977] touchesBegan開始執(zhí)行
2015-11-26 18:23:10.847 GCD同步異步[1282:163977] touchesBegan執(zhí)行結(jié)束
2015-11-26 18:23:10.848 GCD同步異步[1282:164254] start開始執(zhí)行
2015-11-26 18:23:10.848 GCD同步異步[1282:164254] start當(dāng)前線程:<NSThread: 0x7fa778f0f0f0>{number = 2, name = (null)}
2015-11-26 18:23:15.849 GCD同步異步[1282:164254] start執(zhí)行完畢
結(jié)論: 同步是從上到下有順序的執(zhí)行,異步則不是
GCD-Demo
//點(diǎn)擊屏幕的時(shí)候調(diào)用
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//異步
//[self asyncMethod];
//同步
[self syncMethod];
}
//異步的時(shí)候調(diào)用
- (void)asyncMethod{
//獲取全局隊(duì)列
dispatch_queue_t queue=dispatch_get_global_queue(0, 0);
//創(chuàng)建任務(wù)
void(^task)()=^{
NSLog(@"asyncMethod:%@",[NSThread currentThread]);
};
//執(zhí)行任務(wù)
dispatch_async(queue, task);
NSLog(@"end");
}
//同步的時(shí)候調(diào)用
- (void)syncMethod{
//獲取全局隊(duì)列
dispatch_queue_t queue=dispatch_get_global_queue(0, 0);
//創(chuàng)建任務(wù)
void(^task)()=^{
NSLog(@"syncMethod:%@",[NSThread currentThread]);
};
//執(zhí)行任務(wù)
dispatch_sync(queue, task);
NSLog(@"end");
}
執(zhí)行以上代碼,發(fā)現(xiàn)當(dāng)同步的時(shí)候執(zhí)行的結(jié)果為:
2015-11-26 18:40:55.419 GCD中的同步和異步[1361:177648] syncMethod:<NSThread: 0x7fa7d14036b0>{number = 1, name = main}
2015-11-26 18:40:55.419 GCD中的同步和異步[1361:177648] end
2015-11-26 18:40:55.667 GCD中的同步和異步[1361:177648] syncMethod:<NSThread: 0x7fa7d14036b0>{number = 1, name = main}
2015-11-26 18:40:55.667 GCD中的同步和異步[1361:177648] end
2015-11-26 18:40:55.926 GCD中的同步和異步[1361:177648] syncMethod:<NSThread: 0x7fa7d14036b0>{number = 1, name = main}
2015-11-26 18:40:55.927 GCD中的同步和異步[1361:177648] end
執(zhí)行以上代碼,發(fā)現(xiàn)當(dāng)異步的時(shí)候執(zhí)行的結(jié)果為:
2015-11-26 18:41:36.351 GCD中的同步和異步[1370:178492] asyncMethod:<NSThread: 0x7fc941e02a70>{number = 2, name = (null)}
2015-11-26 18:41:36.351 GCD中的同步和異步[1370:178425] end
2015-11-26 18:41:36.576 GCD中的同步和異步[1370:178425] end
2015-11-26 18:41:36.576 GCD中的同步和異步[1370:178492] asyncMethod:<NSThread: 0x7fc941e02a70>{number = 2, name = (null)}
2015-11-26 18:41:36.810 GCD中的同步和異步[1370:178425] end
2015-11-26 18:41:36.810 GCD中的同步和異步[1370:178492] asyncMethod:<NSThread: 0x7fc941e02a70>{number = 2, name = (null)}
和NSThread對(duì)比可以發(fā)現(xiàn)
- 所有的代碼寫在一起的华望,讓代碼更加簡(jiǎn)單蕊蝗,易于閱讀和維護(hù)
- NSThread 通過 @selector 指定要執(zhí)行的方法,代碼分散
- GCD 通過 block 指定要執(zhí)行的代碼赖舟,代碼集中
- 使用 GCD 不需要管理線程的創(chuàng)建/銷毀/復(fù)用的過程蓬戚!程序員不用關(guān)心線程的生命周期
- 如果要開多個(gè)線程 NSThread 必須實(shí)例化多個(gè)線程對(duì)象
- NSThread 靠 NSObject 的分類方法實(shí)現(xiàn)的線程間通訊,GCD 靠 block
使用GCD下載圖片
//點(diǎn)擊下載圖片
- (IBAction)downLoadButton:(id)sender {
//獲取全局隊(duì)列
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//異步下載圖片
NSURL *url=[NSURL URLWithString:@"http://pic7.nipic.com/20100515/2001785_115623014419_2.jpg"];
//將資源轉(zhuǎn)換為二進(jìn)制
NSData *data=[NSData dataWithContentsOfURL:url];
//將二進(jìn)制轉(zhuǎn)化為圖片
UIImage *image=[UIImage imageWithData:data];
//獲取主隊(duì)列,更新UI
dispatch_async(dispatch_get_main_queue(), ^{
//給圖片控件賦值
self.imageView.image=image;
});
});
}
串行隊(duì)列
串行隊(duì)列特點(diǎn):
- 以先進(jìn)先出的方式,順序調(diào)度隊(duì)列中的任務(wù)執(zhí)行
- 無論隊(duì)列中指定的任務(wù)函數(shù)是同步還是異步,都會(huì)等待前一個(gè)任務(wù)執(zhí)行完畢以后,再調(diào)度后面的任務(wù)
隊(duì)列創(chuàng)建
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue = dispatch_queue_create("queue", NULL);
串行隊(duì)列同步&異步Demo
//點(diǎn)擊屏幕的時(shí)候調(diào)用
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//同步執(zhí)行
//[self syncMethod];
//異步執(zhí)行
[self asyncMethod];
}
//同步
- (void)syncMethod{
//創(chuàng)建隊(duì)列
dispatch_queue_t queue=dispatch_queue_create("同步", DISPATCH_QUEUE_SERIAL);
//執(zhí)行任務(wù)
for (int i=0; i<6; i++) {
NSLog(@"1--->%d",i);
dispatch_sync(queue, ^{
NSLog(@"2--->%d---%@",i,[NSThread currentThread]
);
});
}
NSLog(@"end");
}
//異步
- (void)asyncMethod{
//創(chuàng)建隊(duì)列
dispatch_queue_t queue=dispatch_queue_create("異步", DISPATCH_QUEUE_SERIAL);
//執(zhí)行任務(wù)
for (int i=0; i<6; i++) {
NSLog(@"1--->%d",i);
dispatch_async(queue, ^{
NSLog(@"2--->%d---%@",i,[NSThread currentThread]
);
});
}
NSLog(@"end");
}
串行隊(duì)列 同步執(zhí)行結(jié)果:
2015-11-26 19:12:20.876 串行隊(duì)列的同步和異步[1520:204175] 1--->0
2015-11-26 19:12:20.877 串行隊(duì)列的同步和異步[1520:204175] 2--->0---<NSThread: 0x7fe952c05820>{number = 1, name = main}
2015-11-26 19:12:20.877 串行隊(duì)列的同步和異步[1520:204175] 1--->1
2015-11-26 19:12:20.877 串行隊(duì)列的同步和異步[1520:204175] 2--->1---<NSThread: 0x7fe952c05820>{number = 1, name = main}
2015-11-26 19:12:20.877 串行隊(duì)列的同步和異步[1520:204175] 1--->2
2015-11-26 19:12:20.877 串行隊(duì)列的同步和異步[1520:204175] 2--->2---<NSThread: 0x7fe952c05820>{number = 1, name = main}
2015-11-26 19:12:20.878 串行隊(duì)列的同步和異步[1520:204175] 1--->3
2015-11-26 19:12:20.878 串行隊(duì)列的同步和異步[1520:204175] 2--->3---<NSThread: 0x7fe952c05820>{number = 1, name = main}
2015-11-26 19:12:20.878 串行隊(duì)列的同步和異步[1520:204175] 1--->4
2015-11-26 19:12:20.878 串行隊(duì)列的同步和異步[1520:204175] 2--->4---<NSThread: 0x7fe952c05820>{number = 1, name = main}
2015-11-26 19:12:20.878 串行隊(duì)列的同步和異步[1520:204175] 1--->5
2015-11-26 19:12:20.878 串行隊(duì)列的同步和異步[1520:204175] 2--->5---<NSThread: 0x7fe952c05820>{number = 1, name = main}
2015-11-26 19:12:20.878 串行隊(duì)列的同步和異步[1520:204175] end
串行隊(duì)列 異步執(zhí)行結(jié)果:
2015-11-26 19:12:41.923 串行隊(duì)列的同步和異步[1529:204751] 1--->0
2015-11-26 19:12:41.924 串行隊(duì)列的同步和異步[1529:204751] 1--->1
2015-11-26 19:12:41.924 串行隊(duì)列的同步和異步[1529:204829] 2--->0---<NSThread: 0x7fc99970bbe0>{number = 2, name = (null)}
2015-11-26 19:12:41.924 串行隊(duì)列的同步和異步[1529:204751] 1--->2
2015-11-26 19:12:41.924 串行隊(duì)列的同步和異步[1529:204829] 2--->1---<NSThread: 0x7fc99970bbe0>{number = 2, name = (null)}
2015-11-26 19:12:41.924 串行隊(duì)列的同步和異步[1529:204751] 1--->3
2015-11-26 19:12:41.924 串行隊(duì)列的同步和異步[1529:204829] 2--->2---<NSThread: 0x7fc99970bbe0>{number = 2, name = (null)}
2015-11-26 19:12:41.925 串行隊(duì)列的同步和異步[1529:204751] 1--->4
2015-11-26 19:12:41.925 串行隊(duì)列的同步和異步[1529:204829] 2--->3---<NSThread: 0x7fc99970bbe0>{number = 2, name = (null)}
2015-11-26 19:12:41.925 串行隊(duì)列的同步和異步[1529:204751] 1--->5
2015-11-26 19:12:41.925 串行隊(duì)列的同步和異步[1529:204829] 2--->4---<NSThread: 0x7fc99970bbe0>{number = 2, name = (null)}
2015-11-26 19:12:41.925 串行隊(duì)列的同步和異步[1529:204751] end
2015-11-26 19:12:41.925 串行隊(duì)列的同步和異步[1529:204829] 2--->5---<NSThread: 0x7fc99970bbe0>{number = 2, name = (null)}
并發(fā)隊(duì)列
并發(fā)隊(duì)列特點(diǎn):
- 有多個(gè)線程宾抓,操作進(jìn)來之后它會(huì)將這些隊(duì)列安排在可用的處理器上,同時(shí)保證先進(jìn)來的任務(wù)優(yōu)先處理嘿棘。
- 以先進(jìn)先出的方式旭绒,并發(fā)調(diào)度隊(duì)列中的任務(wù)執(zhí)行
- 如果當(dāng)前調(diào)度的任務(wù)是同步執(zhí)行的挥吵,會(huì)等待任務(wù)執(zhí)行完成后忽匈,再調(diào)度后續(xù)的任務(wù)
- 如果當(dāng)前調(diào)度的任務(wù)是異步執(zhí)行的丹允,同時(shí)底層線程池有可用的線程資源雕蔽,會(huì)再新的線程調(diào)度后續(xù)任務(wù)的執(zhí)行
隊(duì)列創(chuàng)建
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
并行隊(duì)列同步&異步Demo
//點(diǎn)擊屏幕的時(shí)候調(diào)用
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//同步
//[self syncMethod];
//異步
[self asyncMethod];
}
//異步
- (void)asyncMethod{
//并發(fā)隊(duì)列
dispatch_queue_t queue=dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
//創(chuàng)建任務(wù)
for(int i=0; i<6 ;i++ ){
dispatch_async(queue, ^{
NSLog(@"async--->%d---%@",i,[NSThread currentThread]);
});
}
NSLog(@"end");
}
//同步
- (void)syncMethod{
//并發(fā)隊(duì)列
dispatch_queue_t queue=dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
//創(chuàng)建任務(wù)
for(int i=0; i<6 ;i++ ){
dispatch_sync(queue, ^{
NSLog(@"sync--->%d---%@",i,[NSThread currentThread]);
});
}
NSLog(@"end");
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
并行隊(duì)列 同步執(zhí)行結(jié)果:
2015-11-26 21:17:19.820 并發(fā)隊(duì)列的同步與異步[1632:233685] sync--->0---<NSThread: 0x7fd762400f70>{number = 1, name = main}
2015-11-26 21:17:19.820 并發(fā)隊(duì)列的同步與異步[1632:233685] sync--->1---<NSThread: 0x7fd762400f70>{number = 1, name = main}
2015-11-26 21:17:19.821 并發(fā)隊(duì)列的同步與異步[1632:233685] sync--->2---<NSThread: 0x7fd762400f70>{number = 1, name = main}
2015-11-26 21:17:19.821 并發(fā)隊(duì)列的同步與異步[1632:233685] sync--->3---<NSThread: 0x7fd762400f70>{number = 1, name = main}
2015-11-26 21:17:19.821 并發(fā)隊(duì)列的同步與異步[1632:233685] sync--->4---<NSThread: 0x7fd762400f70>{number = 1, name = main}
2015-11-26 21:17:19.821 并發(fā)隊(duì)列的同步與異步[1632:233685] sync--->5---<NSThread: 0x7fd762400f70>{number = 1, name = main}
2015-11-26 21:17:19.822 并發(fā)隊(duì)列的同步與異步[1632:233685] end
并行隊(duì)列 異步執(zhí)行結(jié)果:
2015-11-26 21:17:45.000 并發(fā)隊(duì)列的同步與異步[1641:234351] end
2015-11-26 21:17:45.000 并發(fā)隊(duì)列的同步與異步[1641:234532] async--->3---<NSThread: 0x7fa823c9a910>{number = 5, name = (null)}
2015-11-26 21:17:45.000 并發(fā)隊(duì)列的同步與異步[1641:234425] async--->0---<NSThread: 0x7fa823f0e720>{number = 3, name = (null)}
2015-11-26 21:17:45.000 并發(fā)隊(duì)列的同步與異步[1641:234423] async--->2---<NSThread: 0x7fa823e079f0>{number = 4, name = (null)}
2015-11-26 21:17:45.000 并發(fā)隊(duì)列的同步與異步[1641:234533] async--->4---<NSThread: 0x7fa823e000b0>{number = 6, name = (null)}
2015-11-26 21:17:45.000 并發(fā)隊(duì)列的同步與異步[1641:234424] async--->1---<NSThread: 0x7fa823d4d4e0>{number = 2, name = (null)}
2015-11-26 21:17:45.001 并發(fā)隊(duì)列的同步與異步[1641:234534] async--->5---<NSThread: 0x7fa823f0a290>{number = 7, name = (null)}
全局隊(duì)列
- 是系統(tǒng)為了方便程序員開發(fā)提供的嚣艇,其工作表現(xiàn)與并發(fā)隊(duì)列一致
主隊(duì)列
- 專門用來在主線程上調(diào)度任務(wù)的隊(duì)列
- 不會(huì)開啟線程
- 以先進(jìn)先出的方式食零,在主線程空閑時(shí)才會(huì)調(diào)度隊(duì)列中的任務(wù)在主線程執(zhí)行
- 如果當(dāng)前主線程正在有任務(wù)執(zhí)行贰谣,那么無論主隊(duì)列中當(dāng)前被添加了什么任務(wù),都不會(huì)被調(diào)度
//點(diǎn)擊屏幕的時(shí)候調(diào)用
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//全局隊(duì)列同步執(zhí)行
[self global_queue_sync];
//全局隊(duì)列異步執(zhí)行
//[self global_queue_async];
//主隊(duì)列同步執(zhí)行
//[self main_queue_sync];
//主隊(duì)列異步執(zhí)行
//[self main_queue_async];
}
//主隊(duì)列同步執(zhí)行
- (void)main_queue_sync{
dispatch_queue_t queue = dispatch_get_main_queue();
for (int i = 0; i < 10; ++i) {
dispatch_sync(queue, ^{
NSLog(@"main_queue_sync%@---->%d", [NSThread currentThread], i);
});
}
NSLog(@"end");
}
//主隊(duì)列異步執(zhí)行
- (void)main_queue_async{
dispatch_queue_t queue = dispatch_get_main_queue();
for (int i = 0; i < 10; ++i) {
dispatch_async(queue, ^{
NSLog(@"main_queue_async%@---->%d", [NSThread currentThread], i);
});
}
NSLog(@"end");
}
//全局隊(duì)列異步執(zhí)行
- (void)global_queue_async{
//獲取全局隊(duì)列
dispatch_queue_t q = dispatch_get_global_queue(0, 0);
//執(zhí)行任務(wù)
for (int i = 0; i < 10; ++i) {
dispatch_async(q, ^{
NSLog(@"global_queue_async%@---->%d", [NSThread currentThread], i);
});
}
NSLog(@"end");
}
//全局隊(duì)列同步執(zhí)行
- (void)global_queue_sync{
//獲取全局隊(duì)列
dispatch_queue_t q = dispatch_get_global_queue(0, 0);
//執(zhí)行任務(wù)
for (int i = 0; i < 10; ++i) {
dispatch_sync(q, ^{
NSLog(@"global_queue_sync%@---->%d", [NSThread currentThread], i);
});
}
NSLog(@"end");
}
全局隊(duì)列 同步執(zhí)行結(jié)果:
2015-11-26 22:00:12.568 全局隊(duì)列與主隊(duì)列[1895:266991] global_queue_sync<NSThread: 0x7fb871d069e0>{number = 1, name = main}---->0
2015-11-26 22:00:12.569 全局隊(duì)列與主隊(duì)列[1895:266991] global_queue_sync<NSThread: 0x7fb871d069e0>{number = 1, name = main}---->1
2015-11-26 22:00:12.569 全局隊(duì)列與主隊(duì)列[1895:266991] global_queue_sync<NSThread: 0x7fb871d069e0>{number = 1, name = main}---->2
2015-11-26 22:00:12.569 全局隊(duì)列與主隊(duì)列[1895:266991] global_queue_sync<NSThread: 0x7fb871d069e0>{number = 1, name = main}---->3
2015-11-26 22:00:12.569 全局隊(duì)列與主隊(duì)列[1895:266991] global_queue_sync<NSThread: 0x7fb871d069e0>{number = 1, name = main}---->4
2015-11-26 22:00:12.569 全局隊(duì)列與主隊(duì)列[1895:266991] global_queue_sync<NSThread: 0x7fb871d069e0>{number = 1, name = main}---->5
2015-11-26 22:00:12.569 全局隊(duì)列與主隊(duì)列[1895:266991] global_queue_sync<NSThread: 0x7fb871d069e0>{number = 1, name = main}---->6
2015-11-26 22:00:12.569 全局隊(duì)列與主隊(duì)列[1895:266991] global_queue_sync<NSThread: 0x7fb871d069e0>{number = 1, name = main}---->7
2015-11-26 22:00:12.569 全局隊(duì)列與主隊(duì)列[1895:266991] global_queue_sync<NSThread: 0x7fb871d069e0>{number = 1, name = main}---->8
2015-11-26 22:00:12.569 全局隊(duì)列與主隊(duì)列[1895:266991] global_queue_sync<NSThread: 0x7fb871d069e0>{number = 1, name = main}---->9
2015-11-26 22:00:12.570 全局隊(duì)列與主隊(duì)列[1895:266991] end
全局隊(duì)列 異步執(zhí)行結(jié)果:
2015-11-26 22:01:01.565 全局隊(duì)列與主隊(duì)列[1908:268194] end
2015-11-26 22:01:01.566 全局隊(duì)列與主隊(duì)列[1908:268233] global_queue_async<NSThread: 0x7f97fb607e80>{number = 2, name = (null)}---->1
2015-11-26 22:01:01.566 全局隊(duì)列與主隊(duì)列[1908:268234] global_queue_async<NSThread: 0x7f97fb61f710>{number = 4, name = (null)}---->2
2015-11-26 22:01:01.566 全局隊(duì)列與主隊(duì)列[1908:268256] global_queue_async<NSThread: 0x7f97fb63bec0>{number = 5, name = (null)}---->3
2015-11-26 22:01:01.566 全局隊(duì)列與主隊(duì)列[1908:268257] global_queue_async<NSThread: 0x7f97fb7127d0>{number = 6, name = (null)}---->4
2015-11-26 22:01:01.566 全局隊(duì)列與主隊(duì)列[1908:268232] global_queue_async<NSThread: 0x7f97fb70bde0>{number = 3, name = (null)}---->0
2015-11-26 22:01:01.566 全局隊(duì)列與主隊(duì)列[1908:268233] global_queue_async<NSThread: 0x7f97fb607e80>{number = 2, name = (null)}---->5
2015-11-26 22:01:01.566 全局隊(duì)列與主隊(duì)列[1908:268234] global_queue_async<NSThread: 0x7f97fb61f710>{number = 4, name = (null)}---->6
2015-11-26 22:01:01.566 全局隊(duì)列與主隊(duì)列[1908:268258] global_queue_async<NSThread: 0x7f97fb442510>{number = 7, name = (null)}---->7
2015-11-26 22:01:01.566 全局隊(duì)列與主隊(duì)列[1908:268256] global_queue_async<NSThread: 0x7f97fb63bec0>{number = 5, name = (null)}---->8
2015-11-26 22:01:01.567 全局隊(duì)列與主隊(duì)列[1908:268257] global_queue_async<NSThread: 0x7f97fb7127d0>{number = 6, name = (null)}---->9
主隊(duì)列 同步執(zhí)行結(jié)果:
主隊(duì)列和主線程相互等待會(huì)造成死鎖,程序直接卡死
主隊(duì)列 異步執(zhí)行結(jié)果:
2015-11-26 22:02:09.057 全局隊(duì)列與主隊(duì)列[1935:269576] end
2015-11-26 22:02:09.058 全局隊(duì)列與主隊(duì)列[1935:269576] main_queue_async<NSThread: 0x7fadd850a320>{number = 1, name = main}---->0
2015-11-26 22:02:09.058 全局隊(duì)列與主隊(duì)列[1935:269576] main_queue_async<NSThread: 0x7fadd850a320>{number = 1, name = main}---->1
2015-11-26 22:02:09.058 全局隊(duì)列與主隊(duì)列[1935:269576] main_queue_async<NSThread: 0x7fadd850a320>{number = 1, name = main}---->2
2015-11-26 22:02:09.058 全局隊(duì)列與主隊(duì)列[1935:269576] main_queue_async<NSThread: 0x7fadd850a320>{number = 1, name = main}---->3
2015-11-26 22:02:09.058 全局隊(duì)列與主隊(duì)列[1935:269576] main_queue_async<NSThread: 0x7fadd850a320>{number = 1, name = main}---->4
2015-11-26 22:02:09.059 全局隊(duì)列與主隊(duì)列[1935:269576] main_queue_async<NSThread: 0x7fadd850a320>{number = 1, name = main}---->5
2015-11-26 22:02:09.059 全局隊(duì)列與主隊(duì)列[1935:269576] main_queue_async<NSThread: 0x7fadd850a320>{number = 1, name = main}---->6
2015-11-26 22:02:09.059 全局隊(duì)列與主隊(duì)列[1935:269576] main_queue_async<NSThread: 0x7fadd850a320>{number = 1, name = main}---->7
2015-11-26 22:02:09.059 全局隊(duì)列與主隊(duì)列[1935:269576] main_queue_async<NSThread: 0x7fadd850a320>{number = 1, name = main}---->8
2015-11-26 22:02:09.087 全局隊(duì)列與主隊(duì)列[1935:269576] main_queue_async<NSThread: 0x7fadd850a320>{number = 1, name = main}---->9
NSOperation
- NSOperation有兩個(gè)常用子類用于創(chuàng)建線程操作:NSInvocationOperation和NSBlockOperation因痛,兩種方式本質(zhì)沒有區(qū)別鸵膏,但是是后者使用Block形式進(jìn)行代碼組織谭企,使用相對(duì)方便。
NSOperation-Demo
//當(dāng)點(diǎn)擊屏幕的時(shí)候調(diào)用
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//創(chuàng)建url
NSURL *url=[NSURL URLWithString:@"http://pic7.nipic.com/20100515/2001785_115623014419_2.jpg"];
//將資源轉(zhuǎn)換為二進(jìn)制
NSData *data=[NSData dataWithContentsOfURL:url];
//創(chuàng)建operation
NSInvocationOperation *operation=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downLoadImage:) object:data];
//執(zhí)行操作
[operation start];
}
- (void)downLoadImage:(NSData *)data{
//將二進(jìn)制轉(zhuǎn)化為圖片
UIImage *image=[UIImage imageWithData:data];
//顯示圖片
self.imageView.image=image;
}
將任務(wù)添加到隊(duì)里中執(zhí)行
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//創(chuàng)建隊(duì)列
NSOperationQueue *operationQueue=[[NSOperationQueue alloc]init];
//創(chuàng)建任務(wù)
NSInvocationOperation *operation=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downLoadImage) object:nil];
NSLog(@"1--->%@",[NSThread currentThread]);
//將任務(wù)添加到隊(duì)列中
[operationQueue addOperation:operation];
}
//子線程中下載圖片
- (void)downLoadImage{
//創(chuàng)建url
NSURL *url=[NSURL URLWithString:@"http://pic7.nipic.com/20100515/2001785_115623014419_2.jpg"];
//將資源轉(zhuǎn)換為二進(jìn)制
NSData *data=[NSData dataWithContentsOfURL:url];
NSLog(@"2--->%@",[NSThread currentThread]);
//將二進(jìn)制轉(zhuǎn)化為tup
UIImage *image=[UIImage imageWithData:data];
[self performSelectorOnMainThread:@selector(updateImage:) withObject:image waitUntilDone:YES];
}
//主線程中更新圖片
- (void)updateImage:(UIImage *)image{
NSLog(@"3--->%@",[NSThread currentThread]);
self.imageView.image=image;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}