一、什麼是進程?ios
進程是指在系統中正在運行的一個應用程序。好比同時打開QQ、Xcode,系統就會分別啓動2個進程。截圖安全
二、什麼是線程?多線程
1)、一個進程要想執行任務,必須得有線程(每個進程至少要有一條線程)併發
2)、線程是進程的基本執行單元,一個進程(程序)的全部任務都在線程中執行異步
3)、一個線程中任務的執行是串行的。即若是要在1個線程中執行多個任務,那麼只能一個一個的按順序執行這些任務async
三、什麼是多線程?ide
1)、一個線程中能夠開啓多條線程,每條線程能夠並行執行不一樣的任務。好比同時開啓三條線程分別下載3個文件函數
2)、同一時間,CPU只能處理一條線程,只有一條線程在工做(執行)性能
3)、多線程併發(同時)執行,實際上是CPU快速的在多線程之間調度(切換)測試
4)、若是cpu調度線程的時間足夠快,就形成了多線程併發執行的假象
5)、若是線程很是很是多,那麼會發生什麼狀況呢?
可能致使cpu在N條線程之間調度,消耗大量的cpu資源,進而致使每條線程被調度執行的頻次會下降(線程的執行效率下降)
6)、多線程的優勢:能適當提升程序的執行效率;能適當提升資源利用率(cpu、內存利用率)
7)、多線程的缺點:
開啓線程須要佔用必定的內存空間(默認狀況下,主線程佔用1M,子線程佔用512KB),若是開啓大量的線程,會佔用大量的內存空間,下降程序的性能;
線程越多,cpu在調度線程上的開銷就越大;
程序設計更加複雜:好比線程之間的通訊、多線程的數據共享
四、什麼是主線程
1)、一個ios程序運行後,默認會開啓一條線程,稱爲」主線程「或」UI線程「
2)、主線程的做用:
顯示/刷新UI界面;
處理UI事件(好比點擊事件、滾動事件、拖拽事件等)
3)、主線程的使用注意:
別將比較耗時的操做放到主線程中;耗時操做會卡住主線程,嚴重影響UI的流暢度,給用戶一種」卡「的壞體驗;
因此通常將耗時操做放在子線程(後臺線程、非主線程)
五、ios中多線程的實現方案:
六、NSThread
1)一個NSThread對象就表明一條線程
2)建立、啓動線程:
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(testThread) object:nil];
[thread start];
3)、主線程相關用法:
+ (NSThread *)mainThread; //獲取主線程
- (BOOL)isMainThread; //是否爲主線程
+ (BOOL)isMainThread; //是否爲主線程
4)、獲取當前線程: NSThread *current = [NSThread currentThread];
5)、線程的調度優先級
+ (double)threadPriority;
+ (BOOL)setThreadPriority:(double)p;
- (double)threadPriority;
- (BOOL)setThreadPriority:(double)p;
調度優先級的取值範圍是0.0 ~ 1.0, 默認是0.5, 值越大,優先級越高
6)、線程的名字:- (void)setName: (NSString *)n; - (NSString *)name;
7)、另一種建立線程方法:建立線程後啓動線程:
[NSThread detachNewThreadSelector:@selector(testThread) toTarget:self withObject:nil];
8)、第三種建立線程方式:隱式建立並啓動線程:
[self performSelectorInBackground:@selector(testThread) withObject:nil];
9) 、後面2中建立線程方式的優缺點:
優勢:簡單快捷
缺點:沒法對線程進行更詳細的設置
10)、阻塞(暫停)線程:
+ (void)sleepUnitilDate:(NSDate *)date; //睡眠到date這個時間上
+ (void)sleepForTimeInterval:(NSTimeInterval)seconds; //睡眠seconds秒
調用這兩個方法中任一方法,當前線程會睡眠(暫停)所設置的時間後,纔會執行後面的操做
11)、強制中止線程,讓當前線程提早結束它的生命:+ (void)exit;
七、多線程安全問題 - 互斥鎖
1)、互斥鎖使用方式:@synchronized(所對象) { //須要鎖定的代碼 } ; // 線程同步:多條線程按順序地執行任務
2)、互斥鎖的優缺點:
優勢:能有效防止因多線程搶奪同一資源形成的數據安全問題;
缺點:須要消耗大量的CPU資源
八、原子和非原子屬性
OC在定義屬性時有nonatomic和atomic兩種選擇
atomic : 院子屬性,爲setter方法加鎖(默認就是atomic)
nonatomic:非原子屬性,不會位setter方法加鎖
---------------- nontomic 和 atomic對比 -------
atomic :線程安全,須要消耗大量的資源;
nonatomic : 非線程安全,適合內存曉得移動設備
------ 對於設置屬性原子和非原子性的建議 ---
a、全部屬性都聲明位nontomic;
b、儘可能避免多線程搶奪同一塊資源;
c、儘可能將加鎖、資源搶奪的業務邏輯交給服務端處理,減少移動客戶端的壓力。
九、線程間通訊
在1個線程中,線程每每不是孤立存在的,多個線程之間須要常常進行通訊:好比說一個線程傳遞數據給另外一個線程,又或者在一個線程中執行完成特定任務後,轉到另外一個線程繼續執行任務。
線程間通訊經常使用方法:
- (void)performSelectorOnMainThread:(SEL)aSelectorWithObject:(id)arg waitUntilDone:(BOOL)wait; //傳遞數據到主線程
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait; //傳遞數據到另外一個線程
十、GCD
1)、GCD,全稱是Grand Central Dispatch,偉大的中央調度器。純C語言,提供了很是多強大的函數
2)、GCD的優點:
GCD是蘋果公司位多核的並行運算提出的解決方案;會自動利用更多的CPU內核;
會自動管理線程的生命週期(建立線程、調度任務、銷燬線程)
3)、GCD中2個核心概念:任務和隊列。任務指執行什麼操做,隊列是用來存聽任務。
GCD的使用步驟:
a、定製任務。肯定想作的事;
b、將任務添加到隊列中。GCD會自動將隊列中的任務取出,放到對應的線程中執行 ;任務的取出遵循隊列的FIFO原則:先進先出。
GCD執行任務函數:
用同步的方式執行任務:dispatch_sync(dispatch_queue_t queue, dispatch_block_t block); // queue指隊列 ; block指任務
用異步的方式執行任務:dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
同步和異步的區別:同步只能在當前的線程中執行任務,不具有開啓新線程的能力; 異步能夠在新的線程中執行任務,具有開啓新線程的能力;
4)、隊列的類型:主要分爲併發隊列和串行隊列
併發隊列:Concurrent Dispatch Queue, 可讓多個任務併發(同時)執行(自動開啓多個線程同時執行任務);
併發功能只有在異步(dispatch_async)函數下才有效
串行隊列:Serial Dispatch Queue, 讓任務一個接着一個地執行(一個任務執行完畢後,再執行下一個任務)
並行隊列:
GCD默認已經提供了全局的併發隊列,供整個應用使用,不須要手動建立;
使用dispatch_get_global_queue函數得到全局的併發隊列;
dispatch_queue_t dispatch_get_global_queue(dispatch_queue_priority_t priority, unsigned long flags); //priority指隊列的優先級, flags參數暫時無用,用0便可
示例:dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //得到全局併發隊列
全局併發隊列的優先級:
#define DISPATCH_QUEUE_PRIORITY_HIGH 2//高
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0//默認(中)
#define DISPATCH_QUEUE_PRIORITY_LOW (-2) //低
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN //後臺
串行隊列:
使用dispatch_queue_create函數建立一個串行隊列
dispatch_queue_create(const char *lable, dispatch_queue_attr_t attr); //lable參數指隊列名稱;attr參數指隊列屬性,通常用NULL便可
另外可使用主隊列:dispatch_get_main_queue(),主隊列是GCD自帶的一種特殊的串行隊列;放在主隊列中的任務,都會放到主線程中執行
-----------------------------------------------------
線程和隊列、異步同步函數的關係?
一、一個應用程序表示開啓了一個進程
二、一個進程至少有一個線程,即至少有一個主線程,也能夠開啓多條線程
三、一個線程中能夠有多個隊列,每一個隊列中能夠執行多個任務
四、在線程中執行任務的順序能夠是按順序來執行,也能夠用不按順序來執行。即表現爲串行和並行
五、那異步和同步函數的做用在哪裏?
是否開啓多條線程,而後執行的隊列(任務)是否按順序仍是不按順序執行,都須要異步和同步函數的配合才能實現!
並行和串行隊列,與異步同步函數的排列組合有以下這些:
a、並行隊列 + 異步函數 開啓多條線程,不按順序執行任務;
b、串行隊列 + 異步函數 開啓一條新線程,按順序執行任務;
c、主隊列 + 異步函數不開啓新線程,按順序執行任務
d、並行隊列 + 同步函數不開啓新線程,按順序執行任務;
e、串行隊列 + 同步函數不開啓新線程,按順序執行任務;
f、主隊列 + 同步函數會出現卡死現象!緣由:循環等待,主隊列的東西要等主線程執行完,又不能開線程,
因此下面的任務要等上面的任務執行完,而後卡死
舉例說明:
1、並行隊列 + 異步函數:開啓多條線程,不按順序執行任務 (全局隊列+異步函數效果同樣)
dispatch_queue_t q1 = dispatch_queue_create("mulQueue", DISPATCH_QUEUE_CONCURRENT); for (int i = 0; i < 100; i++){ dispatch_async(q1, ^{ NSLog(@"並行+異步,i=%d, currentThread: %@", i, [NSThread currentThread]); }); } NSLog(@"並行隊列+異步函數測試執行 end...."); /* 並行隊列+異步函數測試執行 end.... 並行+異步,i=1, currentThread: <NSThread: 0x60000026ab80>{number = 5, name = (null)} 並行+異步,i=0, currentThread: <NSThread: 0x600000269b00>{number = 3, name = (null)} 並行+異步,i=4, currentThread: <NSThread: 0x60000026ea80>{number = 7, name = (null)} 並行+異步,i=3, currentThread: <NSThread: 0x600000269bc0>{number = 6, name = (null)} 並行+異步,i=5, currentThread: <NSThread: 0x60800026d8c0>{number = 8, name = (null)} .... 並行+異步,i=97, currentThread: <NSThread: 0x600000272f80>{number = 49, name = (null)} 並行+異步,i=99, currentThread: <NSThread: 0x600000273000>{number = 50, name = (null)} 並行+異步,i=98, currentThread: <NSThread: 0x60000026ad40>{number = 11, name = (null)} */
2、並行 + 同步:不開啓線程,按順序執行,在主線程執行
dispatch_queue_t q2 = dispatch_queue_create("mulQueue", DISPATCH_QUEUE_CONCURRENT); for (int i = 0; i < 100; i++){ dispatch_sync(q2, ^{ NSLog(@"並行+同步,i=%d, currentThread: %@", i, [NSThread currentThread]); }); } NSLog(@"並行隊列+同步函數測試執行 end...."); /* 並行+同步,i=0, currentThread: <NSThread: 0x608000079040>{number = 1, name = main} 並行+同步,i=1, currentThread: <NSThread: 0x608000079040>{number = 1, name = main} 並行+同步,i=2, currentThread: <NSThread: 0x608000079040>{number = 1, name = main} .... 並行+同步,i=97, currentThread: <NSThread: 0x608000079040>{number = 1, name = main} 並行+同步,i=98, currentThread: <NSThread: 0x608000079040>{number = 1, name = main} 並行+同步,i=99, currentThread: <NSThread: 0x608000079040>{number = 1, name = main} 並行隊列+同步函數測試執行 end.... */
3、串行 + 異步:開啓一條新線程,按順序執行
dispatch_queue_t q3 = dispatch_queue_create("singleQueue", NULL); for (int i = 0; i < 100; i++){ dispatch_async(q3, ^{ NSLog(@"串行+異步,i=%d, currentThread: %@", i, [NSThread currentThread]); }); } NSLog(@"串行隊列+異步函數測試執行 end....: %@", [NSThread currentThread]); /* 串行+異步,i=0, currentThread: <NSThread: 0x60000007f240>{number = 3, name = (null)} 串行隊列+異步函數測試執行 end....: <NSThread: 0x60800007b800>{number = 1, name = main} 串行+異步,i=1, currentThread: <NSThread: 0x60000007f240>{number = 3, name = (null)} 串行+異步,i=2, currentThread: <NSThread: 0x60000007f240>{number = 3, name = (null)} .... 串行+異步,i=97, currentThread: <NSThread: 0x60000007f240>{number = 3, name = (null)} 串行+異步,i=98, currentThread: <NSThread: 0x60000007f240>{number = 3, name = (null)} 串行+異步,i=99, currentThread: <NSThread: 0x60000007f240>{number = 3, name = (null)} */
4、主隊列 + 異步:不開啓新線程,按順序執行
dispatch_queue_t q4 = dispatch_get_main_queue(); for (int i = 0; i < 100; i++){ dispatch_async(q4, ^{ NSLog(@"主隊列+異步,i=%d, currentThread: %@", i, [NSThread currentThread]); }); } NSLog(@"主隊列+異步函數測試執行 end....: %@", [NSThread currentThread]); /* 主隊列+異步函數測試執行 end....: <NSThread: 0x60000006fe00>{number = 1, name = main} 主隊列+異步,i=0, currentThread: <NSThread: 0x60000006fe00>{number = 1, name = main} 主隊列+異步,i=1, currentThread: <NSThread: 0x60000006fe00>{number = 1, name = main} 主隊列+異步,i=2, currentThread: <NSThread: 0x60000006fe00>{number = 1, name = main} .... 主隊列+異步,i=97, currentThread: <NSThread: 0x60000006fe00>{number = 1, name = main} 主隊列+異步,i=98, currentThread: <NSThread: 0x60000006fe00>{number = 1, name = main} 主隊列+異步,i=99, currentThread: <NSThread: 0x60000006fe00>{number = 1, name = main} */