首先了解單線程:
一、單線程的應用,整個應用中只有一個順序執行流,
當執行流在執行某個耗時的操作,或者不能立即完成的任務時(比如網絡通信、復雜的運行)該執行流就會被阻塞,整個應用就會卡在那里無法繼續執行,因此單線程的程序功能往往是非常有限的.
我們可以這樣理解,單線程程序如同只雇傭一個服務員的餐廳,他必須做完一件事情后才能做下一件的事情,多線程程序則如同雇用多個服務員的餐廳,他們可以同時進行多件事情。
二、線程和進程
所有運行中的任務通常對應一個進程Process (pr??s?s?),當一個程序進入內存運行后即變成了一個進程,進程是系統進行資源分配和調度的一個獨立單位.當一個進程運行時,內部可能包含多個順序執行流,每個順序執行流就是一個線程.
一般而言進程包括如下三個特征:
1、獨立性:進程是系統中的獨立存在的實體,有自己獨立的資源,每一個進程都有自己的私有地址空間,沒有允許,其它用戶進程不可以直接訪問其它的進程空間。
2、動態性:進程與程序的區別在于,程序只是一個靜態的指令集合,而進程是一個正在系統中活動的指令集合,在進程中加入了時間的概念,進程具有自己的生命周期和各種不同的狀態,這些概念在程序中都是不具備的。
3、并發性:多個進程可以在單個處理器上并發執行。
4、并發性(concurrency k?n?k?r(?)ns)和 并行性(parallel ?par?l?l ) 是兩個概念,
4.1、并發性:指在同一時刻只能有一條指令執行,但多個進程指定被快速輪換執行,使得在宏觀上具有多個進程同時執行的效果。大部分操作系統都支持多線程并發運行,例如:一邊寫程序一邊查看手冊同時播放音樂等等……這些進程看上去像是在同時工作。對于一個CPU,它在某個時間點上只能執行一個程序,只能運行一個進程,CPU不斷的在這些進程之間輪換執行,
4.2、并行性:指在同一時刻有多少指令在多個處理器上同時執行。
三、多線程和多進程
多線程則擴展了多進程的概念,使得同一個進程可以同時并發處理多個任務,
線程(Thread θr?d )也被稱作輕量級進程(Lightweight Process)
線程是進程的執行單元,線程在程序中是獨立的、并發的執行流。
當進程被初始化后,主線程就被創建了,對于絕大多數的應用程序來說,通常僅要求有一個主線程,但我們可以在該程序內創建多條順序執行流,這些順序執行流就是線程 每條線程也是相互獨立的。
操作系統可以同時執行多個任務,每個任務就是進程;進程可以同時執行多個任務,每個任務就是線程。一個程序運行后至少有一個進程,一個進程里可以有多個線程,但至少要包含一個線程。也就是說一個線程必須有一個父進程,線程是進程的組成部分,
線程可以擁有自己的堆棧,自己的程序計數器和自己的局部變量,但不再擁有系統資源。線程是獨立運行的,線程的執行是搶占式的。也就是說當前運行的線程在任何時候都可能被掛起,以方便另外一個線程可以運行。一個線程可以創建和撤銷另一個線程,線程的調度和管理有進程本身負責完成。
四、多線程
1、為什么要用多線程?
答: 每個iOS 應用程序都有專門的自己的用來更新顯示UI界面或處理用戶的觸摸事件的-主線程,因此不能將其他太耗時的操作放在主線程中去執行,不然會造成主線程堵塞(出現卡機的現象),帶來極壞的用戶體驗。
So 一般的解決方案就是將那些耗時的操作放到另外一個線程中去執行,
So 多線程編程是防止主線程堵塞,增加運行效率等等的最佳方法。而原始的多線程方法存在很多的毛病,包括線程鎖死等。
例如: 用戶上的某個按鈕,該按鈕需要執行的任務需要幾秒甚至幾十秒,如果直接在UI線程中完成這個任務,這個任務執行完成、返回之前,UI線程被該任務阻塞,無法響應用戶的其他操作--在這個時間內,用戶的iOS操作系統的操作將不會有任何反應(除非用戶單擊home鍵返回)這不是用戶希望的結果,最好的做法是:將任何耗時的任務,(比如復雜的運算、從網絡下載數據等操作)都放在非UI線程中完成,這樣UI線程就不會被阻塞,IOS應用也不會失去響應。
2、多線程是什么?
答: 多線程是個復雜的概念,按字面意思是同步完成多項任務,提高了資源的使用效率,
1>從硬件、操作系統、應用軟件不同的角度去看,多線程被賦予不同的內涵,對于硬件,現在市面上多數的CPU都是多核的,多核的CPU運算多線程更為出色;
2>從操作系統角度,是多任務,現在用的主流操作系統都是多任務的,可以一邊聽歌、一邊寫博客;
對于應用來說,多線程可以讓應用有更快的回應,可以在網絡下載時,同時響應用戶的觸摸操作。
3>在iOS應用中,對多線程最初的理解,就是并發,它的含義是原來先做燒水,再摘菜,再炒菜的工作,會變成燒水的同時去摘菜,最后去炒菜。
3、 多線程的底層實現?
1> 首先搞清楚什么是線程、什么是多線程?
2> Mach是第一個以多線程方式處理任務的系統,因此多線程的底層實現機制是基于Mach的線程
3> 開發中很少用Mach級的線程,因為Mach級的線程沒有提供多線程的基本特征,線程之間是獨立的
4> 開發中實現多線程的方案
4.1 C語言的POSIX接口:#include <pthread.h>
4.2 OC的NSThread
4.3 C語言的GCD接口(性能最好,代碼更精簡)
4.4 OC的NSOperation和NSOperationQueue(基于GCD)
五、iOS中有哪些多線程編程?
iOS中的多線程,是Cocoa框架下的多線程,通過Cocoa的封裝,可以讓我們更為方便的使用線程,做過C++的同學可能會對線程有更多的理解,比如線程的創立,信號量、共享變量有認識,Cocoa框架下會方便很多,它對線程做了封裝,有些封裝,可以讓我們創建的對象,本身便擁有線程,也就是線程的對象化抽象,從而減少我們的工程,提供程序的健壯性。
iOS支持-多個-層次的-多線程編程,提供了如下三種多線程編程的技術:
1.NSThread 每個 NSThread對象 對應一個線程,量級較輕(真正的多線程)
2.以下兩點是蘋果專門開發的“并發”技術,使得程序員可以不再去關心線程的具體使用問題
1> NSOperation/NSOperationQueue 面向對象的線程技術
2> GCD —— Grand Central Dispatch(派發) 是基于C語言的框架,可以充分利用多核,是蘋果推薦使用的多線程技術
//使用NSThread實現多線程,(θr?d )
//使用NSOperation與 NSOperationQueue 實現多線程
//使用GCD實現多線程(Grand Central Dispatch)
以上這三種編程方式從上到下,抽象度層次是從低到高的,抽象度越高的使用越簡單,也是Apple最推薦使用的,在項目中很多框架技術分別使用了不同多線程技術。
六、三種多線程技術的對比
- NSThread:
–優點:NSThread比其他兩種多線程方案較輕量級,更直觀地控制線程對象(θred )
–缺點:需要自己管理線程的生命周期、線程同步、加鎖、睡眠以及喚醒等。線程同步對數據的加鎖會導致一定的性能開銷
2.NSOperation:
–NSOperation是面向對象的 (Cocoa Operations 是基于OC實現的)
NSOperation 是以-面向對象-的方式-封裝了-需要執行的操作,–不需要關心線程管理,數據同步的事情,可以把精力放在自己需要執行的操作上
NSOperation是一個抽象基類,iOS提供了兩種默認實現:
NSInvocationOperation (?nv??ke??n) 和 NSBlockOperation,當然也可以自定義NSOperation
3.GCD:
-Grand Central Dispatch (gr?nd sentr?l d??sp?t? 簡稱GCD,iOS4.0+才能使用,基于C語言的)
–GCD是由蘋果開發的一個多核編程的解決方案。是替代NSThread, NSOperation的高效和強大的技術 提供了一些新特性、運行庫來支持多核并行編程-,它的關注點更高:如何在多個cpu上提升效率
GCD從系統級別提供的一個易用的多線程類庫,具有運行時的特點,能充分利用多核心硬件。
GCD的API接口為C語言的函數,函數參數中多數有Block,關于Block的使用為我們提供強大的“接口”
七、一般的面試問題:
- 線程間怎么通信?
1> performSelector:onThread:withObject:waitUntilDone:
2> NSMachPort
- 網絡圖片處理問題中怎么解決一個相同的網絡地址重復請求的問題?
利用字典(圖片地址為key,下載操作為value)
- 談談多線程安全的幾種解決辦法及多線程安全怎么控制?
1> 只在主線程刷新訪問UI
2> 如果要防止資源搶奪,得用@synchronized [?s??kr??na?zd]進行加鎖保護
3> 如果異步操作要保證線程安全等問題,盡量使用GCD(有些函數默認就是安全的) 《你可以看一下之前的文章單例的創建,采用GCD的方式創建的》- 你用過NSOperationQueue么?為什么要使用NSOperationQueue,實現了什么? 以及描述它和GCD的區別和類似的地方?(提示:可以從兩者的實現機制和適用范圍來描述)。
1> GCD是純C語言的API,NSOperationQueue是基于GCD的OC版本封裝
2> GCD只支持FIFO的隊列,NSOperationQueue可以很方便地調整執行順序、設置最大并發數量
3> NSOperationQueue可以在輕松在Operation間設置依賴關系,而GCD需要寫很多的代碼才能實現
4> NSOperationQueue支持KVO,可以監測operation是否正在執行(isExecuted)、是否結束(isFinished),是否取消(isCanceld)
5> GCD的執行速度比NSOperationQueue快
任務之間不太互相依賴使用:GCD
任務之間有依賴\或者要監聽任務的執行情況使用:NSOperationQueue
- 在使用GCD以及block時要注意些什么?它們兩是一回事兒么?block在ARC中和傳統的MRC中的行為和用法有沒有什么區別,需要注意些什么?
Block的使用注意:
1> block的內存管理
2> 防止循環retian
λ 非ARC(MRC):__block
λ ARC:__weak__unsafe_unretained
使用block是要注意,若將block做函數參數時,需要把它放到最后,GCD是Grand Central Dispatch,是一個對線程開源類庫,而Block是閉包,是能夠讀取其他函數內部變量的函數。
6.在異步線程中下載很多圖片,如果失敗了,該如何處理?請結合RunLoop來談談解決方案.(提示:在異步線程中啟動一個RunLoop重新發送網絡請求,下載圖片)
1> 重新下載圖片
2> 下載完畢, 利用RunLoop的輸入源回到主線程刷新UIImageVIUew
7.在項目什么時候選擇使用GCD,什么時候選擇NSOperation?
使用NSOperationQueue用來管理子類化的NSOperation對象,控制其線程并發數目。GCD和NSOperation都可以實現對線程的管理,區別是 NSOperation和NSOperationQueue是多線程的面向對象抽象。
項目中使用NSOperation的優點是: NSOperation是對線程的高度抽象,在項目中使用它,會使項目的程序結構更好,子類化NSOperation的設計思路,是具有面向對象的優點(復用、封裝),使得實現是多線程支持,而接口簡單,建議在復雜項目中使用。
項目中使用GCD的優點是GCD本身非常簡單、易用,對于不復雜的多線程操作,會節省代碼量,而Block參數的使用,會是代碼更為易讀,建議在簡單項目中使用
8、您是否做過異步的網絡處理和通訊方面的工作?如果有,能具體介紹一些實現策略么?
使用NSOperation發送異步網絡請求,使用NSOperationQueue管理線程數目及優先級,底層是用NSURLSession
9、OC中有線程池(線程隊例)嗎?NSOperationQueue是如何管理線程的:
1>、NSPOperationQueue是OC中的線程池,線程可以存放多個線程
2>、NSPOperationQueue可以管理線程的并發數,還可以管理線程之間的優先級。