黑馬ios1期04多線程_第1頁
黑馬ios1期04多線程_第2頁
黑馬ios1期04多線程_第3頁
黑馬ios1期04多線程_第4頁
黑馬ios1期04多線程_第5頁
已閱讀5頁,還剩33頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

多線程講師:劉凡技術(shù)博客:/liufan9多線程的應(yīng)用應(yīng)用中的網(wǎng)絡(luò)圖片、視頻、歌曲、書籍等資源下載游戲中的聲音播放多線程示意圖充分發(fā)揮多核處理器的優(yōu)勢,并發(fā)執(zhí)行任務(wù)讓系統(tǒng)運(yùn)行的更快、更流暢任務(wù)2任務(wù)…任務(wù)N任務(wù)1并發(fā)任務(wù)2任務(wù)2任務(wù)(…)任務(wù)N任務(wù)1并發(fā)任務(wù)1單線程示意圖多線程示意圖“執(zhí)行流”的概念單核雙核進(jìn)程與線程概念一個(gè)運(yùn)行的程序就是一個(gè)進(jìn)程或者叫做一個(gè)任務(wù)一個(gè)進(jìn)程至少包含一個(gè)線程,線程是程序的執(zhí)行流iOS程序啟動(dòng)時(shí),在創(chuàng)建一個(gè)進(jìn)程的同時(shí),會(huì)開始運(yùn)行一個(gè)線程,該線程被稱為主線程主線程是其他線程最終的父線程,所有界面的顯示操作必須在主線程進(jìn)行!?。∠到y(tǒng)中的每一個(gè)進(jìn)程都有自己獨(dú)立的虛擬內(nèi)存空間,而同一個(gè)進(jìn)程中的多個(gè)線程則共用進(jìn)程的內(nèi)存空間每創(chuàng)建一個(gè)新的線程,都會(huì)消耗一定內(nèi)存和CPU時(shí)間當(dāng)多個(gè)線程對(duì)同一個(gè)資源出現(xiàn)爭奪的時(shí)候需要注意線程安全問題多線程的優(yōu)勢與難點(diǎn)優(yōu)勢充分發(fā)揮多核處理器優(yōu)勢,將不同線程任務(wù)分配給不同的處理器,真正進(jìn)入“并行運(yùn)算”狀態(tài)將耗時(shí)、輪詢或者并發(fā)需求高等任務(wù)分配到其他線程執(zhí)行,并由主線程負(fù)責(zé)統(tǒng)一更新界面會(huì)使得應(yīng)用程序更加流暢,用戶體驗(yàn)更好當(dāng)硬件處理器的數(shù)量增加,程序會(huì)運(yùn)行更快,而無需做任何調(diào)整難點(diǎn)共享資源的“爭奪”多線程是為了同步完成多項(xiàng)任務(wù),不是為了提高運(yùn)行效率,而是為了通過提高資源使用效率來提高系統(tǒng)的整體性能多線程使用注意事項(xiàng)線程使用不是無節(jié)制的iOS中的主線程的堆棧大小是1M從第二個(gè)線程開始都是512KB這些數(shù)值不能通過編譯器開關(guān)或線程API函數(shù)更改只有主線程有直接修改UI的能力iOS的三種多線程技術(shù)NSThreadNSOperationGCD——GrandCentralDispatch,是基于C語言的框架以上這三種編程方式從上到下,抽象度層次是從低到高的,抽象度越高的使用越簡單,也是Apple最推薦使用的。但是就目前而言,iOS的開發(fā)者,需要了解三種多線程技術(shù)的基本使用過程。因?yàn)楹芏嗫蚣芗夹g(shù)分別使用了不同多線程技術(shù)。例如NSURLConnection的異步靜態(tài)方法:sendAsynchronousRequest:requestqueue:[NSOperationQueuemainQueue]

completionHandler:^(NSURLResponse*response,NSData*data,NSError*error)三種多線程技術(shù)的對(duì)比NSThread:優(yōu)點(diǎn):NSThread比其他兩個(gè)輕量級(jí),使用簡單缺點(diǎn):需要自己管理線程的生命周期、線程同步。線程同步對(duì)數(shù)據(jù)的加鎖會(huì)有一定的系統(tǒng)開銷NSOperation:不需要關(guān)心線程管理,數(shù)據(jù)同步的事情,可以把精力放在自己需要執(zhí)行的操作上GCD:GrandCentralDispatch是由蘋果開發(fā)的一個(gè)多核編程的解決方案。iOS4.0+才能使用,是替代NSThread,NSOperation的高效和強(qiáng)大的技術(shù)多線程演練——賣票系統(tǒng)預(yù)設(shè)共有100張票可以銷售(開發(fā)時(shí)可以少一些,專注實(shí)現(xiàn))售票工作由兩個(gè)線程并發(fā)進(jìn)行沒有可出售票據(jù)時(shí),線程工作停止兩個(gè)線程的執(zhí)行時(shí)間不同,模擬售票人員效率不同使用一個(gè)多行文本框公告售票進(jìn)度(主線程更新UI)線程工作安排主線程:負(fù)責(zé)更新UI線程1:模擬第1名賣票員線程2:模擬第2名賣票員兩個(gè)線程幾乎同時(shí)開始賣票單線程賣票流程圖是否還有票?顯示當(dāng)前票數(shù)總票數(shù)-1模擬售票其他耗時(shí)操作賣票結(jié)束YesNo多線程賣票示意圖共享資源(票)賣票線程1賣票線程2賣票流程賣票流程演練準(zhǔn)備——更新UI方法,由主線程調(diào)用//向文本框追加文本-(void)appendTextView:(NSString*)text{

NSMutableString*str=[NSMutableString

stringWithString:[_infoTextView

text]];[strappendFormat:@"\n%@",text];

NSRangerange=NSMakeRange(str.length,1);[_infoTextView

setText:str];

//滾動(dòng)至文本框文字末尾[_infoTextView

scrollRangeToVisible:range];}NSThread創(chuàng)建線程方法:+(void)detachNewThreadSelector:(SEL)selectortoTarget:(id)targetwithObject:(id)argument;-(id)initWithTarget:(id)targetselector:(SEL)selectorobject:(id)argument;參數(shù)說明:selector:線程執(zhí)行的方法,只能有一個(gè)參數(shù),不能有返回值target:selector消息發(fā)送的對(duì)象argument:傳輸給target的唯一參數(shù),也可以是nilNSObject直接加入了多線程的支持,允許對(duì)象的某個(gè)方法在后臺(tái)運(yùn)行(本方法普遍應(yīng)用在游戲中,利用多線程播放聲音)-(void)performSelectorInBackground:(SEL)aSelectorwithObject:(id)arg;NSThread使用流程創(chuàng)建線程啟動(dòng)線程線程執(zhí)行的方法——對(duì)應(yīng)前文單線程賣票流程圖while(YES){

if(_tickets>0){

NSString*str=[NSString

stringWithFormat:@"當(dāng)前票數(shù):%d,售票線程:%@",_tickets,[[NSThreadcurrentThread]name]];

//調(diào)用主線程方法更新UI[self

performSelectorOnMainThread:@selector(appendTextView:)withObject:strwaitUntilDone:YES];

_tickets--;

//模擬休息

if([[[NSThread

currentThread]name]isEqualToString:@"售票線程-1"]){[NSThread

sleepForTimeInterval:0.3f];}else{[NSThread

sleepForTimeInterval:0.2f];}}else{

NSString*str=[NSString

stringWithFormat:@"票已售完,售票線程:%@",[[NSThreadcurrentThread]name]];

//調(diào)用主線程方法更新UI[self

performSelectorOnMainThread:@selector(appendTextView:)withObject:strwaitUntilDone:YES];

break;}}NSThread售票方法//設(shè)置預(yù)售票數(shù),共享資源!_tickets=20;//創(chuàng)建線程1NSThread*thread1=[[NSThread

alloc]initWithTarget:self

selector:@selector(threadSaleMethod)object:nil];//設(shè)置線程名稱,因?yàn)樾枰ㄟ^線程名稱跟蹤線程執(zhí)行情況,因此此處不使用線程靜態(tài)方法[thread1setName:@"售票線程-1"];//啟動(dòng)線程1[thread1start];//創(chuàng)建線程2,步驟同上NSThread*thread2=[[NSThread

alloc]initWithTarget:self

selector:@selector(threadSaleMethod)object:nil];[thread2setName:@"售票線程-2"];[thread2start];運(yùn)行,資源爭奪!解決方案:使用共享資源時(shí)——加鎖!加鎖方案1——對(duì)單個(gè)售票流程加鎖while(YES){

//加鎖

[_threadLocklock];

if(_tickets>0){//……

if([[[NSThread

currentThread]name]isEqualToString:@"售票線程-1"]){[NSThread

sleepForTimeInterval:1.0f];}else{[NSThread

sleepForTimeInterval:0.1f];}}else{//……

//解鎖[_threadLock

unlock];

break;}

//解鎖

[_threadLockunlock];}數(shù)據(jù)安全了,線程休眠模擬卻無法體現(xiàn)了!加鎖方案2——在共享資源被爭奪范圍內(nèi)加鎖//加鎖[_threadLocklock];if(_tickets>0){

NSString*str=[NSString

stringWithFormat:@"當(dāng)前票數(shù):%d,售票線程:%@",_tickets,[[NSThreadcurrentThread]name]];

//調(diào)用主線程方法更新UI[self

performSelectorOnMainThread:@selector(appendTextView:)withObject:strwaitUntilDone:YES];//盡早地使用完共享資源,然后解鎖

_tickets--;

//解鎖[_threadLockunlock];

//……加鎖易犯的錯(cuò)誤——只對(duì)部分共享資源加鎖if(_tickets>0){

NSString*str=[NSString

stringWithFormat:@"當(dāng)前票數(shù):%d,售票線程:%@",_tickets,[[NSThreadcurrentThread]name]];

//調(diào)用主線程方法更新UI[self

performSelectorOnMainThread:@selector(appendTextView:)withObject:strwaitUntilDone:YES];

//加鎖[_threadLocklock];_tickets--;

//解鎖[_threadLockunlock];NSThread使用小結(jié)當(dāng)涉及到共享資源爭奪時(shí),共享資源的數(shù)據(jù)加鎖是一個(gè)難點(diǎn),既要保證數(shù)據(jù)安全,又要保證線程執(zhí)行效率使用前加鎖盡快使用使用完解鎖再去做其他的事情多線程編寫順序單個(gè)方法調(diào)試OK單個(gè)線程調(diào)試OK增加線程,并考慮線程加鎖、解鎖的準(zhǔn)確位置。注意:只有主線程能夠修改UI如果不涉及到內(nèi)存爭搶,NSThread寫多線程是最簡單的當(dāng)不涉及共享資源爭奪時(shí),使用NSObject的performSelectorInBackground方法可以非常的方便地實(shí)現(xiàn)多線程定義一個(gè)鎖加鎖解鎖線程1包括內(nèi)存加鎖解鎖線程2包括內(nèi)存加鎖NSOperation

&

NSOperationQueueNSOperation的兩個(gè)子類NSInvocationOperationNSBlockOperation工作原理:用NSOperation封裝要執(zhí)行的操作將創(chuàng)建好的NSOperation對(duì)象放NSOperationQueue中啟動(dòng)OperationQueue開始新的線程執(zhí)行隊(duì)列中的操作注意事項(xiàng):使用多線程時(shí)通常需要控制線程的并發(fā)數(shù),因?yàn)榫€程會(huì)消耗系統(tǒng)資源,同時(shí)運(yùn)行的線程過多,系統(tǒng)會(huì)變慢使用以下方法可以控制并發(fā)的線程數(shù)量:-(void)setMaxConcurrentOperationCount:(NSInteger)cnt;NSOperation操作流程定義操作1

~

N定義隊(duì)列將操作添加至隊(duì)列隊(duì)列是自動(dòng)啟動(dòng)的OperationQueue調(diào)度的方法while(YES){

if(_tickets>0){

//在主線程操作隊(duì)列更新界面[[NSOperationQueue

mainQueue]addOperationWithBlock:^{

NSString*str=[NSString

stringWithFormat:@"當(dāng)前票數(shù):%d,售票線程:%@",_tickets,operationName];[self

appendTextView:str];

_tickets--;}];

//模擬休息

//……

}else{

//在主線程操作隊(duì)列更新界面[[NSOperationQueue

mainQueue]addOperationWithBlock:^{

NSString*str=[NSString

stringWithFormat:@"票已售完,售票線程:%@",operationName];[self

appendTextView:str];}];

break;}}NSInvocationOperation售票方法//設(shè)置預(yù)售票數(shù),共享資源!_tickets=20;//定義操作1NSInvocationOperation*operation1=[[NSInvocationOperation

alloc]initWithTarget:self

selector:@selector(operationSaleMethod:)object:@"售票操作-1"];//定義操作2NSInvocationOperation*operation2=[[NSInvocationOperation

alloc]initWithTarget:self

selector:@selector(operationSaleMethod:)object:@"售票操作-2"];//定義操作隊(duì)列NSOperationQueue*queue=[[NSOperationQueue

alloc]init];[queueaddOperation:operation1];[queueaddOperation:operation2];NSBlockOperation售票方法(需要補(bǔ)錄視頻)//設(shè)置預(yù)售票數(shù),共享資源!_tickets=20;//定義操作隊(duì)列NSOperationQueue*queue=[[NSOperationQueue

alloc]init];[queueaddOperationWithBlock:^{[self

operationSaleMethod:@"售票操作-1"];}];[queueaddOperationWithBlock:^{[self

operationSaleMethod:@"售票操作-2"];}];測試限制線程并發(fā)數(shù)量——體會(huì)執(zhí)行流的概念//設(shè)置預(yù)售票數(shù),共享資源!_tickets=20;//定義操作隊(duì)列NSOperationQueue*queue=[[NSOperationQueue

alloc]init];[queueaddOperationWithBlock:^{[self

operationSaleMethod:@"售票操作-1"];}];[queueaddOperationWithBlock:^{[self

operationSaleMethod:@"售票操作-2"];}];[queueaddOperationWithBlock:^{[self

operationSaleMethod:@"售票操作-3"];}];//設(shè)置最大線程數(shù)量[queuesetMaxConcurrentOperationCount:2];NSOperation使用小結(jié)NSOperation中無需使用線程鎖除更新UI之外,對(duì)共享資源的爭奪也需放在主線程隊(duì)列之中將定義的操作添加至隊(duì)列之后,多線程便開始啟動(dòng)NSBlockOperation的使用相比NSInvocationOperation更加靈活、方便通過setMaxConcurrentOperationCount方法可以控制并發(fā)的最大線程數(shù)量GCDGCD是基于C語言的框架工作原理:讓程序平行排隊(duì)的特定任務(wù),根據(jù)可用的處理資源,安排它們?cè)谌魏慰捎玫奶幚砥魃蠄?zhí)行任務(wù)要執(zhí)行的任務(wù)可以是一個(gè)函數(shù)或者一個(gè)block底層是通過線程實(shí)現(xiàn)的,不過程序員可以不必關(guān)注實(shí)現(xiàn)的細(xì)節(jié)GCD中的FIFO隊(duì)列稱為dispatchqueue,可以保證先進(jìn)來的任務(wù)先得到執(zhí)行dispatch_

_notify可以實(shí)現(xiàn)監(jiān)聽一組任務(wù)是否完成,完成后得到通知dispatchqueue:Maindispatchqueue:是全局可用的隊(duì)列,用于在主線程上執(zhí)行任務(wù)Serial:同時(shí)只執(zhí)行一個(gè)任務(wù)Concurrent:可以并發(fā)地執(zhí)行多個(gè)任務(wù),但是執(zhí)行完成的順序是隨機(jī)的GCD使用流程1.獲取全局調(diào)度隊(duì)列2.創(chuàng)建調(diào)度群組3.向調(diào)度群組添加異步任務(wù),并指定執(zhí)行隊(duì)列4.接收群組調(diào)度完成通知,群組中所有任務(wù)完成后獲得通知GCD調(diào)度的方法while(YES){

if(_tickets>0){

//在主調(diào)度隊(duì)列更新界面

dispatch_async(dispatch_get_main_queue(),^{

NSString*str=[NSString

stringWithFormat:@"當(dāng)前票數(shù):%d,售票線程:%@",_tickets,gcdName];[self

appendTextView:str];

_tickets--;});

//模擬休息

if([gcdNameisEqualToString:@"售票GCD-1"]){[NSThread

sleepForTimeInterval:0.1f];}else{[NSThread

sleepForTimeInterval:0.2f];}}else{

break;}}GCD售票方法//設(shè)置預(yù)售票數(shù),共享資源!_tickets=20;//1.獲取默認(rèn)調(diào)度優(yōu)先級(jí)的全局調(diào)度隊(duì)列,第二個(gè)參數(shù)為今后拓展使用,目前始終

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論