iOS多線程-多線程實現之GCD

  • 什麼是GCD?

    • GCD: Grand Central Dispatch (重要的中樞調度器)
    • GCD是純C語言的, 學習它就是學習一些函數的使用.
  • GCD的核心概念和使用步驟

    • 核心概念
      • 任務 : 執行什麼操做
      • 隊列 : 用於存聽任務. 隊列決定了隊列中任務的執行方式
        • 隊列又分爲:
          • 並行隊列 : 能夠多個任務同時執行.
          • 串行隊列 : 一次只能執行一個任務, 執行完一個任務才能執行下一個任務.
          • 主隊列: 特殊的串行隊列,這個後面會細說. 只要記住,主隊列中的任務,在主線程中執行.
    • 使用步驟
      • 1.肯定任務
      • 2.將任務添加到隊列中,GCD會自動將隊列中的任務取出,放到對應的線程中執行
        注意:任務取出遵照隊列的FIFO(First Input First Output)原則:先進先出,後進後出
  • GCD執行任務的兩個函數

    • 同步函數 : dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
      • queue :隊列
      • block : 回調block,也就是上面所說的任務
      • 使用同步函數的任務是在當前線程中執行,同步函數沒有建立新線程的能力
      • 注意點:若是是同步函數,只要是代碼執行到同步函數哪一行,就會當即執行block,執行完以後纔會繼續往下執行
    • 異步函數 : dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
      • queue :隊列
      • block : 回調block,也就是上面所說的任務
      • 使用異步函數的任務是在新的線程中執行,同步函數具備建立新線程的能力(具體建立多少個線程,是由系統決定的)

總結

  • 同步函數: 在當前線程中執行任務,沒有建立新線程的能力
  • 異步函數: 在新線程中執行任務,具備建立新線程的能力
  • 串行隊列: 一次只能執行一個任務,執行完畢後才能執行下一個任務
  • 並行隊列: 能夠多個任務同時執行
  • 兩種函數執行不一樣隊列的效果

    • 同步函數:
      • 使用並行隊列,在當前線程中一個一個的執行
      • 使用串行隊列,在當前線程中一個一個的執行
      • 使用主隊列,在主線程中一個一個的執行.注意:若是當前線程就是主線程的話會發生死鎖
    • 異步函數:
      • 使用並行隊列,建立多個子線程執行任務.
      • 使用串行隊列,建立一個子線程,在子線程中一個一個的執行(具體建立多少個線程,是由系統決定的)
      • 使用主隊列,在主線程中一個一個的執行.若是當前是主線程的話並不會發生死鎖

廢話很少說,上代碼

// // ViewControllerGCD.m // GCD使用 // // Created by 雨軒 on 16/1/25. // Copyright © 2016年 apple. All rights reserved. // #import "ViewControllerGCD.h" @implementation ViewControllerGCD -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ NSLog(@"======================同步函數======================"); [self syncToALLQueue]; NSLog(@"======================我是一條可愛的分割線======================"); NSLog(@"======================異步函數======================"); [self asyncToALLQueue]; } //異步函數搭配不一樣的隊列 - (void)asyncToALLQueue{ /****************************************************並行隊列****************************************************/ //方式一:建立一個隊列 /* 第一個參數:隊列的名稱 第二個參數:隊列的類型 DISPATCH_QUEUE_SERIAL 串行隊列(讓任務一個接着一個執行) DISPATCH_QUEUE_CONCURRENT 併發隊列(可讓多個任務併發執行,自動開啓多個線程執行,執行異步函數中才有效果) */ dispatch_queue_t concurrentQueue1 = dispatch_queue_create("yuxuan", DISPATCH_QUEUE_CONCURRENT); //方式二:獲取GCD提供的一個全局的並行隊列 /* 第一個參數:IOS8以前表明線程的優先級 / IOS8以後表明的是服務質量 (通常寫0) IO8以前的取值 IOS8以後的取值 * - DISPATCH_QUEUE_PRIORITY_HIGH(2) QOS_CLASS_USER_INTERACTIVE 用戶交互(用戶迫切的執行任務,不要在這種服務質量下作耗時操做) * - DISPATCH_QUEUE_PRIORITY_DEFAULT(0) QOS_CLASS_DEFAULT 默認(重置隊列) * - DISPATCH_QUEUE_PRIORITY_LOW(-2) QOS_CLASS_UTILITY 實用工具(耗時操做放在這裏) * - DISPATCH_QUEUE_PRIORITY_BACKGROUND(-32768) QOS_CLASS_BACKGROUND QOS_CLASS_UNSPECIFIED 用戶須要 QOS_CLASS_USER_INITIATED 沒有設置任務優先級 第二個參數:系統保留的佔位參數,永遠寫0 */ dispatch_queue_t concurrentQueue2 = dispatch_get_global_queue(0, 0); /****************************************************串行隊列****************************************************/ /* 第一個參數:隊列的名稱 第二個參數:隊列的類型 DISPATCH_QUEUE_SERIAL 串行隊列(讓任務一個接着一個執行) DISPATCH_QUEUE_CONCURRENT 併發隊列(可讓多個任務併發執行,自動開啓多個線程執行,執行異步函數中才有效果) */ dispatch_queue_t serialQueue = dispatch_queue_create("yuxuan", DISPATCH_QUEUE_SERIAL); /****************************************************主隊列****************************************************/ //調用函數直接獲取 dispatch_queue_t mainQueue = dispatch_get_main_queue(); /****************************************************添加任務****************************************************/ //異步函數 dispatch_async(mainQueue, ^{ NSLog(@"任務1==========%@",[NSThread currentThread]); }); //異步函數 dispatch_async(mainQueue, ^{ NSLog(@"任務2==========%@",[NSThread currentThread]); }); //異步函數 dispatch_async(mainQueue, ^{ NSLog(@"任務3==========%@",[NSThread currentThread]); }); //異步函數 dispatch_async(mainQueue, ^{ NSLog(@"任務4==========%@",[NSThread currentThread]); }); } //同步函數搭配不一樣的隊列 - (void)syncToALLQueue{ /****************************************************並行隊列****************************************************/ //方式一:建立一個隊列 /* 第一個參數:隊列的名稱 第二個參數:隊列的類型 DISPATCH_QUEUE_SERIAL 串行隊列(讓任務一個接着一個執行) DISPATCH_QUEUE_CONCURRENT 併發隊列(可讓多個任務併發執行,自動開啓多個線程執行,執行異步函數中才有效果) */ dispatch_queue_t concurrentQueue1 = dispatch_queue_create("yuxuan", DISPATCH_QUEUE_CONCURRENT); //方式二:獲取GCD提供的一個全局的並行隊列 /* 第一個參數:IOS8以前表明線程的優先級 / IOS8以後表明的是服務質量 (通常寫0) IO8以前的取值 IOS8以後的取值 * - DISPATCH_QUEUE_PRIORITY_HIGH(2) QOS_CLASS_USER_INTERACTIVE 用戶交互(用戶迫切的執行任務,不要在這種服務質量下作耗時操做) * - DISPATCH_QUEUE_PRIORITY_DEFAULT(0) QOS_CLASS_DEFAULT 默認(重置隊列) * - DISPATCH_QUEUE_PRIORITY_LOW(-2) QOS_CLASS_UTILITY 實用工具(耗時操做放在這裏) * - DISPATCH_QUEUE_PRIORITY_BACKGROUND(-32768) QOS_CLASS_BACKGROUND QOS_CLASS_UNSPECIFIED 用戶須要 QOS_CLASS_USER_INITIATED 沒有設置任務優先級 第二個參數:系統保留的佔位參數,永遠寫0 */ dispatch_queue_t concurrentQueue2 = dispatch_get_global_queue(0, 0); /****************************************************串行隊列****************************************************/ /* 第一個參數:隊列的名稱 第二個參數:隊列的類型 DISPATCH_QUEUE_SERIAL 串行隊列(讓任務一個接着一個執行) DISPATCH_QUEUE_CONCURRENT 併發隊列(可讓多個任務併發執行,自動開啓多個線程執行,執行異步函數中才有效果) */ dispatch_queue_t serialQueue = dispatch_queue_create("yuxuan", DISPATCH_QUEUE_SERIAL); /****************************************************主隊列****************************************************/ //調用函數直接獲取 dispatch_queue_t mainQueue = dispatch_get_main_queue(); /****************************************************添加任務****************************************************/ //異步函數 dispatch_sync(mainQueue, ^{ NSLog(@"任務1==========%@",[NSThread currentThread]); }); //異步函數 dispatch_sync(mainQueue, ^{ NSLog(@"任務2==========%@",[NSThread currentThread]); }); //異步函數 dispatch_sync(mainQueue, ^{ NSLog(@"任務3==========%@",[NSThread currentThread]); }); //異步函數 dispatch_sync(mainQueue, ^{ NSLog(@"任務4==========%@",[NSThread currentThread]); }); } @end
異步函數和同步函數搭配並行隊列的打印日誌:當前線程是主線程
  • 異步函數:建立了多個子線程,並行(一塊兒)執行
  • 同步函數:在當前線程(主線程)中一個一個的執行

    Paste_Image.png
異步函數和同步函數搭配串行隊列的打印日誌:當前線程是主線程
  • 異步函數: 在新線程(子線程)中一個一個的執行.
  • 同步函數: 在當前線程中一個一個的執行.

    Paste_Image.png
異步函數和同步函數搭配主隊列的打印日誌: 當前線程是主線程
  • 在syncToALLQueue方法中發生了死鎖.同步函數使用主隊列時,若是當前線程是主線程的話會發生死鎖.
    • 緣由:同步函數,只要是代碼執行到同步函數哪一行,就會當即執行block,執行完以後纔會繼續往下執行.可是此時的主線程正在處理同步函數這個函數,可是主隊列中的任務又必須在主線程中執行,這個時候block任務就會一直在等着主線程,而同步函數又一直在等着block任務執行完.這樣就發生了咱們所說的死鎖狀況.

      Paste_Image.png
    • 代碼修改,解決死鎖問題

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ //把代碼封裝到子線程中執行, 解決同步函數使用主隊列死鎖問題 dispatch_async(dispatch_get_global_queue(0, 0), ^{ NSLog(@"======================同步函數======================"); [self syncToALLQueue]; NSLog(@"======================我是一條可愛的分割線======================"); NSLog(@"======================異步函數======================"); [self asyncToALLQueue]; }); }
  • 這樣就解決了死鎖問題,由於當前線程再也不是主線程了.

    Paste_Image.png

GCD中實現線程間的通訊

  • GCD實現線程間的通訊很是簡單,直接在函數裏嵌套函數就好了
    代碼以下:併發

    //線程間的通訊 -(void)threadsCommunicate{ //在子線程中執行耗時操做 dispatch_async(dispatch_get_global_queue(0, 0), ^{ //耗時操做...... //通知主線程,執行操做(好比刷新UI) //這種狀況下使用異步函數或使用同步函數,效果是同樣的都是在主線程中執行,而且當前線程不是主線程,並不會發生死鎖 dispatch_async(dispatch_get_main_queue(), ^{ // 刷新UI }); }); }



原文連接:http://www.jianshu.com/p/efa69b932883
相關文章
相關標籤/搜索