大廠常問iOS面試題--多線程篇

1.進程與線程

  • 進程:

    1.進程是一個具有一定獨立功能的程序關于某次數據集合的一次運行活動,它是操作系統分配資源的基本單元.

    2.進程是指在系統中正在運行的一個應用程序,就是一段程序的執行過程,我們可以理解為手機上的一個app.

    3.每個進程之間是獨立的,每個進程均運行在其專用且受保護的內存空間內,擁有獨立運行所需的全部資源

  • 線程

    1.程序執行流的最小單元,線程是進程中的一個實體.

    2.一個進程要想執行任務,必須至少有一條線程.應用程序啟動的時候,系統會默認開啟一條線程,也就是主線程

  • 進程和線程的關系

    1.線程是進程的執行單元,進程的所有任務都在線程中執行

    2.線程是 CPU 分配資源和調度的最小單位

    3.一個程序可以對應多個進程(多進程),一個進程中可有多個線程,但至少要有一條線程

    4.同一個進程內的線程共享進程資源

2.什么是多線程?

  • 多線程的實現原理:事實上,同一時間內單核的CPU只能執行一個線程,多線程是CPU快速的在多個線程之間進行切換(調度),造成了多個線程同時執行的假象。

  • 如果是多核CPU就真的可以同時處理多個線程了。

  • 多線程的目的是為了同步完成多項任務,通過提高系統的資源利用率來提高系統的效率。

3.多線程的優點和缺點

  • 優點:

    能適當提高程序的執行效率

    能適當提高資源利用率(CPU、內存利用率)

  • 缺點:

    開啟線程需要占用一定的內存空間(默認情況下,主線程占用1M,子線程占用512KB),如果開啟大量的線程,會占用大量的內存空間,降低程序的性能

    線程越多,CPU在調度線程上的開銷就越大

    程序設計更加復雜:比如線程之間的通信、多線程的數據共享

4.多線程的 并行 和 并發 有什么區別?

  • 并行:充分利用計算機的多核,在多個線程上同步進行

  • 并發:在一條線程上通過快速切換,讓人感覺在同步進行

5.iOS中實現多線程的幾種方案,各自有什么特點?

  • NSThread 面向對象的,需要程序員手動創建線程,但不需要手動銷毀。子線程間通信很難。

  • GCD c語言,充分利用了設備的多核,自動管理線程生命周期。比NSOperation效率更高。

  • NSOperation 基于gcd封裝,更加面向對象,比gcd多了一些功能。

6.多個網絡請求完成后執行下一步

  • 使用GCD的dispatch_group_t

    創建一個dispatch_group_t

    每次網絡請求前先dispatch_group_enter,請求回調后再dispatch_group_leave,enter和leave必須配合使用,有幾次enter就要有幾次leave,否則group會一直存在。

    當所有enter的block都leave后,會執行dispatch_group_notify的block。

    NSString *str = @"http://xxxx.com/";
    NSURL *url = [NSURL URLWithString:str];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    NSURLSession *session = [NSURLSession sharedSession];
    
    dispatch_group_t downloadGroup = dispatch_group_create();
    for (int i=0; i<10; i++) {
        dispatch_group_enter(downloadGroup);
    
        NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            NSLog(@"%d---%d",i,i);
            dispatch_group_leave(downloadGroup);
        }];
        [task resume];
    }
    
    dispatch_group_notify(downloadGroup, dispatch_get_main_queue(), ^{
        NSLog(@"end");
    });
    
    
  • 使用GCD的信號量dispatch_semaphore_t

    dispatch_semaphore信號量為基于計數器的一種多線程同步機制。如果semaphore計數大于等于1,計數-1,返回,程序繼續運行。如果計數為0,則等待。dispatch_semaphore_signal(semaphore)為計數+1操作,dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER)為設置等待時間,這里設置的等待時間是一直等待。

    創建semaphore為0,等待,等10個網絡請求都完成了,dispatch_semaphore_signal(semaphore)為計數+1,然后計數-1返回

    NSString *str = @"http://xxxx.com/";
    NSURL *url = [NSURL URLWithString:str];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    NSURLSession *session = [NSURLSession sharedSession];
    
    dispatch_semaphore_t sem = dispatch_semaphore_create(0);
    for (int i=0; i<10; i++) {
    
        NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            NSLog(@"%d---%d",i,i);
            count++;
            if (count==10) {
                dispatch_semaphore_signal(sem);
                count = 0;
            }
        }];
        [task resume];
    }
    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
    
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"end");
    });
    
    

7.多個網絡請求順序執行后執行下一步

  • 使用信號量semaphore

    每一次遍歷,都讓其dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER),這個時候線程會等待,阻塞當前線程,直到dispatch_semaphore_signal(sem)調用之后

    NSString *str = @"http://www.lxweimin.com/p/6930f335adba";
    NSURL *url = [NSURL URLWithString:str];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    NSURLSession *session = [NSURLSession sharedSession];
    
    dispatch_semaphore_t sem = dispatch_semaphore_create(0);
    for (int i=0; i<10; i++) {
    
        NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
    
            NSLog(@"%d---%d",i,i);
            dispatch_semaphore_signal(sem);
        }];
    
        [task resume];
        dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
    }
    
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"end");
    });
    
    

8.異步操作兩組數據時, 執行完第一組之后, 才能執行第二組

  • 這里使用dispatch_barrier_async柵欄方法即可實現

    dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{
        NSLog(@"第一次任務的主線程為: %@", [NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"第二次任務的主線程為: %@", [NSThread currentThread]);
    });
    
    dispatch_barrier_async(queue, ^{
        NSLog(@"第一次任務, 第二次任務執行完畢, 繼續執行");
    });
    
    dispatch_async(queue, ^{
        NSLog(@"第三次任務的主線程為: %@", [NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"第四次任務的主線程為: %@", [NSThread currentThread]);
    });
    
    

9.多線程中的死鎖?

死鎖是由于多個線程(進程)在執行過程中,因為爭奪資源而造成的互相等待現象,你可以理解為卡主了。產生死鎖的必要條件有四個:

  • 互斥條件 : 指進程對所分配到的資源進行排它性使用,即在一段時間內某資源只由一個進程占用。如果此時還有其它進程請求資源,則請求者只能等待,直至占有資源的進程用畢釋放。

  • 請求和保持條件 : 指進程已經保持至少一個資源,但又提出了新的資源請求,而該資源已被其它進程占有,此時請求進程阻塞,但又對自己已獲得的其它資源保持不放。

  • 不可剝奪條件 : 指進程已獲得的資源,在未使用完之前,不能被剝奪,只能在使用完時由自己釋放。

  • 環路等待條件 : 指在發生死鎖時,必然存在一個進程——資源的環形鏈,即進程集合{P0,P1,P2,···,Pn}中的P0正在等待一個P1占用的資源;P1正在等待P2占用的資源,……,Pn正在等待已被P0占用的資源。

    最常見的就是 同步函數 + 主隊列 的組合,本質是隊列阻塞。

    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"2");
    });
    
    NSLog(@"1");
    // 什么也不會打印,直接報錯
    
    

10.GCD執行原理?

  • GCD有一個底層線程池,這個池中存放的是一個個的線程。之所以稱為“池”,很容易理解出這個“池”中的線程是可以重用的,當一段時間后這個線程沒有被調用胡話,這個線程就會被銷毀。注意:開多少條線程是由底層線程池決定的(線程建議控制再3~5條),池是系統自動來維護,不需要我們程序員來維護(看到這句話是不是很開心?) 而我們程序員需要關心的是什么呢?我們只關心的是向隊列中添加任務,隊列調度即可。

  • 如果隊列中存放的是同步任務,則任務出隊后,底層線程池中會提供一條線程供這個任務執行,任務執行完畢后這條線程再回到線程池。這樣隊列中的任務反復調度,因為是同步的,所以當我們用currentThread打印的時候,就是同一條線程。

  • 如果隊列中存放的是異步的任務,(注意異步可以開線程),當任務出隊后,底層線程池會提供一個線程供任務執行,因為是異步執行,隊列中的任務不需等待當前任務執行完畢就可以調度下一個任務,這時底層線程池中會再次提供一個線程供第二個任務執行,執行完畢后再回到底層線程池中。

  • 這樣就對線程完成一個復用,而不需要每一個任務執行都開啟新的線程,也就從而節約的系統的開銷,提高了效率。在iOS7.0的時候,使用GCD系統通常只能開5--8條線程,iOS8.0以后,系統可以開啟很多條線程,但是實在開發應用中,建議開啟線程條數:3--5條最為合理。


需要iOS開發學習資料、大廠面試真題,可加 iOS技術探討群:937194184,群文件直接獲取

如下圖所示:

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,572評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,071評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,409評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,569評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,360評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,895評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,979評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,123評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,643評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,559評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,742評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,250評論 5 356
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,981評論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,363評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,622評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,354評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,707評論 2 370

推薦閱讀更多精彩內容