- Object C中創(chuàng)建線程的方法是什么?如果在主線程中執(zhí)行代碼,方法是什么?如果想延時執(zhí)行代碼、方法又是什么?
1.線程創(chuàng)建有三種方法:
使用NSThread創(chuàng)建、
使用GCD的dispatch、
使用子類化的NSOperation,然后將其加入NSOperationQueue。2.在主線程執(zhí)行代碼,方法是performSelectorOnMainThread。
3.如果想延時執(zhí)行代碼可以用performSelector:onThread:withObject:waitUntilDone。
4、GCD的隊列(dispatch_queue_t)分那兩種類型?
- 串行隊列Serial Dispatch Queue
- 并行隊列Concurrent Dispatch Queue
3、NSOperation相比于Grand Central Dispatch有哪些優(yōu)勢?
iOS有四種多線程編程的技術(shù),分別是:NSThread,Cocoa NSOperation,GCD(全稱:Grand Central Dispatch),pthread。
四種方式的優(yōu)缺點介紹:
1)NSThread
優(yōu)點:NSThread 比其他兩個輕量級。
缺點:需要自己管理線程的生命周期,線程同步。
線程同步對數(shù)據(jù)的加鎖會有一定的系統(tǒng)開銷。2)NSOperation
優(yōu)點:不需要關(guān)心線程管理, 數(shù)據(jù)同步的事情,可以把精力放在自己需要執(zhí)行的操作上。
Cocoa operation相關(guān)的類是NSOperation, NSOperationQueue.NSOperation是個抽象類,使用它必須用它的子類,可以實現(xiàn)它或者使用它定義好的兩個子類: NSInvocationOperation和NSBlockOperation.創(chuàng)建NSOperation子類的對象,把對象添加到NSOperationQueue隊列里執(zhí)行。3)GCD
(全優(yōu)點)Grand Central dispatch(GCD)是Apple開發(fā)的一個多核編程的解決方案。
在iOS4.0開始之后才能使用。
GCD是一個替代NSThread, NSOperationQueue,NSInvocationOperation等技術(shù)的很高效強(qiáng)大的技術(shù)。4)pthread
是一套通用的多線程API,適用于Linux\Windows\Unix,跨平臺,可移植,使用C語言,生命周期需要程序員管理,IOS開發(fā)中使用很少。GCD Queue 分為三種:
1,The main queue :主隊列,主線程就是在個隊列中。
2,Global queues : 全局并發(fā)隊列。
3,用戶隊列:是用函數(shù) dispatch_queue_create創(chuàng)建的自定義隊列dispatch_sync 和 dispatch_async 區(qū)別:
1.dispatch_async(queue,block) async 異步隊列,dispatch_async函數(shù)會立即返回, block會在后臺異步執(zhí)行。
2.dispatch_sync(queue,block) sync 同步隊列,dispatch_sync函數(shù)不會立即返回,及阻塞當(dāng)前線程,等待 block同步執(zhí)行完成。GCD線程死鎖
GCD 確實好用 ,很強(qiáng)大,相比NSOpretion 無法提供 取消任務(wù)的功能。
如此強(qiáng)大的工具用不好可能會出現(xiàn)線程死鎖。五個案例讓你明白GCD死鎖
http://ios.jobbole.com/82622/
61.線程間怎么通信?
(1) GCD:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
//下載圖片
UIImage *image = nil;
dispatch_async(dispatch_get_main_queue(),^{
//回到主線程
});
}
(2) NSThread的線程通信
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
//下載圖片
UIImage *image = nil;
[selfperformSelector:@selector(settingImage:) onThread:[NSThread mainThread]withObject:image waitUntilDone:YES modes:nil];
}
這種情況也適用于子線程之間的通信。
7、同步異步、串行和并行
串行與并行針對的是隊列,而同步與異步,針對的則是線程。最大的區(qū)別在于,同步線程要阻塞當(dāng)前線程,必須要等待同步線程中的任務(wù)執(zhí)行完,返回以后,才能繼續(xù)執(zhí)行下一任務(wù);而異步線程則是不用等待。
1.多線程的底層實現(xiàn)?
1>首先搞清楚什么是線程、什么是多線程
2> Mach是第一個以多線程方式處理任務(wù)的系統(tǒng),因此多線程的底層實現(xiàn)機(jī)制是基于Mach的線程
3>開發(fā)中很少用Mach級的線程,因為Mach級的線程沒有提供多線程的基本特征,線程之間是獨立的
4>開發(fā)中實現(xiàn)多線程的方案C語言的POSIX接口:#include
OC的NSThread
C語言的GCD接口(性能最好,代碼更精簡)
OC的NSOperation和NSOperationQueue(基于GCD)
2.線程間怎么通信?
1> performSelector:onThread:withObject:waitUntilDone:
2> NSMachPort
(基本機(jī)制:A線程(父線程)創(chuàng)建NSMachPort對象,并加入A線程的run loop。當(dāng)創(chuàng)建B線程(輔助線程)時,將創(chuàng)建的NSMachPort對象傳遞到主體入口點,B線程(輔助線程)就可以使用相同的端口對象將消息傳回A線程(父線程)。
http://mobile.51cto.com/hot-403083_all.htm)
3.網(wǎng)絡(luò)圖片處理問題中怎么解決一個相同的網(wǎng)絡(luò)地址重復(fù)請求的問題?
利用字典(圖片地址為key,下載操作為value)
4.用NSOpertion和NSOpertionQueue處理A,B,C三個線程,要求執(zhí)行完A,B后才能執(zhí)行C,怎么做?
//創(chuàng)建隊列
NSOperationQueue *queue =[[NSOperationQueue alloc] init];
//創(chuàng)建3個操作
NSOperation *a = [NSBlockOperationblockOperationWithBlock:^{
NSLog(@”operation1---“);
}];
NSOperation *b= [NSBlockOperation blockOperationWithBlock:^{
NSLog(@”operation1---“);
}];
NSOperation *c= [NSBlockOperation blockOperationWithBlock:^{
NSLog(@”operation1---“);
}];
//添加依賴
[c addDependency:a];
[c addDependency:b];
//執(zhí)行操作
[queue addOperation:a];
[queue addOperation:b];
[queue addOperation:c];
5.列舉cocoa中常見對幾種多線程的實現(xiàn),并談?wù)劧嗑€程安全的幾種解決辦法及多線程安全怎么控制?
1>只在主線程刷新訪問UI
2>如果要防止資源搶奪,得用synchronized進(jìn)行加鎖保護(hù)
3>如果異步操作要保證線程安全等問題,盡量使用GCD(有些函數(shù)默認(rèn)就是安全的)
6.GCD內(nèi)部怎么實現(xiàn)的
1> iOS和OS X的核心是XNU內(nèi)核,GCD是基于XNU內(nèi)核實現(xiàn)的
2> GCD的API全部在libdispatch庫中
3> GCD的底層實現(xiàn)主要有Dispatch Queue和Dispatch Source
Dispatch Queue:管理block(操作)
Dispatch Source:處理事件(MACH端口發(fā)送,MACH端口接收,檢測與進(jìn)程相關(guān)事件等10種事件)
7.你用過NSOperationQueue么?如果用過或者了解的話,你為什么要使用NSOperationQueue,實現(xiàn)了什么?請描述它和GCD的區(qū)別和類似的地方(提示:可以從兩者的實現(xiàn)機(jī)制和適用范圍來描述)。
1> GCD是純C語言的API,NSOperationQueue是基于GCD的OC版本封裝
2> GCD只支持FIFO(先進(jìn)先出)的隊列,NSOperationQueue可以很方便地調(diào)整執(zhí)行順序、設(shè)置最大并發(fā)數(shù)量
3> NSOperationQueue可以在輕松在Operation間設(shè)置依賴關(guān)系,而GCD需要寫很多的代碼才能實現(xiàn)
4> NSOperationQueue支持KVO,可以監(jiān)測operation是否正在執(zhí)行(isExecuted)、是否結(jié)束(isFinished),是否取消(isCanceld)
5> GCD的執(zhí)行速度比NSOperationQueue快任務(wù)之間不太互相依賴:GCD
任務(wù)之間有依賴\或者要監(jiān)聽任務(wù)的執(zhí)行情況:NSOperationQueue
8.既然提到GCD,那么問一下在使用GCD以及block時要注意些什么?它們兩是一回事兒么?block在ARC中和傳統(tǒng)的MRC中的行為和用法有沒有什么區(qū)別,需要注意些什么?
Block的使用注意:
1>block的內(nèi)存管理
2>防止循環(huán)retian非ARC(MRC):__block
ARC:__weak__unsafe_unretained
9.在異步線程中下載很多圖片,如果失敗了,該如何處理?請結(jié)合RunLoop來談?wù)劷鉀Q方案.(提示:在異步線程中啟動一個RunLoop重新發(fā)送網(wǎng)絡(luò)請求,下載圖片)
1>重新下載圖片
2>下載完畢,利用RunLoop的輸入源回到主線程刷新UIImageVIUew
2、多線程?
一個進(jìn)程開啟多條線程,每條線程并發(fā)地執(zhí)行不同的任務(wù)。多線程的并發(fā)(同時)執(zhí)行,其實是CPU快速地在多個線程間調(diào)度(切換)
優(yōu)點:可以適當(dāng)?shù)奶岣叱绦虻膱?zhí)行效率,能適當(dāng)提高資源利用率(CPU、內(nèi)存利用率),
缺點:開啟線程需要占用一定的內(nèi)存空間(默認(rèn)情況下,主線程占用1M,子線程占用512KB),如果開啟大量的線程,會占用大量的內(nèi)存空間,降低程序的性能
線程越多,CPU在調(diào)度線程上的開銷就越大
程序設(shè)計更加復(fù)雜:比如線程之間的通信、多線程的數(shù)據(jù)共享
一般開1~3條線程,不能超過5條
主線程:(UI線程)處理UI刷新、處理事件、用戶交互
子線程:(異步線程、后臺線程):處理比較耗時的操作(如下載等)
3、創(chuàng)建多線程的4種方式?
pthread、NSThread、NSOperation、GCD
區(qū)別:
a、pthread:POSIX線程,是基于C語言的,調(diào)用的時候需要引用頭文件
#import ,需要手動的管理線程的生命周期,使用起來比較麻煩
b、NSThread是蘋果封裝后的基于OC的,是面向?qū)ο蟮模沁€是需要手動管理線程的生命周期
c、GCD:Grand Central Dispatch,是基于C語言底層的API,是基于XNU內(nèi)核的,會充分利用cpu的內(nèi)核,而且無需我們手動管理線程的生命周期(線程的創(chuàng)建、調(diào)度、銷毀等操作),GCD的API全部在libdispatch庫中
GCD的底層實現(xiàn)主要有Dispatch Queue和Dispatch Source
Dispatch Queue:管理block(操作)
Dispatch Source:處理事件
GCD的核心思想是將操作放入隊列中執(zhí)行:操作放在block中,隊列是queue
GCD的操作有兩種:
并發(fā)隊列:全局并發(fā)隊列,也可以手動創(chuàng)建
串行隊列:主隊列,也可以手動創(chuàng)建
串行隊列:
dispatch_queue_t queue =dispatch_queue_create("tk.bourne.testQueue",NULL);
dispatch_queue_t queue =dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_SERIAL);
并行隊列
dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue",DISPATCH_QUEUE_CONCURRENT);
第二個參數(shù)用來表示創(chuàng)建的隊列是串行的還是并行的,傳入DISPATCH_QUEUE_SERIAL或NULL表示創(chuàng)建串行隊列。傳入DISPATCH_QUEUE_CONCURRENT表示創(chuàng)建并行隊列。
d、NSOperation:是蘋果基于GCD的oc版本的封裝,面向?qū)ο蟮?,自動管理線程的聲明周期,可以很方便的設(shè)置線程間的依賴,調(diào)整線程的執(zhí)行順序,設(shè)置最大并發(fā)數(shù),支持kvo,可以檢測線程的執(zhí)行狀態(tài),是否正在執(zhí)行、是否結(jié)束,是否取消。
任務(wù):NSOperation的派生類:NSInvocationOperation和NSBlockOperation
創(chuàng)建一個任務(wù),執(zhí)行start方法啟動任務(wù),調(diào)用cancel取消任務(wù)
隊列:主隊列和其他隊列
NSOperationQueue
*queue = [NSOperationQueue mainQueue];主隊列
*queue = [[NSOperationQueue alloc]init];其他隊列
放入主隊列的任務(wù)在主線程中按順序一個接一個的執(zhí)行
放入其他隊列的任務(wù)會在其他線程并發(fā)執(zhí)行
注:在其他隊列中,通過設(shè)置最大并發(fā)數(shù),控制同步還是異步,如設(shè)置最大并發(fā)量為1,就是同步執(zhí)行,否則為異步執(zhí)行
4、什么是線程同步?
多個線程搶奪同一塊資源,造成數(shù)據(jù)安全問題,例如買票
解決方案:互斥鎖、同步鎖、同步操作、信號量、以及其他加鎖方式(條件鎖,遞歸鎖等)
1、@synchronized(鎖對象,一般直接寫:self){
//需要執(zhí)行的代碼
},(最簡單的方法)
@synchronized(self) {
//需要執(zhí)行的代碼塊
}
NSLock : lock加鎖,unlock解鎖,tryLock嘗試獲得鎖對象
2、同步執(zhí)行,GCD的串行隊列和NSOperationQueue其他隊列
設(shè)置queue的maxConcurrentOperationCount為1
3、GCD中信號量dispatch_semaphore_t,也可以防止資源搶奪
4、NSCondition控制線程通信,類似GCD的信號量機(jī)制,也可以解決資源搶奪問題,NSCondition更重要的是解決線程之間的調(diào)度關(guān)系
5、線程間通信的方法
performSelect : onThread : withObject : waitUntilDone
performSelectOnMainThread : withObject : waitUntilDone//跟主線程通信
dispatch_async(dispatch_get_main_queue(),^{ }); //GCD回主線程
[[NSOperationQueue mainQueue]addOperationWithBlock:^{ }];//跟主線程通信
6、線程死鎖?
經(jīng)典的死鎖現(xiàn)象是GCD的同步操作串行隊列:
NSLog(@"1"); //任務(wù)1
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"2");
//任務(wù)2死鎖
});
NSLog(@"3"); //任務(wù)3
只會打?。?
進(jìn)程死鎖:
是指兩個或兩個以上的進(jìn)程在執(zhí)行過程中,因爭奪資源而造成的一種互相等待的現(xiàn)象,若無外力作用,它們都將無法推進(jìn)下去。
產(chǎn)生原因:資源競爭及進(jìn)程推進(jìn)順序非法
死鎖的4個必要條件:互斥、請求保持、不可剝奪、環(huán)路
死鎖的處理:鴕鳥策略、預(yù)防策略、避免策略、檢測與解除死鎖
19、項目中哪塊用到多線程,碰到了什么問題,怎么解決的
什么時候使用多線程:
將耗時、查詢或者并發(fā)需求高等任務(wù)分配到其他線程執(zhí)行,并由主線程負(fù)責(zé)統(tǒng)一更新界面會使得應(yīng)用程序更加流暢,用戶體驗更好,例如網(wǎng)絡(luò)請求,播放游戲的背景音樂,文件下載等。
碰到的問題以及解決辦法:
(1)使用多線程時通常需要控制線程的并發(fā)數(shù),因為線程會消耗系統(tǒng)資源,同時運行的線程過多,系統(tǒng)會變慢。
使用以下方法可以控制并發(fā)的線程數(shù)量:
-(void)setMaxConcurrentOperationCount:(NSInteger)cnt;
使用addDependency可以建立操作之間的依賴關(guān)系,設(shè)定操作的執(zhí)行順序
(2)當(dāng)多個線程對同一個資源出現(xiàn)爭奪的時候需要注意線程安全問題:
添加互斥鎖。
(3)更新UI界面,處理界面和用戶之間的交互事件一定要在主線程中處理。多線程中棧與堆是公有的還是私有的?
一般來說棧是私有的,堆是公有的;但是可以為特定的線程創(chuàng)建私有的堆。
在多線程環(huán)境下,每個線程擁有一個棧和一個程序計數(shù)器。棧和程序計數(shù)器用來保存線程的執(zhí)行歷史和線程的執(zhí)行狀態(tài),是線程私有的資源。其他的資源(比如堆、地址空間、全局變量)是由同一個進(jìn)程內(nèi)的多個線程共享。堆: 是大家共有的空間,分全局堆和局部堆。全局堆就是所有沒有分配的空間,局部堆就是用戶分配的空間。堆在操作系統(tǒng)對進(jìn)程初始化的時候分配,運行過程中也可以向系統(tǒng)要額外的堆,但是記得用完了要還給操作系統(tǒng),要不然就是內(nèi)存泄漏。
棧:是個線程獨有的,保存其運行狀態(tài)和局部自動變量的。棧在線程開始的時候初始化,每個線程的棧互相獨立,因此,棧是線程安全的。操作系統(tǒng)在切換線程的時候會自動的切換棧,就是切換 SS/ESP寄存器。??臻g不需要在高級語言里面顯式的分配和釋放。
21、GCD的隊列(dispatch_queue_t)分哪兩種類型?編寫代碼:使?用并?行隊列實現(xiàn)多線程開發(fā)
串?行隊列Serial Dispatch Queue
并?行隊列Concurrent Dispatch Queue
1:dispatch_queue_t aQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIO RITY_DEFAULT, 0);
2:dispatch_queue_t aQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIO RITY_HIGH, 0);
3:dispatch_queue_t aQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIO RITY_LOW, 0);
5、列舉幾種進(jìn)程的同步機(jī)制并進(jìn)行比較。
(1)信號量機(jī)制:一個信號量只能置一次初值,以后只能對之進(jìn)行p操作或v操作。由此也可以看到,信號量機(jī)制必須有公共內(nèi)存,不能用于分布式操作系統(tǒng),這是它最大的弱點。信號量機(jī)制功能強(qiáng)大,但使用時對信號量的操作分散, 而且難以控制,讀寫和維護(hù)都很困難。加重了程序員的編碼負(fù)擔(dān);核心操作P-V分散在各用戶程序的代碼中,不易控制和管理;一旦錯誤,后果嚴(yán)重,且不易發(fā)現(xiàn)和糾正。
(2)自旋鎖:自旋鎖是為了保護(hù)共享資源提出的一種鎖機(jī)制。調(diào)用者申請的資源如果被占用,即自旋鎖被已經(jīng)被別的執(zhí)行單元保持,則調(diào)用者一直循環(huán)在那里看是否該自旋鎖的保持著已經(jīng)釋放了鎖。自旋鎖是一種比較低級的保護(hù)數(shù)據(jù)結(jié)構(gòu)和代碼片段的原始方式,可能會引起以下兩個問題:
1、死鎖;
2、過多地占用CPU資源傳統(tǒng)自旋鎖由于無序競爭會導(dǎo)致“公平性”問題。(3)管程:信號量機(jī)制功能強(qiáng)大,但使用時對信號量的操作分散,而且難以控制,讀寫和維護(hù)都很困難。因此后來又提出了一種集中式同步進(jìn)程——管程。其基本思想是將共享變量和對它們的操作集中在一個模塊中,操作系統(tǒng)或并發(fā)程序就由這樣的模塊構(gòu)成。這樣模塊之間聯(lián)系清晰,便于維護(hù)和修改,易于保證正確性。
(4)會合:進(jìn)程直接進(jìn)行相互作用
(5)分布式系統(tǒng):由于在分布式操作系統(tǒng)中沒有公共內(nèi)存,因此參數(shù)全為值參,而且不可為指針。
6、導(dǎo)致進(jìn)程死鎖的原因是什么,如何解決。
產(chǎn)生死鎖的原因:
一是系統(tǒng)提供的資源數(shù)量有限,不能滿足每個進(jìn)程的使用;
二是多道程序運行時,進(jìn)程推進(jìn)順序不合理。產(chǎn)生死鎖的必要條件是:
1、互斥條件;
2、不可剝奪條件(不可搶占);
3、部分分配;
4、循環(huán)等待。根據(jù)產(chǎn)生死鎖的四個必要條件,只要使其中之一不能成立,死鎖就不會出現(xiàn)。為此,可以采取下列三種預(yù)防措施:
1、采用資源靜態(tài)分配策略,破壞"部分分配"條件;
2、允許進(jìn)程剝奪使用其他進(jìn)程占有的資源,從而破壞"不可剝奪"條件;
3、采用資源有序分配法,破壞"環(huán)路"條件。死鎖的避免不嚴(yán)格地限制死鎖的必要條件的存在,而是系統(tǒng)在系統(tǒng)運行過程中小心地避免死鎖的最終發(fā)生。最著名的死鎖避免算法是銀行家算法。死鎖避免算法需要很大的系統(tǒng)開銷。
解決死鎖的另一條途徑是死鎖檢測方法,這種方法對資源的分配不加限制,即允許死鎖的發(fā)生。但系統(tǒng)定時地運行一個"死鎖檢測"程序,判斷系統(tǒng)是否已發(fā)生死鎖,若檢測到死鎖發(fā)生則設(shè)法加以解除。
解除死鎖常常采用下面兩種方法:1、資源剝奪法;2、撤消進(jìn)程法
解決策略:鴕鳥策略、預(yù)防策略、避免策略、檢測與解除死鎖
7.線程注意事項
關(guān)于多線程的詳細(xì)介紹
http://mobile.51cto.com/iphone-403490.htm1、線程的堆棧大小
iPhone設(shè)備上的應(yīng)用程序開發(fā)也是屬于嵌入式設(shè)備的開發(fā),同樣需要注意嵌入式設(shè)備開發(fā)時的幾點問題,比如資源上限,處理器速度等。
iPhone中的線程應(yīng)用并不是無節(jié)制的,官方給出的資料顯示iPhone OS下的主線程的堆棧大小是1M,第二個線程開始都是512KB。并且該值不能通過編譯器開關(guān)或線程API函數(shù)來更改。2、Autorelease
如果你什么都不考慮,在線程函數(shù)內(nèi)調(diào)用autorelease,會出現(xiàn)錯誤3、子線程中描畫窗口
多線程編程中普遍遵循一個原則,就是一切與UI相關(guān)的操作都由主線程做,子線程只負(fù)責(zé)事務(wù),數(shù)據(jù)方面的處理。那么如果想在子線程中更新UI時怎么做呢?如果是在windows下,你會PostMessage一個描畫更新的消息,在iPhone中,需要使用performSelectorOnMainThread委托主線程處理。總結(jié):
多線程能適當(dāng)提高程序的執(zhí)行效率,能適當(dāng)提高資源利用率(CPU、內(nèi)存利用率),但是開啟線程需要占用一定的內(nèi)存空間(默認(rèn)情況下,主線程占用1M,子線程占用512KB),如果開啟大量的線程,會占用大量的內(nèi)存空間,降低程序的性能,而且線程越多,CPU在調(diào)度線程上的開銷就越大,使用多線程程序設(shè)計更加復(fù)雜:比如線程之間的通信、多線程的數(shù)據(jù)共享一個iOS程序運行后,默認(rèn)會開啟1條線程,稱為“主線程”或“UI線程”
主線程的使用注意:別將比較耗時的操作放到主線程中。耗時操作會卡住主線程,嚴(yán)重影響UI的流暢度,給用戶一種“卡”的壞體驗
19.多線程在實際項目中的應(yīng)用中有沒有碰到什么問題
什么時候使用多線程:
將耗時、查詢或者并發(fā)需求高等任務(wù)分配到其他線程執(zhí)行,并由主線程負(fù)責(zé)統(tǒng)一更新界面會使得應(yīng)用程序更加流暢,用戶體驗更好,例如網(wǎng)絡(luò)請求,播放游戲的背景音樂,文件下載等。碰到的問題以及解決辦法:
(1)使用多線程時通常需要控制線程的并發(fā)數(shù),因為線程會消耗系統(tǒng)資源,同時運行的線程過多,系統(tǒng)會變慢
使用以下方法可以控制并發(fā)的線程數(shù)量:
-(void)setMaxConcurrentOperationCount:(NSInteger)cnt;
使用addDependency可以建立操作之間的依賴關(guān)系,設(shè)定操作的執(zhí)行順序
(2)當(dāng)多個線程對同一個資源出現(xiàn)爭奪的時候需要注意線程安全問題
(3)更新UI界面,處理界面和用戶之間的交互事件一定要在主線程中處理
dispatch_async(dispatch_get_mian_queue(),^{
//這里應(yīng)該寫哪些代碼?
}
12、談?wù)勀銓Χ嗑€程開發(fā)的理解?ios中有幾種實現(xiàn)多線程的方法?
好處:
①、使用線程可以把程序中占據(jù)時間長的任務(wù)放到后臺去處理,如圖片、視頻的下載
②、發(fā)揮多核處理器的優(yōu)勢,并發(fā)執(zhí)行讓系統(tǒng)運行的更快、更流暢,用戶體驗更好
缺點:
①、大量的線程降低代碼的可讀性,
②、更多的線程需要更多的內(nèi)存空間
③、當(dāng)多個線程對同一個資源出現(xiàn)爭奪的時候要注意線程安全的問題。
iOS有三種多線程編程的技術(shù):
①、NSThread(兩種創(chuàng)建方式)
[NSThread detachNewThreadSelector:@selector(doSomething:) toTarget:self withObject:nil];
NSThread *myThread = [[NSThread alloc] initWithTarget:self selector:@selector(doSomething:) object:nil];
[myThread start];
②、NSOperationQueue
NSOperationQueue *oprationQueue = [[NSOperationQueue alloc] init];
oprationQueue addOperationWithBlock:^{
//這個block語句塊在子線程中執(zhí)行
}
http://alloc.[sinaapp.com/wp/?p=237](http://sinaapp.com/wp/?p=237)
③、Grand Central Dispatch (GCD)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//耗時的操作
dispatch_async(dispatch_get_main_queue(), ^{
//更新界面
});
});
http://blog.[csdn.net/totogo2010/article/details/8016129](http://csdn.net/totogo2010/article/details/8016129)
PS:不顯示的創(chuàng)建線程的方法:
用NSObject的類方法performSelectorInBackground:withObject:
創(chuàng)建一個線程:
[Obj performSelectorInBackground:@selector(doSomething) withObject:nil];
13、線程同步和異步的區(qū)別?IOS中如何實現(xiàn)多線程的同步?
同步:一個線程要等待上一個線程執(zhí)行完之后才能執(zhí)行當(dāng)前的線程,生活中的例子(上廁所)。
異步:同時去做兩件或者多件事。比如邊聽歌邊看報。
14、 GCD的隊列(dispatch_queue_t)分哪兩種類型?
串行隊列Serial Dispatch Queue
并行隊列Concurrent Dispatch Queue
15、你參與的APP,是如何處理多個服務(wù)的同步發(fā)起的?
使用iOS線程技術(shù),創(chuàng)建并行隊列來分別執(zhí)行不同的任務(wù)。將不同的任務(wù)加入到子隊列當(dāng)中,任務(wù)執(zhí)行后回到主線程當(dāng)中刷新UI界面。
APP界面一般都是根據(jù)產(chǎn)品需求和UI效果圖來完成的,但是我們?yōu)榱颂岣叽a的復(fù)用性,會將視圖的實現(xiàn)進(jìn)行封裝,然后在控制器當(dāng)中進(jìn)行加載調(diào)用。
16、NSOperationQueue有哪些使用方式?
一種在iOS中執(zhí)行并發(fā)操作的方法,是使用NSOperation和NSOperationQueue類。
另一種處理操作之間的依賴關(guān)系,如果操作直接有依賴關(guān)系,比如第二個操作必須等第一個操作結(jié)束后再執(zhí)行。控制線程池中的線程數(shù),具體參考http://blog.sina.com.cn/s/blog_45e2b66c0100ztz7.html
17、NSThread中的Runloop的作用,如何使用?
有些情況下,我們還是在運行一些長線任務(wù)或者復(fù)雜任務(wù)的時候需要用比較原始的NSThread。這就需要為NSThread創(chuàng)建一個run loop.
NSThread *thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(playerThread: ) object:nil];
[thread start];
//如果要利用NSOperation,原理類似。只需要加入到queue里面去就好了。queue會在合適的時機(jī)調(diào)用方法,下面代碼作為參考。
- (void) playerThread: (void*)unused
{
audioRunLoop = CFRunLoopGetCurrent();//子線程的runloop引用
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];//子線程的
[self initPlayer]; CFRunLoopRun(); //運行子線程的
[pool release]; // run loop,這里就會停住了。
}
//實現(xiàn)一個timer,用于檢查子線程的工作狀態(tài),并在合適的時候做任務(wù)切換?;蛘呤呛线m的時候停掉自己的
-(void) initPlayer
{
//在這里你可以初始化一個工作類,比如聲音或者視頻播放
NSTimer *stateChange = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(checkStatuserInfo:nil repeats:YES];
}
-(void) checkState:(NSTimer*) timer
{
if(需要退出自線程了) {
//釋放子線程里面的資源
CFRunLoopStop( CFRunLoopGetCurrent());//結(jié)束子線程任務(wù)
}
}
18、NSThread、NSOperationQueue以及GCD等多線程編程技術(shù)什么情況下使用?
1)NSThread
優(yōu)點:NSThread比其他兩個輕量級
缺點:需要自己管理線程的生命周期,線程同步。線程同步對數(shù)據(jù)的加鎖會有一定的系統(tǒng)開銷2)Cocoa NSOperation
優(yōu)點:不需要關(guān)心線程管理, 數(shù)據(jù)同步的事情,可以把精力放在自己需要執(zhí)行的操作上。
Cocoa operation相關(guān)的類是NSOperation, NSOperationQueue.
NSOperation是個抽象類,使用它必須用它的子類,可以實現(xiàn)它或者使用它定義好的兩個子類: NSInvocationOperation和NSBlockOperation.
創(chuàng)建NSOperation子類的對象,把對象添加到NSOperationQueue隊列里執(zhí)行。3)GCD使用過程中遇到的問題?
3.NSOperationQueue中有一個屬性叫maxConcurrentCount即最大并發(fā)數(shù)。這里所謂的最大并發(fā)數(shù)指的是什么含義?
答:這里的最大并發(fā)數(shù)指的是在隊列中同時執(zhí)行的任務(wù)的個數(shù)。有很多人會認(rèn)為是所分配的線程的個數(shù)。其實不是的。因為線程的個數(shù)的多少取決于系統(tǒng),系統(tǒng)會分配合適的線程數(shù)量來保證這些任務(wù)并發(fā)執(zhí)行的,作為程序員我們是沒辦法控制的。
4.在項目中什么時候選擇使用GCD,什么時候選擇使用NSOperation?
答:無論是GCD還是NSOperation其實都是多線程的一種實現(xiàn)形式。嚴(yán)格的說NSOperation和線程并沒有必然聯(lián)系,更不是多線程,NSOperation只是操作,封裝了target和action或者Block,在主線程中執(zhí)行Operation,Operation就會運行在主線程中,在子線程中執(zhí)行Operation,Operation就運行在子線程中。它只有和NSOperationQueue聯(lián)合使用的時候,才能發(fā)揮出價值。NSOperationQueue是Operation的管理者,它首先是一個隊列,先來的任務(wù)先開始執(zhí)行,后來的任務(wù)后開始執(zhí)行,這些任務(wù)的執(zhí)行是并發(fā)的,NSOperationQueue負(fù)責(zé)為任務(wù)開辟線程以及關(guān)閉線程,有點類似于cell重用,用有限的線程執(zhí)行任意數(shù)量的任務(wù),同時可以設(shè)置最大并發(fā)數(shù),控制程序的性能,不至于全部任務(wù)一起執(zhí)行。GCD出現(xiàn)比NSOperationQueue要晚,是一套基于C函數(shù)的API,由于是C函數(shù),所以性能比較高,使用靈活,安全,當(dāng)然功能也強(qiáng)大。但是相對于GCD來講,NSOperationQueue對線程做了封裝,使用比較簡單,尤其是不用管理線程的開啟和關(guān)閉。個人認(rèn)為,如果僅僅是想要實現(xiàn)異步執(zhí)行任務(wù),首選GCD,如果要管理多個異步任務(wù),NSoperationQueue比較方便。如果要做更復(fù)雜的處理,比如前5個任務(wù)并發(fā),5個任務(wù)執(zhí)行完之后,需要串行執(zhí)行3個任務(wù),之后再并發(fā)執(zhí)行若干任務(wù),就需要使用GCD了。總的來說,特別簡單的和非常復(fù)雜的多線程任務(wù)GCD比較適合,介于二者之間的用NSOperationQueue比較合適。
5.寫出在多線程情況下的一個單例。
答:一般情況下,在開發(fā)中我們所寫的單例都是偽單例。即只是保證了在調(diào)用某一方法時,所產(chǎn)生的對象只有一個,但是沒有考慮其他的影響其引用計數(shù)的方法。例如retain、copy等。為了保證線程安全,單例的寫法如下所示:
方法一:
static AccountManager *sharedAccountManagerInstance = nil;
+ (AccountManager *)sharedManager{
@synchronized (self){
if (sharedAccountManagerInstance == nil) {
sharedAccountManagerInstance = [[AccountManager alloc] init];
}
}
return sharedAccountManagerInstance;
}
方法二:
static AccountManager *sharedAccountManagerInstance = nil;
+ (AccountManager *)sharedManager
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedAccountManagerInstance = [[AccountManager alloc] init];
});
return sharedAccountManagerInstance;
}
6、NSThread中的Runloop的作用,如何使用?
每個線程(NSThread)對象中內(nèi)部都有一個run loop(NSRunLoop)對象用來循環(huán)處理輸入事件,處理的事件包括兩類,一是來自Input sources的異步事件,一是來自Timer sources的同步事件;
run Loop在處理輸入事件時會產(chǎn)生通知,可以通過Core Foundation向線程中添加run-loop observers來監(jiān)聽特定事件,以在監(jiān)聽的事件發(fā)生時做附加的處理工作。 主線程的Run Loop會在App運行時自動運行,子線程中需要手動運行。
Run Loop就是一個處理事件源的循環(huán),你可以控制這個Run Loop運行多久,如果當(dāng)前沒有事件發(fā)生,Run Loop會讓這個線程進(jìn)入睡眠狀態(tài)(避免再浪費CPU時間),如果有事件發(fā)生,Run Loop就處理這個事件。
如果子線程進(jìn)入一個循環(huán)需要不斷處理一些事件,那么設(shè)置一個Run Loop是最好的處理方式,如果需要Timer,那么Run Loop就是必須的。
開發(fā)中遇到的需要使用Run Loop的情況有:
需要使用Port或者自定義Input Source與其他線程進(jìn)行通訊。
子線程中使用了定時器;
使用任何performSelector*****到子線程中運行方法
使用子線程去執(zhí)行周期性任務(wù)
NSURLConnection在子線程中發(fā)起異步請求
20、描述runloop和線程的關(guān)系
Run loop,正如其名,loop表?示某種循環(huán),和run放在一起就表?一直在運?行著的循環(huán)。實際上,run loop和線程是緊密相連的,可以這樣說run loop是為了線程?生,沒有線程,它就沒有存在的必要。Run loops是線程的基礎(chǔ)架構(gòu)部分, Cocoa和CoreFundation都提供了run loop對象?方便配置和管理線程的run loop(以下都已Cocoa為例)。每個線程,包括程序的主線程(main thread)都有與之相 應(yīng)的run loop對象。
14、runloop和線程有什么關(guān)系?
總的說來,Run loop,正如其名,loop表示某種循環(huán),和run放在一起就表示一直在運行著的循環(huán)。實際上,run loop和線程是緊密相連的,可以這樣說run loop是為了線程而生,沒有線程,它就沒有存在的必要。Run loops是線程的基礎(chǔ)架構(gòu)部分,Cocoa和CoreFundation都提供了run loop對象方便配置和管理線程的run loop(以下都以Cocoa為例)。每個線程,包括程序的主線程(main thread)都有與之相應(yīng)的run loop對象。
runloop和線程的關(guān)系:主線程的run loop默認(rèn)是啟動的。iOS的應(yīng)用程序里面,程序啟動后會有一個如下的main()函數(shù)
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
重點是UIApplicationMain()函數(shù),這個方法會為main thread設(shè)置一個NSRunLoop對象,這就解釋了:為什么我們的應(yīng)用可以在無人操作的時候休息,需要讓它干活的時候又能立馬響應(yīng)。
對其它線程來說,run loop默認(rèn)是沒有啟動的,如果你需要更多的線程交互則可以手動配置和啟動,如果線程只是去執(zhí)行一個長時間的已確定的任務(wù)則不需要。
在任何一個Cocoa程序的線程中,都可以通過以下代碼來獲取到當(dāng)前線程的run loop。
NSRunLoop *runloop = [NSRunLoop currentRunLoop];
6、線程間通訊
1、在后臺線程下載圖像
[self performSelectorInBackground:@selector(downloadImage) withObject:nil];
2、在主線程設(shè)置圖像
// waitUntilDone:是否等待主線程執(zhí)行完畢 setImage:方法。
// YES:等待 NO:不等待
// 一般不用等待,直接設(shè)置 NO 即可
[self performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO];
13、線程間通訊
主線程實現(xiàn)
1、定義屬性
/// 根視圖是滾動視圖
@property (nonatomic, strong) UIScrollView *scrollView;
/// 圖像視圖
@property (nonatomic, weak) UIImageView *imageView;
/// 網(wǎng)絡(luò)下載的圖像
@property (nonatomic, weak) UIImage *image;
2、loadView 方法
加載視圖層次結(jié)構(gòu)
用純代碼開發(fā)應(yīng)用程序時使用
功能和 Storyboard & XIB 是等價的
- (void)loadView {
_scrollView = [[UIScrollView alloc] init];
_scrollView.backgroundColor = [UIColor orangeColor];
self.view = _scrollView;
UIImageView *iv = [[UIImageView alloc] init];
[self.view addSubview:iv];
_imageView = iv;
}
3、viewDidLoad 方法
視圖加載完成后執(zhí)行
可以做一些數(shù)據(jù)初始化的工作
如果用純代碼開發(fā),不要在此方法中設(shè)置界面 UI
- (void)viewDidLoad {
[super viewDidLoad];
// 下載圖像
[self downloadImage];
}
4、下載網(wǎng)絡(luò)圖片
- (void)downloadImage{
// 1. 網(wǎng)絡(luò)圖片資源路徑
NSURL *url = [NSURL URLWithString:@"[http://c.hiphotos.baidu.com/image/pic/item/4afbfbedab64034f42b14da1aec379310a551d1c.jpg](http://c.hiphotos.baidu.com/image/pic/item/4afbfbedab64034f42b14da1aec379310a551d1c.jpg)"];
// 2. 從網(wǎng)絡(luò)資源路徑實例化二進(jìn)制數(shù)據(jù)(網(wǎng)絡(luò)訪問)
NSData *data = [NSData dataWithContentsOfURL:url];
// 3. 將二進(jìn)制數(shù)據(jù)轉(zhuǎn)換成圖像
UIImage *image = [UIImage imageWithData:data];
// 4. 設(shè)置圖像
self.image = image;
}
5、設(shè)置圖片
- (void)setImage:(UIImage *)image {
// 1. 設(shè)置圖像視圖的圖像
self.imageView.image = image;
// 2. 按照圖像大小設(shè)置圖像視圖的大小
[self.imageView sizeToFit];
// 3. 設(shè)置滾動視圖的 contentSize
self.scrollView.contentSize = image.size;
}
6、設(shè)置滾動視圖的縮放
1)設(shè)置滾動視圖縮放屬性
// 1> 最小縮放比例
self.scrollView.minimumZoomScale = 0.5;
// 2> 最大縮放比例
self.scrollView.maximumZoomScale = 2.0;
// 3> 設(shè)置代理
self.scrollView.delegate = self;
2)實現(xiàn)代理方法 - 告訴滾動視圖縮放哪一個視圖
#pragma mark - UIScrollViewDelegate 代理方法
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return self.imageView;
}
7、線程間通訊
1)在后臺線程下載圖像
[self performSelectorInBackground:@selector(downloadImage) withObject:nil];
2)在主線程設(shè)置圖像
// waitUntilDone:是否等待主線程執(zhí)行完畢 setImage:方法。
// YES:等待 NO:不等待
// 一般不用等待,直接設(shè)置 NO 即可
[self performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO];
3.多線程的實現(xiàn),你用過哪些?如何保證線程安全?
1.使用互斥鎖
優(yōu)點:能有效防止因多線程搶奪資源造成的數(shù)據(jù)安全問題
缺點:需要消耗大量的CPU資源2.原子和非原子屬性
OC在定義屬性時有nonatomic和atomic兩種選擇
atomic:原子屬性,為setter方法加鎖(默認(rèn)就是atomic)
nonatomic:非原子屬性,不會為setter方法加鎖atomic:線程安全,需要消耗大量的資源
nonatomic:非線程安全,適合內(nèi)存小的移動設(shè)備
*96.關(guān)于下面線程管理錯誤的是(B)
//不確定
A.GCD在后端管理著一個線程池
B.NSOperationQueue是對NSthread的更高層的封裝
C.NSThread需要自己管理線程的生命周期
D.GCD可以根據(jù)不同優(yōu)先級分配線程,對
102.請使用gcd完成如下任務(wù),執(zhí)行并發(fā)任務(wù)task1,task1完成后update UI.
答:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
//task1:
NSLog(@"執(zhí)行task1");
//更新UI
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"更新UI");
});
});
103.為什么在主線程中更新UI?子線程中想要更新UI怎么做?
答:
(1)在子線程中不能更新UI,除了極少數(shù)UI外,其他UI更新要等到子線程執(zhí)行完畢后回到主線程中進(jìn)行更新。如果子線程一直在運行,則子線程中UI更新的函數(shù)棧主線程無法得知,即UI無法更新;
(2)回到主線程中進(jìn)行UI更新;
7、Object_C中創(chuàng)建線程的方法有哪些?如果在主線程中執(zhí)行代碼,方法是什么?如果想在延時執(zhí)行代碼,方法又是什么?
創(chuàng)建線程方式 GCD,NSOpertaion,NSThread
主線程要用 dispatch_get_main_queue()
延時的方法dispatch_after
- Object C中創(chuàng)建線程的方法是什么?如果在主線程中執(zhí)行代碼,方法是什么?如果想延時執(zhí)行代碼,方法又是什么?
線程創(chuàng)建有三種方法:使用NSThread創(chuàng)建、使用GCD的dispatch、使用子類化的NSOperation,然后將其加入NSOperationQueue;
在主線程執(zhí)行代碼,方法是performSelectorOnMainThread,
如果想延時執(zhí)行代碼可以用
performSelector:onThread:withObject: afterDelay:
或者使用GCD的函數(shù):
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 2秒后異步執(zhí)行這里的代碼...
});
3.列舉Cocoa中常用的幾種多線程實現(xiàn),并談?wù)劧嗑€程安全問題的幾種解決方案,什么地方會用到多線程?
多線程實現(xiàn)方法:
1、Thread;
2、Cocoa operations;
3、Grand Central Dispatch (GCD) (iOS4 才開始支持)多線程安全問題解決方案:
添加互斥鎖,
1、列舉Cocoa中常見對幾種線程的實現(xiàn),并談?wù)劧嗑€程安全的幾種解決辦法和多線程安全怎么控制.
Cocoa中常見對幾種線程的實現(xiàn):
(1)OC的NSThread
(2) C語言的GCD接口(性能最好,代碼更精簡)
(3) OC的NSOperation和NSOperationQueue(基于GCD)多線程安全的幾種解決辦法
(1)只在主線程刷新訪問UI
(2)如果要防止資源搶奪,得用synchronize進(jìn)行加鎖保護(hù)。
(3)如果異步操作要保證線程安全等問題,盡量使用GCD。(GCD有些函數(shù)默認(rèn)就是安全的)
9、GCD的queue,main queue中執(zhí)行的代碼,一定是在main thread么?
看:http://www.tuicool.com/articles/AVnMVj
1、對于queue中所執(zhí)行的代碼不一定在main thread中。如果queue是在主線程中創(chuàng)建的,那么所執(zhí)行的代碼就是在主線程中執(zhí)行。如果是在子線程中創(chuàng)建的,那么就不會在main thread中執(zhí)行。
2、對于main queue就是在主線程中的,因此一定會在主線程中執(zhí)行。獲取main queue就可以了,不需要我們創(chuàng)建,獲取方式通過調(diào)用方法dispatch get main_queue來獲取。
10、從用戶體驗角度舉例說明同步和異步。
答:
1.同步意味著線程阻塞,在主線程中使用此方法會不響應(yīng)任何用戶事件。所以,在應(yīng)用程序設(shè)計時,大多被用在專門的子線程增加用戶體驗,或用異步請求代替。
2.異步請求的好處是不阻塞當(dāng)前線程,但相對于同步請求略為復(fù)雜,至少要添加兩個回調(diào)方法來獲取異步事件,從用戶的體驗來說,異步請求數(shù)據(jù)的APP比同步請求的APP操作更加流暢,快捷,
11、以下兩種GCD隊列創(chuàng)建有什么不同?
dispatch_queue_t queue = dispatch_queue_create("MyQueue”, DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue = dispatch_queue_create(@"MyQueue", DISPATCH_QUEUE_CONCURRENT);
//生成一個串行隊列,隊列中的block按照先進(jìn)先出(FIFO)的順序去執(zhí)行,實際上為單線程執(zhí)行。第一個參數(shù)是隊列的名稱,在調(diào)試程序時會非常有用,所有盡量不要重名了。
// 生成一個并發(fā)執(zhí)行隊列,block被分發(fā)到多個線程去執(zhí)行
11、線程是什么?進(jìn)程是什么?二者有什么區(qū)別和聯(lián)系?
線程是CPU獨立運行和獨立調(diào)度的基本單位(可以理解為一個進(jìn)程中執(zhí)行的代碼片段);
進(jìn)程是資源分配的基本單位(進(jìn)程是一塊包含了某些資源的內(nèi)存區(qū)域)。
進(jìn)程是線程的容器,真正完成代碼執(zhí)行的是線程,而進(jìn)程則作為線程的執(zhí)行環(huán)境。
一個程序至少包含一個進(jìn)程,一個進(jìn)程至少包含一個線程,一個進(jìn)程中的多個線程共享當(dāng)前進(jìn)程所擁有的資源。
8、線程和進(jìn)程的區(qū)別和聯(lián)系
進(jìn)程和線程都是由操作系統(tǒng)所體會的程序運行的基本單元,系統(tǒng)利用該基本單元實現(xiàn)系統(tǒng)對應(yīng)用的并發(fā)性。
進(jìn)程和線程的主要差別在于它們是不同的操作系統(tǒng)資源管理方式。
進(jìn)程有獨立的地址空間,一個進(jìn)程崩潰后,在保護(hù)模式下不會對其它進(jìn)程產(chǎn)生影響。
而線程只是一個進(jìn)程中的不同執(zhí)行路徑。線程有自己的堆棧和局部變量,但線程之間沒有單獨的地址空間,一個線程死掉就等于整個進(jìn)程死掉,所以多進(jìn)程的程序要比多線程的程序健壯,但在進(jìn)程切換時,耗費資源較大,效率要差一些。但對于一些要求同時進(jìn)行并且又要共享某些變量的并發(fā)操作,只能用線程,不能用進(jìn)程。
1、線程和進(jìn)程?
進(jìn)程:用于指代一個正在運行的可執(zhí)行程序,它可以包含多個線程,是擁有獨立資源的最小單元
線程:用于指代獨立執(zhí)行的代碼段。線程是進(jìn)程中執(zhí)行運算的最小單位,是進(jìn)程中的一個實體,是被系統(tǒng)獨立調(diào)度和分派的基本單位
兩者之前的聯(lián)系:一個進(jìn)程至少包含一個線程,稱為主線程,而一個線程只能屬于一個進(jìn)程,進(jìn)程是擁有獨立的地址空間,擁有獨立的資源,是擁有獨立資源的最小單元,線程本身不擁有系統(tǒng)資源,但與所在的進(jìn)程中的其他線程共享進(jìn)程的全部資源。
進(jìn)程和線程的主要差別在于它們是不同的操作系統(tǒng)資源管理方式。進(jìn)程有獨立的地址空間,一個進(jìn)程崩潰后,在保護(hù)模式下不會對其它進(jìn)程產(chǎn)生影響,而線程只是一個進(jìn)程中的不同執(zhí)行路徑。線程有自己的堆棧和局部變量,但線程之間沒有單獨的地址空間,一個線程死掉就等于整個進(jìn)程死掉,所以多進(jìn)程的程序要比多線程的程序健壯,但在進(jìn)程切換時,耗費資源較大,效率要差一些。但對于一些要求同時進(jìn)行并且又要共享某些變量的并發(fā)操作,只能用線程,不能用進(jìn)程。
12.線程與進(jìn)程的區(qū)別與聯(lián)系
進(jìn)程,是并發(fā)執(zhí)行的程序在執(zhí)行過程中分配和管理資源的基本單位,是一個動態(tài)概念,計算機(jī)系統(tǒng)資源的基本單位。每一個進(jìn)程都有一個自己的地址空間,即進(jìn)程空間或(虛空間)。進(jìn)程空間的大小只與處理機(jī)的位數(shù)有關(guān),一個16位長處理機(jī)的進(jìn)程空間大小為216,而32位處理機(jī)的進(jìn)程空間大小為232。進(jìn)程至少有5種基本狀態(tài),它們是:初始態(tài),執(zhí)行態(tài),等待狀態(tài),就緒狀態(tài),終止?fàn)顟B(tài)。
線程,在網(wǎng)絡(luò)或多用戶環(huán)境下,一個服務(wù)器通常需要接收大量且不確定數(shù)量用戶的并發(fā)請求,為每一個請求都創(chuàng)建一個進(jìn)程顯然是行不通的,無論是從系統(tǒng)資源開銷方面或是響應(yīng)用戶請求的效率方面來看。因此,操作系統(tǒng)中線程的概念便被引進(jìn)了。
線程,是進(jìn)程的一部分,一個沒有線程的進(jìn)程可以被看作是單線程的。線程有時又被稱為輕權(quán)進(jìn)程或輕量級進(jìn)程,也是CPU調(diào)度的一個基本單位。
進(jìn)程
? 進(jìn)程是指在系統(tǒng)中正在運行的一個應(yīng)用程序
? 每個進(jìn)程之間是獨立的,每個進(jìn)程均運行在其專用且受保護(hù)的內(nèi)存空間內(nèi)
? 通過 活動監(jiān)視器可以查看 Mac 系統(tǒng)中所開啟的進(jìn)程線程
? 進(jìn)程要想執(zhí)行任務(wù),必須得有線程,進(jìn)程至少要有一條線程
? 程序啟動會默認(rèn)開啟一條線程,這條線程被稱為主線程或UI 線程
? 線程是進(jìn)程的基本執(zhí)行單元,進(jìn)程的所有任務(wù)都在線程中執(zhí)行多線程
? 一個進(jìn)程中可以開啟多條線程,每條線程可以同時執(zhí)行不同的任務(wù)
○ 進(jìn)程 -> 公司
○ 線程 -> 員工
○ 主線程 -> 老板(第一個員工)
? 多線程技術(shù)可以提高程序的執(zhí)行效率多線程原理
? 同一時間,CPU只能處理一條線程,只有一條線程在執(zhí)行
? 多線程同時執(zhí)行,其實是CPU快速地在多條線程之間切換
? 如果CPU調(diào)度線程的時間足夠快,就造成了多線程并發(fā)執(zhí)行的假象
? 如果線程非常多,會在多條線程之間來回切換,消耗大量的 CPU 資源
○ 每個線程被調(diào)度的次數(shù)會降低
○ 線程的執(zhí)行效率會下降iOS 8.0 主線程的默認(rèn)堆棧大小也是 512K
多線程優(yōu)缺點
優(yōu)點
? 能適當(dāng)提高資源利用率(CPU、內(nèi)存利用率)
? 能適當(dāng)提高程序的執(zhí)行效率
缺點
? 開啟線程需要占用一定的內(nèi)存空間,如果開啟大量的線程,會占用大量的內(nèi)存空間,降低程序的性能
? 線程越多,CPU在調(diào)度線程上的開銷就越大
? 程序設(shè)計更加復(fù)雜:比如線程之間的通信、多線程的數(shù)據(jù)共享主線程
? 程序啟動創(chuàng)建的線程,被稱為主線程或UI線程
? 主線程的作用
○ 顯示/刷新 UI 界面
○ 處理 UI 事件:點擊、滾動、拖拽等事件注意:要將耗時操作放在后臺線程執(zhí)行,否則會影響 UI 的流暢度,破壞用戶體驗
所有網(wǎng)絡(luò)訪問都是耗時操作!
173.請描述一下線程的生命周期。
新建(new Thread)、就緒(runnable)、運行(running)、死亡(dead)、堵塞(blocked)
1.NSOPrationQueue 與GCD分別在什么情況下更合適使用?
1、GCD是底層的C語言構(gòu)成的API,而NSOperationQueue是基于GCD的OC封裝。
2、GCD支持FIFO隊列,NSOperationQueue可以方便設(shè)置執(zhí)行順序,設(shè)置最大的并發(fā)數(shù)量。
3、NSOperationQueue可以方便地設(shè)置operation之間的依賴關(guān)系,GCDF則需要更多的代碼。
4、NSOperationQueue支持KVO,可以檢測operation是否正在執(zhí)行(isExecuted),是否結(jié)束(isFinished),是否取消(isCanceled)。
5、GCD的執(zhí)行速度比NSOperationQueue快。使用場合:
任務(wù)之間不太相互依賴:GCD;
任務(wù)之間依賴或者監(jiān)聽任務(wù)的執(zhí)行情況:NSOperationQueue那這兩者直接有什么區(qū)別呢?
1、GCD是底層的C語言構(gòu)成的API,而NSOperationQueue及相關(guān)對象是Objc的對象。在GCD中,在隊列中執(zhí)行的是由block構(gòu)成的任務(wù),這是一個輕量級的數(shù)據(jù)結(jié)構(gòu);而Operation作為一個對象,為我們提供了更多的選擇;
2、在NSOperationQueue中,我們可以隨時取消已經(jīng)設(shè)定要準(zhǔn)備執(zhí)行的任務(wù)(當(dāng)然,已經(jīng)開始的任務(wù)就無法阻止了),而GCD沒法停止已經(jīng)加入queue的block(其實是有的,但需要許多復(fù)雜的代碼);
3、NSOperation能夠方便地設(shè)置依賴關(guān)系,我們可以讓一個Operation依賴于另一個Operation,這樣的話盡管兩個Operation處于同一個并行隊列中,但前者會直到后者執(zhí)行完畢后再執(zhí)行;
4、我們能將KVO應(yīng)用在NSOperation中,可以監(jiān)聽一個Operation是否完成或取消,這樣子能比GCD更加有效地掌控我們執(zhí)行的后臺任務(wù);
5、在NSOperation中,我們能夠設(shè)置NSOperation的priority優(yōu)先級,能夠使同一個并行隊列中的任務(wù)區(qū)分先后地執(zhí)行,而在GCD中,我們只能區(qū)分不同任務(wù)隊列的優(yōu)先級,如果要區(qū)分block任務(wù)的優(yōu)先級,也需要大量的復(fù)雜代碼;
6、我們能夠?qū)SOperation進(jìn)行繼承,在這之上添加成員變量與成員方法,提高整個代碼的復(fù)用度,這比簡單地將block任務(wù)排入執(zhí)行隊列更有自由度,能夠在其之上添加更多自定制的功能。總的來說,Operation queue 提供了更多你在編寫多線程程序時需要的功能,并隱藏了許多線程調(diào)度,線程取消與線程優(yōu)先級的復(fù)雜代碼,為我們提供簡單的API入口。從編程原則來說,一般我們需要盡可能的使用高等級、封裝完美的API,在必須時才使用底層API。但是我認(rèn)為當(dāng)我們的需求能夠以更簡單的底層代碼完成的時候,簡潔的GCD或許是個更好的選擇,而Operation queue 為我們提供能更多的選擇。
135.實現(xiàn)多線程有哪些方法,分別有什么區(qū)別?
答: (http://www.[cnblogs.com/hanjun/p/3667874.html](http://cnblogs.com/hanjun/p/3667874.html))
1.NSThread
2.NSOperationQueue
3.GCD
區(qū)別:
Thread是這三種范式里面相對輕量級的,但也是使用起來最負(fù)責(zé)的,你需要自己管理thread的生命周期,線程之間的同步。線程共享同一應(yīng)用程序的部分內(nèi)存空間,它們擁有對數(shù)據(jù)相同的訪問權(quán)限。你得協(xié)調(diào)多個線程對同一數(shù)據(jù)的訪問,一般做法是在訪問之前加鎖,這會導(dǎo)致一定的性能開銷。在iOS中我們可以使用多種形式的thread:
Cocoa threads:使用NSThread或直接從NSObject的類方法performSelectorInBackground:withObject:來創(chuàng)建一個線程。如果你選擇thread來實現(xiàn)多線程,那么NSThread就是官方推薦優(yōu)先選用的方式。
Cocoa operations是基于Obective-C實現(xiàn)的,類NSOperation以面向?qū)ο蟮姆绞椒庋b了用戶需要執(zhí)行的操作,我們只要聚焦于我們需要做的事情,而不必太操心線程的管理,同步等事情,因為NSOperation已經(jīng)為我們封裝了這些事情。NSOperation是一個抽象基類,我們必須使用它的子類。iOS提供了兩種默認(rèn)實現(xiàn):NSInvocationOperation和NSBlockOperation。
Grand Central Dispatch (GCD): iOS4才開始支持,它提供了一些新的特性,以及運行庫來支持多核并行編程,它的關(guān)注點更高:如何在多個cpu上提升效率。
34.你的項目什么時候選擇使用GCD,什么時候選擇NSOperation?
答:
項目中使用NSOperation的優(yōu)點是NSOperation是對線程的高度抽象,在項目中使用它,會使項目的程序結(jié)構(gòu)更好,子類化NSOperation的設(shè)計思路,是具有面向?qū)ο蟮膬?yōu)點(復(fù)用、封裝),使得實現(xiàn)是多線程支持,而接口簡單,建議在復(fù)雜項目中使用。
項目中使用GCD的優(yōu)點是GCD本身非常簡單、易用,對于不復(fù)雜的多線程操作,會節(jié)省代碼量,而Block參數(shù)的使用,會是代碼更為易讀,建議在簡單項目中使用。
9.在項目什么時候選擇使用GCD,什么時候選擇NSOperation?
gcd是基于c的底層api,NSOperation屬于object-c類。
相對于gcd:
1,NSOperation擁有更多的函數(shù)可用,具體查看api。
2,在NSOperationQueue中,可以建立各個NSOperation之間的依賴關(guān)系。
3,有kvo,可以監(jiān)測operation是否正在執(zhí)行(isExecuted)、是否結(jié)束(isFinished),是否取消(isCanceld)。
4,NSOperationQueue可以方便的管理并發(fā)、NSOperation之間的優(yōu)先級。
gcd主要與block結(jié)合使用。
項目中使用NSOperation的優(yōu)點是NSOperation是對線程的高度抽象,在項目中使用它,會使項目的程序結(jié)構(gòu)更好,子類化NSOperation的設(shè)計思路,是具有面向?qū)ο蟮膬?yōu)點(復(fù)用、封裝),使得實現(xiàn)是多線程支持,而接口簡單,建議在復(fù)雜項目中使用。
項目中使用GCD的優(yōu)點是GCD本身非常簡單、易用,對于不復(fù)雜的多線程操作,會節(jié)省代碼量,而Block參數(shù)的使用,會是代碼更為易讀,建議在簡單項目中使用。
2.dispatch_queue_t有哪幾種類型?
queue mainqueue globalqueue
5、使用GCD實現(xiàn)一個單例
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
});