iOS | 面試知識整理 - 多執行緒 (六)
前言:
最近公司專案不怎麼忙,閒暇時間把iOS 在面試中可能會遇到的問題整理了一番,一部分題目是自己面試遇到的,一部分題目則是網上收錄的,方便自己鞏固複習,也分享給大家! 知識點比較多,比較雜,這裡做了分類,下面是分類連結地址;
面試知識點整理 - 目錄:
iOS | 面試知識整理 - OC基礎 (一)
iOS | 面試知識整理 - OC基礎 (二)
iOS | 面試知識整理 - OC基礎 (三)
iOS | 面試知識整理 - UI 相 關 (四)
iOS | 面試知識整理 - 記憶體管理 (五)
iOS | 面試知識整理 - 多 線 程 (六)
iOS | 面試知識整理 - 網路相關 (七)
iOS | 面試知識整理 - 資料持久化 (八)
iOS | 面試知識整理 - Swift 基礎 (九)
iOS | 面試知識整理 - 多 線 程 (六)
1.什麼是多執行緒?
-
多執行緒
是指實現多個執行緒併發執行的技術,進而提升整體處理效能。 - 同一時間,CPU 只能處理一條執行緒,多執行緒併發執行,其實是 CPU 快速的在多條執行緒之間排程(切換)如果 CPU 排程執行緒的時間足夠快,就造成了多執行緒併發執行的假象
- 主執行緒的棧區 空間大小為1M,非常非常寶貴
- 子執行緒的棧區 空間大小為512K記憶體空間
- 優勢
充分發揮多核處理器的優勢,將不同執行緒任務分配給不同的處理器,真正進入“平行計算”狀態 - 弊端
新執行緒會消耗記憶體控制元件和cpu時間,執行緒太多會降低系統執行效能。
2.程序和執行緒區別?
- 程序:正在執行的程式,負責程式的記憶體分配,每一個程序都有自己獨立的虛擬記憶體空間。(一個程式執行的動態過程)
- 執行緒:執行緒是程序中一個獨立執行的路徑(控制單元)一個程序至少包含一條執行緒,即主執行緒可以將耗時的執行路徑(如網路請求)放在其他執行緒中執行。
- 程序和執行緒的比較
- 執行緒是 CPU 呼叫的最小單位
- 程序是 CPU 分配資源和排程的單位
- 一個程式可以對應多個程序,一個程序中可有多個執行緒,但至少要有一條執行緒,
- 同一個程序內的執行緒共享程序資源
3.執行緒間怎麼通訊?
- 執行緒間的通訊體現: 一個執行緒傳遞資料給另一個執行緒,
- 在一個執行緒中執行完特定的任務後,轉到另一個執行緒繼續執行任務。
4.iOS的多執行緒方案有哪幾種?
5. 什麼是GCD?
GCD(Grand Central Dispatch)
,又叫做大中央排程,它對執行緒操作進行了封裝,加入了很多新的特性,內部進行了效率優化,提供了簡潔的C語言介面
,使用更加高效,也是蘋果推薦的使用方式.
6.GCD 的佇列型別?
GCD的佇列可以分為2大型別
併發佇列(
Concurrent Dispatch Queue
)
可以讓多個任務併發(同時)執行(自動開啟多個執行緒同時執行任務)
併發功能只有在非同步(dispatch_async
)函式下才有效序列佇列(
Serial Dispatch Queue
)
讓任務一個接著一個地執行(一個任務執行完畢後,再執行下一個任務),按照FIFO順序執行.
7.什麼是同步和非同步任務派發(synchronous和asynchronous)?
GCD多執行緒經常會使用 dispatch_sync
和dispatch_async
函式向指定佇列新增任務,分別是同步和非同步
- 同步指阻塞當前執行緒,既要等待新增的耗時任務塊Block完成後,函式才能返回,後面的程式碼才能繼續執行
- 非同步指將任務新增到佇列後,函式立即返回,後面的程式碼不用等待新增的任務完成後即可執行,非同步提交無法確定任務執行順序
8.dispatch_after使用?
通過該函式可以讓提交的任務在指定時間後開始執行,也就是延遲執行;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)(10 * NSEC_PER_SEC)),dispatch_get_main_queue(),^{
NSLog(@"10秒後開始執行")
});
複製程式碼
9.dispatch_group_t (組排程)的使用?
組排程可以實現等待一組操都作完成後執行後續任務.
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{
//請求1
});
dispatch_group_async(group,^{
//請求2
});
dispatch_group_async(group,^{
//請求3
});
dispatch_group_notify(group,^{
//介面重新整理
NSLog(@"任務均完成,重新整理介面");
});
複製程式碼
10.dispatch_semaphore (訊號量)如何使用?
- 用於控制最大併發數
- 可以防止資源搶奪
與他相關的共有三個函式,分別是
dispatch_semaphore_create, // 建立最大併發數
dispatch_semaphore_wait。 // -1 開始執行 (0則等待)
dispatch_semaphore_signal, // +1
複製程式碼
11.什麼是NSOperation?
NSOperation是基於GCD的上封裝,將執行緒封裝成要執行的操作,不需要管理執行緒的生命週期和同步,比GCD可控性更強
例如:
可以加入操作依賴控制執行順序,設定操作佇列最大併發數,取消操作等
12. NSOperation如何實現操作依賴?
通過任務間新增依賴,可以為任務設定執行的先後順序。接下來通過一個案例來展示設定依賴的效果。
NSOperationQueue *queue=[[NSOperationQueue alloc] init];
//建立操作
NSBlockOperation *operation1=[NSBlockOperation blockOperationWithBlock:^(){
NSLog(@"執行第1次操作,執行緒:%@",[NSThread currentThread]);
}];
NSBlockOperation *operation2=[NSBlockOperation blockOperationWithBlock:^(){
NSLog(@"執行第2次操作,執行緒:%@",[NSThread currentThread]);
}];
NSBlockOperation *operation3=[NSBlockOperation blockOperationWithBlock:^(){
NSLog(@"執行第3次操作,執行緒:%@",[NSThread currentThread]);
}];
//新增依賴
[operation1 addDependency:operation2];
[operation2 addDependency:operation3];
//將操作新增到佇列中去
[queue addOperation:operation1];
[queue addOperation:operation2];
[queue addOperation:operation3];
複製程式碼
13.是否可以把比較耗時的操作放在 NSNotification中?
- 如果在非同步執行緒發的通知,那麼可以執行比較耗時的操作;
- 如果在主執行緒發的通知,那麼就不可以執行比較耗時的操作
14.說幾個你在工作中使用到的執行緒安全的例子?
- UIKit(必須在主執行緒)
- FMDBDataBaseQueue(序列佇列)
- 等等..
15.dispatch_barrier_(a)sync使用?
- 一個dispatch barrier 允許在一個併發佇列中建立一個同步點。當在併發佇列中遇到一個barrier,他會延遲執行barrier的block,等待所有在barrier之前提交的blocks執行結束。 這時,barrier block自己開始執行。 之後, 佇列繼續正常的執行操作。
16. dispatch_set_target_queue 使用?
dispatch_set_target_queue(dispatch_object_t object,dispatch_queue_t queue);
複製程式碼
dispatch_set_target_queue 函式有兩個作用:第一,變更佇列的執行優先順序;第二,目標佇列可以成為原佇列的執行階層。
- 第一個引數是要執行變更的佇列(不能指定主佇列和全域性佇列)
- 第二個引數是目標佇列(指定全域性佇列)
主執行緒是相對於什麼而言的
17.在專案什麼時候選擇使用 GCD,什麼時候選 擇 NSOperation?
- 專案中使用 NSOperation 的優點是 NSOperation 是對執行緒的高度抽象,在專案中使 用它,會使專案的程式結構更好,子類化 NSOperation 的設計思路,是具有面向對 象的優點(複用、封裝),使得實現是多執行緒支援,而介面簡單,建議在複雜專案中 使用。
- 專案中使用 GCD 的優點是 GCD 本身非常簡單、易用,對於不復雜的多執行緒操 作,會節省程式碼量,而 Block 引數的使用,會是程式碼更為易讀,建議在簡單專案中 使用。
18.說一下 OperationQueue 和 GCD 的區別,以及各自的優勢
- GCD是純C語⾔言的API,NSOperationQueue是基於GCD的OC版本封裝
- GCD只⽀支援FIFO的佇列列,NSOperationQueue可以很⽅方便便地調整執⾏行行順 序、設 置最⼤大併發數量量
- NSOperationQueue可以在輕鬆在Operation間設定依賴關係,⽽而GCD 需要寫很 多的程式碼才能實現
- NSOperationQueue⽀支援KVO,可以監測operation是否正在執⾏行行 (isExecuted)、 是否結束(isFinished),是否取消(isCanceld)
- GCD的執⾏行行速度⽐比NSOperationQueue快 任務之間不不太互相依賴:GCD 任務之間 有依賴\或者要監聽任務的執⾏行行情況:NSOperationQueue
19.GCD如何取消執行緒?
GCD目前有兩種方式可以取消執行緒:
1.dispatch_block_cancel
類似NSOperation一樣,可以取消還未執行的執行緒。但是沒辦法做到取消一個正在執行的執行緒。
dispatch_queue_t queue = dispatch_get_global_queue(0,0);
dispatch_block_t block1 = dispatch_block_create(0,^{
NSLog(@"block1");
});
dispatch_block_t block2 = dispatch_block_create(0,^{
NSLog(@"block2");
});
dispatch_block_t block3 = dispatch_block_create(0,^{
NSLog(@"block3");
});
dispatch_async(queue,block1);
dispatch_async(queue,block2);
dispatch_async(queue,block3);
dispatch_block_cancel(block3); // 取消 block3
複製程式碼
2.使用臨時變數+return
方式取消 正在執行的Block
__block BOOL gcdFlag= NO; // 臨時變數
dispatch_async(dispatch_get_global_queue(0,^{
for (long i=0; i<1000; i++) {
NSLog(@"正在執行第i次:%ld",i);
sleep(1);
if (gcdFlag==YES) { // 判斷並終止
NSLog(@"終止");
return ;
}
};
});
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,^{
NSLog(@"我要停止啦");
gcdFlag = YES;
});
複製程式碼
20.NSOperation取消執行緒方式?
1.通過 cancel 取消未執行的單個操作
NSOperationQueue *queue1 = [[NSOperationQueue alloc]init];
NSBlockOperation *block1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"block11");
}];
NSBlockOperation *block2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"block22");
}];
NSBlockOperation *block3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"block33");
}];
[block3 cancel];
[queue1 addOperations:@[block1,block2,block3] waitUntilFinished:YES];
複製程式碼
2.移除佇列裡面所有的操作,但正在執行的操作無法移除
[queue1 cancelAllOperations];
複製程式碼
3.掛起佇列,使佇列任務不再執行,但正在執行的操作無法掛起
queue1.suspended = YES;
複製程式碼
4.我們可以自定義NSOperation,實現取消正在執行的操作。其實就是攔截main方法。
main方法:
1、任何操作在執行時,首先會呼叫start方法,start方法會更新操作的狀態(過濾操作,如過濾掉處於“取消”狀態的操作)。
2、經start方法過濾後,只有正常可執行的操作,就會呼叫main方法。
3、重寫操作的入口方法(main),就可以在這個方法裡面指定操作執行的任務。
4、main方法預設是在子執行緒非同步執行的。
複製程式碼
21. 什麼是執行緒安全?
- 1塊資源可能會被多個執行緒共享,也就是多個執行緒可能會訪問同一塊資源
- 比如多個執行緒訪問同一個物件、同一個變數、同一個檔案
- 當多個執行緒訪問同一塊資源時,很容易引發資料錯亂和資料安全問題
22.執行緒安全的處理手段有哪些?
- 加鎖
- 同步執行
23.如何理解GCD死鎖?
- 所謂死鎖.通常是指2個操作相互等待對方完成,造成死迴圈,於是2個操作都無法進行,就產生了死鎖;
24.自旋鎖和互斥鎖的是什麼?
- 自旋鎖會忙等: 所謂忙等,即在訪問被鎖資源時,呼叫者執行緒不會休眠,而是不停迴圈在那裡,直到被鎖資源釋放鎖。
- 互斥鎖會休眠: 所謂休眠,即在訪問被鎖資源時,呼叫者執行緒會休眠,此時cpu可以排程其他執行緒工作。直到被鎖資源釋放鎖。此時會喚醒休眠執行緒。
25.OC你瞭解的鎖有哪些?
- os_unfair_lock ios10 開始
- OSSpanLock ios10 廢棄
- dispatch_semaphore 建議使用,效能也比較好
- dispatch_mutex
- dispatch_queue 序列
- NSLock 對 mutex 封裝
- @synchronized 效能最差
26:自旋和互斥什麼情況下使用?
什麼情況使用自旋鎖比較划算?
- 預計執行緒等待鎖的時間很短
- 加鎖的程式碼(臨界區)經常被呼叫,但競爭情況很少發生
- CPU資源不緊張
- 多核處理器
什麼情況使用互斥鎖比較划算?
- 預計執行緒等待鎖的時間較長
- 單核處理器
- 臨界區有IO操作
- 臨界區程式碼複雜或者迴圈量大
- 臨界區競爭非常激烈
27.程式碼分析一,此函式耗時? 輸出結果
dispatch_queue_t queue = dispatch_queue_create("test",nil);
dispatch_async(queue,^{
NSLog(@"1");
sleep(1);
});
dispatch_async(queue,^{
NSLog(@"2");
sleep(1);
});
dispatch_sync(queue,^{
NSLog(@"3");
sleep(1);
});
此函式耗時?: 3秒
此函式輸出?: 123
複製程式碼
- 序列佇列非同步執行會開新執行緒,同步執行不會開執行緒,在一個序列隊列了,則是按照順序執行 耗時3秒,列印123;
- 併發: 任務以FIFO從序列中移除,然後併發執行,可以按照任何順序完成。它會自動開啟多個執行緒同時執行任務
- 序列: 任務以FIFO從序列中一個一個執行。一次只調度一個任務,佇列中的任務一個接著一個地執行(一個任務執行完畢後,再執行下一個任務)而且只會開啟一條執行緒
28.程式碼分析二,列印結果
dispatch_queue_t queue = dispatch_get_global_queue(0,0);
dispatch_async(queue,^{
NSLog(@"1");
[self performSelector:@selector(test) withObject:nil afterDelay:0];
NSLog(@"3");
});
- (void)test{
NSLog(@"2");
}
複製程式碼
列印 1,3
performSelector after 是基於 timer 定製器,定時器又是基於 runloop 實現的;任務2在子執行緒中,子執行緒預設 runloop 是不開啟的,所以不執行2
29.請問下面程式碼的列印結果是什麼?
- (void)test{
NSLog(@"2");
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
NSThread *thread = [[NSThread alloc]initWithBlock:^{
NSLog(@"1");
}];
[thread start];
[self performSelector:@selector(test) onThread:thread withObject:nil waitUntilDone:YES];
}
複製程式碼
列印1
- start 執行完,執行緒就銷燬了.任務 test 沒法執行了
下一篇入口:
其實呢作為一個開發者,有一個學習的氛圍跟一個交流圈子特別重要,這是我的微信 大家有興趣可以新增 邀請小夥伴們進入微信群裡一起 交流(想要加群的可以加小編微信進群哦17512010526)
作者:LEON_iOS
連結:www.jianshu.com/p/a937fd308…