#多線程理解

1.多線程概念

  • 1.什么是多線程
    事實上,同一時間內單核的CPU只能執(zhí)行一個線程,多線程是CPU快速的在多個線程之間進行切換(調度),造成了多個線程同時執(zhí)行的假象。
    如果是多核CPU就真的可以同時處理多個線程了。
  • 2.為什么要用多線程
    多線程的目的是為了同步完成多項任務,通過提高系統(tǒng)的資源利用率來提高系統(tǒng)的效率
  • 3.多線程的優(yōu)缺點
    1.優(yōu)點
    能適當提高程序的運行效率
    能適當提高資源利用率(CPU、內存利用率)
    2.缺點
    開啟線程需要占用一定的內存空間(默認情況下,主線程占用1M,子線程占用512KB),如果開啟大量的線程,會占用大量的內存空間,降低程序的性能
    線程越多,CPU在調度線程上的開銷就越大
    程序設計更加復雜:比如線程之間的通信、多線程的數(shù)據(jù)共享

2.多線程的實現(xiàn)方式

(1)pthread(POSIX Threads):一套C語言編寫的跨平臺多線程API,使用難度大,需要手動管理線程生命周期。
(2)NSThread:面向對象操作線程,使用相對簡單,需要手動管理線程生命周期。
(3)GCD:蘋果多核編程解決方案,使用起來非常方便。需要自己實現(xiàn)如:限制并發(fā)數(shù),任務間的依賴等功能。自動管理線程生命周期。
(4)NSOperation:基于GCD的封裝,面向對象操作線程,提供了比GCD更豐富的API:限制最大并發(fā)數(shù),設置任務依賴關系。但是它不能直接使用,因為它是一個抽象類,可以繼承它或者使用系統(tǒng)定義NSInvocationOperation或NSBlockOperation。自動管理線程生命周期。

3.GCD

  • 任務:任務就是執(zhí)行操作,指的是block中的代碼
    同步執(zhí)行(sync):是指不具備開辟新線程的能力
    異步執(zhí)行(async):不會阻塞主線程,會開啟新線程執(zhí)行任務,在后臺執(zhí)行

  • 隊列:
    這里的隊列就是任務隊列,即用來存放任務的隊列。隊列是一種特殊的線性表,采用先進先出(FIFO)的原則,
    每次新任務都會被插入到隊列尾部,而執(zhí)行隊列中的任務時,會從隊列頭部開始讀取并執(zhí)行。

  • GCD中有兩種隊列:串行隊列和并行隊列
    1.并行隊列(DISPATCH_QUEUE_CONCURRENT):可以多個任務同時進行,也就會開啟多個線程執(zhí)行任務。交替執(zhí)行。
    2.串行隊列(DISPATCH_QUEUE_SERIAL):任務一個接著一個執(zhí)行,也就是一個任務執(zhí)行完后,下一個任務就開始。一個接著一個執(zhí)行。

  • 特殊隊列
    1.全局隊列 dispatch_get_global_queue ,全局隊列就是并行隊列,供整個應用使用;需要兩個參數(shù),第一個是隊列優(yōu)先級(DISPATCH_QUEUE_PRIORITY_DEFAULT),第二個0即可(官方文檔說:For future use)
    2.主隊列 dispatch_get_main_queue ,主隊列就是串行隊列,在應用啟動時,就創(chuàng)建好了,所以我們要用的時候就直接拿來用而不需要創(chuàng)建

  • 任務隊列組合情況
    1.異步 + 串行 可以開辟新線程,但是任務只能一個一個取,所以沒必要開辟新線程 結果:單線程
    2.異步 + 并行 可以開辟多線程,前一個任務一旦執(zhí)行,就可以調度下一個任務 結果 :多線程
    3.同步 + 串行 即不可以開辟新線程,也不可以不等待前一任務完成就調度,完全沒必要開辟新線程 結果: 單線程
    4.同步 + 并行 不可以開辟新線程,但是可以前一個任務一旦執(zhí)行,就可以調度下一個任務 結果:單線程
    5.同步+主隊列 死鎖
    6.異步+主隊列 只在主線程中執(zhí)行任務,執(zhí)行完一個任務,再執(zhí)行下一個任務

  • 三種死鎖情況(隊列阻塞)
    1.主線程主隊列嵌套同步隊列
    2.同步串行嵌套同步串行任務
    3.異步串行嵌套同步串行任務

    3.1GCD常用方法

    • 1.柵欄函數(shù)
      dispatch_barrier_sync(myconcurrent, ^{ }); 作用相同,但是這個會堵塞線程,影響后面的執(zhí)行
      dispatch_barrier_async(myconcurrent, ^{ }); 前面的任務執(zhí)行完畢,才會來到這里,不影響后面任務的執(zhí)行
dispatch_queue_t queue = dispatch_queue_create("testqueue", DISPATCH_QUEUE_CONCURRENT);
    NSLog(@"start");

        dispatch_async(queue, ^{
            NSLog(@"----1-----%@", [NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"----2-----%@", [NSThread currentThread]);
        });
        
        dispatch_barrier_sync(queue, ^{
            NSLog(@"----barrier-----%@", [NSThread currentThread]);
        });
    NSLog(@"center");

        
        dispatch_async(queue, ^{
            NSLog(@"----3-----%@", [NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"----4-----%@", [NSThread currentThread]);
        });
    NSLog(@"end");

    //結果 12結束后再執(zhí)行34
    //dispatch_barrier_async和dispatch_barrier_sync區(qū)別 (都是在柵欄函數(shù)之前的先執(zhí)行,在柵欄后面的后執(zhí)行)
    //dispatch_barrier_async不會阻塞當前線程block添加到queue中后就會立即返回執(zhí)行線程中后面的方法
    //dispatch_barrier_sync會阻塞當前線程
  • 2.GCD延時方法
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ });
  • 3.只執(zhí)行一次操作(單例創(chuàng)建)
    static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{});
  • 4.快速迭代方法 (同時遍歷)
    dispatch_queue_t global_queue = dispatch_get_global_queue(0, 0);
    dispatch_apply(6, global_queue, ^(size_t index) {
    NSLog(@"%zd %@", index, [NSThread currentThread]);
    });
  • 5.隊列組dispatch_group_t
    第一種 會阻塞主線程,等待上面的任務執(zhí)行完,再繼續(xù)向下執(zhí)行
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    第二種 不會阻塞主線程,等待上面的任務執(zhí)行完,該block就會執(zhí)行 (推薦)
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{ NSLog(@"回到主線程 %@", [NSThread currentThread]); });
  • 6.信號量dispatch_semaphore_t
    dispatch_semaphore_wait當信號量的值大于0時,信號量會減1,當信號量的值等于0時,阻塞線程直到該信號量的值大于0或者達到等待時間
    dispatch_semaphore_signal釋放信號量,使得該信號量的值加1
    作用
    實現(xiàn)異步任務同步執(zhí)行
    限制最大并發(fā)數(shù)
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_async(queue, ^{
        sleep(3);
        dispatch_semaphore_signal(sem);

        NSLog(@"A   --thread:%@", [NSThread currentThread]);
    });
    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);

    dispatch_async(queue, ^{
        sleep(3);
        dispatch_semaphore_signal(sem);
        NSLog(@"B   --thread:%@", [NSThread currentThread]);
    });
    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);


    dispatch_async(queue, ^{
        sleep(3);
        NSLog(@"C   --thread:%@", [NSThread currentThread]);
        dispatch_semaphore_signal(sem);
    });
    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);

4.NSOperation

  • 1.什么是NSOperation
    1.NSOperation是Apple提供給開發(fā)者的一套多線程解決方案,實際上是基于GCD的一套更高級封裝,完全Objective-C代碼。簡單、易用、代碼可讀性高。
    2.NSOperation需要配合NSOperationQueue來實現(xiàn)多線程,因為默認情況下NSOperation單獨使用時是系統(tǒng)同步執(zhí)行操作,并沒有開啟新線程的能力,只有配合NSOperationQueue才能實現(xiàn)異步執(zhí)行
    3.因為NSOperation是基于GCD的,那么使用起來也和GCD差不多,其中,NSOperation相當于GCD中的任務,而NSOperationQueue則相當于GCD中的隊列。
  • 2.NSOperation實現(xiàn)多線程的使用步驟分為三步:
    1.創(chuàng)建任務 NSBlockOperation/NSInvocationOperation
    2.創(chuàng)建隊列 NSOperationQueue
    主隊列NSOperationQueue *queue = [NSOperationQueue mainQueue];
    其它隊列NSOperationQueue *queue = [[NSOperationQueue alloc] init];根據(jù)maxConcurrentOperationCount是否串行 1串行 >1并發(fā)默認并發(fā)
  • 3.操作依賴
// 1.創(chuàng)建隊列
   NSOperationQueue *queue = [[NSOperationQueue alloc] init];

   // 2.創(chuàng)建操作
   NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
       for (int i = 0; i < 2; i++) {
           [NSThread sleepForTimeInterval:2]; // 模擬耗時操作
           NSLog(@"1---%@", [NSThread currentThread]); // 打印當前線程
       }
   }];
   NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
       for (int i = 0; i < 2; i++) {
           [NSThread sleepForTimeInterval:2]; // 模擬耗時操作
           NSLog(@"2---%@", [NSThread currentThread]); // 打印當前線程
       }
   }];

   // 3.添加依賴
   [op2 addDependency:op1]; // 讓op2 依賴于 op1,則先執(zhí)行op1,在執(zhí)行op2

   // 4.添加操作到隊列中
   [queue addOperation:op1];
   [queue addOperation:op2];
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 多線程 什么是多線程?多線程就是一個進程中可以開啟多條線程,每條線程可以并行執(zhí)行不同的任務,提高執(zhí)行效率;一個基本...
    西風頌閱讀 969評論 1 16
  • 一、iOS中常見的多線程方案 要解釋多線程,需要先解釋進程和線程之間的區(qū)別。線程才是程序真正的執(zhí)行單元,一個進程可...
    小豆豆苗閱讀 837評論 0 0
  • 1.基本概念: 什么是進程: 1)進程是一個具有獨立功能的程序關于某次數(shù)據(jù)集合的一次運行活動,他是操作系統(tǒng)分配資源...
    83c11ad52c96閱讀 291評論 0 0
  • 首先先說明此文是學習了李峰峰大牛的博客后所寫,有興趣的可以百度搜索一下李峰峰的博客。 一、線程和進程 1、線程 線...
    奇怪的她的他閱讀 482評論 0 2
  • 談到編程,就離不開多線程。多線程提升了系統(tǒng)資源的利用率,使得程序在相同時間單位里可以做更多的事情,是我們每個程序員...
    楚檳夕閱讀 5,421評論 1 10

友情鏈接更多精彩內容