
線程與多線程相關概念
進程
- 資源分配的最小獨立單元,進程是具有一定獨立功能的程序關于某個數(shù)據(jù)集合上的一次運行活動,進程是系統(tǒng)進行資源分配和調度的一個獨立單位
線程
- 進程下的一個分支,是進程的實體,是CPU調度和分派的基本單元,它是比進程更小的能獨立運行的基本單位,線程自己基本不擁有系統(tǒng)資源,只擁有一點在運行中必不可少的資源(程序計數(shù)器、一組寄存器、棧)顿乒,但是它可與同屬一個進程的其他線程共享進程所擁有的全部資源。
進程和線程的主要差別
- 在于它們是不同的操作系統(tǒng)資源管理方式铭拧。進程有獨立的地址空間,一個進程崩潰后恃锉,在保護模式下不會對其它進程產(chǎn)生影響,而線程只是一個進程中的不同執(zhí)行路徑呕臂。線程有自己的堆棧和局部變量破托,但線程之間沒有單獨的地址空間,一個線程死掉就等于整個進程死掉歧蒋,所以多進程的程序要比多線程的程序健壯土砂,但在進程切換時,耗費資源較大谜洽,效率要差一些萝映。
重要概念(非常非常重要,不能理解這些概念多線程這輩子也學不會)
任務:即操作阐虚,你想要干什么序臂,說白了就是一段代碼,在 GCD 中就是一個 Block
隊列:用于存放任務
同步和異步:同步異步概念面向的是任務实束。同步指第一個任務不執(zhí)行完奥秆,不會開始第二個,異步是不管第一個有沒有執(zhí)行完咸灿,都開始第二個构订。
串行和并行:串行并行概念面向的是隊列。串行是多個任務按一定順序執(zhí)行避矢,并行是多個任務同時執(zhí)行
iOS中隊列的種類有
- 串行隊列:隊列中的任務只會順序執(zhí)行
- 并行隊列: 隊列中的任務通常會并發(fā)執(zhí)行
- 主隊列:每一個應用程序對應唯一主隊列悼瘾,直接GET即可囊榜;在多線程開發(fā)中,使用主隊列更新UI
- 全局隊列:是系統(tǒng)的亥宿,直接拿過來(GET)用就可以卸勺;與并行隊列類似
iOS中常用的多線程技術
pthread "已被拋棄"
NSThread
NSOperation
GCD
NSThread
NSThread是OC語言面向對象的多線程方案。所以你可以直接操控線程對象箩绍,非常直觀和方便孔庭。但是,它的生命周期還是需要我們手動管理材蛛,所以這套方案只有在一些非常簡單的場景才會用
創(chuàng)建并自動啟動
[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:nil];```
- 獲取當前線程
```swift
[NSThread currentThread];```
- 獲取主線程
```swift
[NSThread mainThread];```
----
####GCD
- GCD(Grand Central Dispatch)是基于C語言開發(fā)的一套多線程開發(fā)機制圆到,也是目前蘋果官方推薦的多線程開發(fā)方法。它會自動合理地利用更多的CPU內核(比如雙核卑吭、四核)芽淡,最重要的是它會自動管理線程的生命周期(創(chuàng)建線程、調度任務豆赏、銷毀線程)挣菲,完全不需要我們管理,我們只需要告訴干什么就行掷邦。
####隊列
- 獲取主隊列
dispatch_queue_t queue = dispatch_get_main_queue();```
- 獲取全局并行隊列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);```
----
####創(chuàng)建隊列
- 創(chuàng)建串行隊列
dispatch_queue_t queue = dispatch_queue_create("testQueue", NULL);```
- 創(chuàng)建并行隊列
dispatch_queue_t queue = dispatch_queue_create("testQueue", DISPATCH_QUEUE_CONCURRENT);```
####任務
- 創(chuàng)建同步任務
dispatch_sync(queue1, ^{
});```
- 創(chuàng)建異步任務
dispatch_async(queue2, ^{
});```
----
####隊列組
- 隊列組可以將很多隊列添加到一個組里白胀,這樣做的好處是,當這個組里所有的任務都執(zhí)行完了抚岗,隊列組會通過一個方法通知我們
1或杠、創(chuàng)建隊列組
dispatch_group_t group = dispatch_group_create();
2、創(chuàng)建隊列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3宣蔚、使用隊列組的方法執(zhí)行任務
dispatch_group_async(group, queue, ^{
});
4向抢、當隊列組的方法全部執(zhí)行完后,會執(zhí)行
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
});```
線程死鎖
- 簡單的說胚委,就是在當前串行隊列中添加一個同步任務挟鸠,因為隊列是串行的只能一個一個的執(zhí)行任務,而同步任務會阻塞隊列亩冬,這樣必須等該同步任務執(zhí)行完才能執(zhí)行其他任務艘希,但是該同步任務又是其他任務的一部分,所以兩個任務互相等待一直阻塞隊列硅急,這就是線程死鎖枢冤。
NSOperation
NSOperation 是蘋果公司對 GCD 的封裝,完全面向對象铜秆,所以使用起來更好理解淹真。 大家可以看到 NSOperation 和 NSOperationQueue 分別對應 GCD 的 任務 和 隊列 。
任務
NSOperation 只是一個抽象類连茧,所以不能封裝任務核蘸。但它有 2 個子類用于封裝任務巍糯。分別是:NSInvocationOperation
和NSBlockOperation
。創(chuàng)建一個 Operation 后客扎,需要調用 start 方法來啟動任務祟峦,它會默認在當前隊列同步執(zhí)行。通過NSInvocationOperation創(chuàng)建任務
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];```
- 通過NSBlockOperation創(chuàng)建任務
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
}];```
- NSBlockOperation 還有一個方法:
addExecutionBlock:
徙鱼,通過這個方法可以給 Operation 添加多個執(zhí)行Block
宅楞。
隊列
獲取主隊列
NSOperationQueue *queue = [NSOperationQueue mainQueue];
創(chuàng)建其他隊列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
往隊列中添加任務
[queue addOperation:operation];
NSOperationQueue有一個屬性maxConcurrentOperationCount代表最大并發(fā)數(shù),用來設置最多可以讓多少個任務同時執(zhí)行袱吆。當設置為 1 的時候厌衙,就是串行隊列。```
----
####線程依賴
- NSOperation 有一個非常實用的功能绞绒,那就是添加依賴婶希。比如有 3 個任務:A: 從服務器上下載一張圖片,B:給這張圖片加個水印蓬衡,C:把圖片返回給服務器喻杈。
- 這時就可以用到依賴了
[operation2 addDependency:operation1];
[operation3 addDependency:operation2];
[queue addOperations:@[operation3, operation2, operation1] waitUntilFinished:NO];```
- 返回主線程的方法
NSThread
[self performSelectorOnMainThread:@selector(run) withObject:nil waitUntilDone:NO];
GCD
dispatch_async(dispatch_get_main_queue(), ^{
});```
####NSOperation
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
}];```
線程同步
所謂線程同步就是為了防止多個線程搶奪同一個資源造成的數(shù)據(jù)安全問題,所采取的一種措施狰晚。
互斥鎖 :給需要同步的代碼塊加一個互斥鎖筒饰,就可以保證每次只有一個線程訪問此代碼塊。
@synchronized(self) {
//需要執(zhí)行的代碼塊
}```
- 同步執(zhí)行 :我們可以把多個線程都要執(zhí)行此段代碼添加到同一個串行隊列壁晒,這樣就實現(xiàn)了線程同步的概念瓷们。