ios開發之多線程--GCD介紹

一.GCD簡單介紹
1.什麼是GCD
全稱是Grand Central Dispatch,可譯爲“牛逼的中樞調度器”
C語言,提供了非常多強大的函數

2.GCD的優勢
GCD是蘋果公司爲多核並行運算提出的解決方案
GCD會自動利用更多的CPU內核(比如雙核、四核)
GCD會自動管理線程的生命週期(創建線程、調度任務、銷燬線程)
程序員只需要告訴GCD想要執行什麼任務,不需要編寫任何線程管理代碼

3.任務和隊列
GCD中有2個核心概念
任務執行什麼操作
隊列:用來存放任務

GCD的使用就2個步驟
定製任務
確定想做的事情
任務添加到隊列
GCD會自動將隊列中的任務取出,放到對應的線程中執行
任務的取出遵循隊列FIFO原則:先進先出,後進後出

4.執行任務
GCD中有2個用來執行任務的函數
同步的方式執行任務

dispatch_sync(dispatch_queue_tqueue, dispatch_block_tblock);

queue:隊列
block:任務
異步的方式執行任務

dispatch_async(dispatch_queue_tqueue, dispatch_block_tblock);

同步和異步的區別
同步:只能在當前線程中執行任務,不具備開啓新線程的能力
異步:可以在新的線程中執行任務,具備開啓新線程的能力

5.隊列類型
GCD的隊列可以分爲2大類型
併發隊列(Concurrent Dispatch Queue
可以讓多個任務併發同時)執行自動開啓多個線程同時執行任務)
併發功能只有在異步dispatch_async)函數下才有效
串行隊列(Serial Dispatch Queue
讓任務一個接着一個地執行(一個任務執行完畢後,再執行下一個任務


重點提示:容易混淆的術語
4個術語比較容易混淆:同步異步併發串行
同步異步主要影響:能不能開啓新的線程
同步:在當前線程中執行任務,不具備開啓新線程的能力
異步:在新的線程中執行任務,具備開啓新線程的能力

併發串行主要影響:任務的執行方式
併發多個任務併發(同時)執行
串行一個任務執行完畢後,再執行下一個任務

二.創建隊列
1.併發隊列
GCD默認已經提供了全局的併發隊列,供整個應用使用,不需要手動創建
使用dispatch_get_global_queue函數獲得全局的併發隊列

dispatch_queue_t dispatch_get_global_queue(

dispatch_queue_priority_tpriority,// 隊列的優先級

unsigned longflags);// 此參數暫時無用,用0即可

dispatch_queue_tqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //獲得全局併發隊列

全局併發隊列的優先級
#defineDISPATCH_QUEUE_PRIORITY_HIGH 2//
#defineDISPATCH_QUEUE_PRIORITY_DEFAULT 0// 默認(中)
#defineDISPATCH_QUEUE_PRIORITY_LOW (-2)//
#defineDISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN// 後臺

2.串行隊列
GCD中獲得串行有2種途徑
使用dispatch_queue_create函數創建串行隊列

dispatch_queue_t

dispatch_queue_create(const char*label, //隊列名稱

dispatch_queue_attr_t attr); //隊列屬性,一般用NULL即可

dispatch_queue_tqueue = dispatch_queue_create("cn.itcast.queue", NULL); // 創建

dispatch_release(queue); //ARC需要釋放手動創建的隊列

使用主隊列(跟主線程相關聯的隊列)
主隊列是GCD自帶的一種特殊的串行隊列
放在主隊列中的任務,都會放到主線程中執行
使用dispatch_get_main_queue()獲得主隊列

dispatch_queue_tqueue = dispatch_get_main_queue();

3.各種隊列執行的效果


 注意

 使用sync函數往當前串行隊列中添加任務,會卡住當前的串行隊列

三.線程間通信示例

從子線程回到主線程

dispatch_async(

dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

   //執行耗時的異步操作...

     dispatch_async(dispatch_get_main_queue(),^{

        // 回到主線程,執行UI刷新操作

        });

});


四.延時執行
iOS常見的延時執行有2種方式
調用NSObject的方法

[self performSelector:@selector(run)withObject:nil afterDelay:2.0];

// 2秒後再調用selfrun方法

使用GCD函數

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(),^{

   //2秒後執行這裏的代碼...在哪個線程執行,跟隊列類型有關

   

});

五.一次性代碼
使用dispatch_once函數能保證某段代碼在程序運行過程中只被執行1

static dispatch_once_t onceToken;

dispatch_once(&onceToken, ^{

   //只執行1次的代碼(這裏面默認是線程安全的)

});


六.隊列組
有這麼1種需求
首先:分別異步執行2個耗時的操作
其次:等2個異步操作都執行完畢後,再回到主線程執行操作

如果想要快速高效地實現上述需求,可以考慮用隊列組

dispatch_group_tgroup =  dispatch_group_create();

dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

   //執行1個耗時的異步操作

});

dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

   //執行1個耗時的異步操作

});

dispatch_group_notify(group,dispatch_get_main_queue(),^{

   //等前面的異步操作都執行完畢後,回到主線程...

});

七.單例模式

1.單例模式的作用
可以保證在程序運行過程,一個類只有一個實例,而且該實例易於供外界訪問
從而方便地控制了實例個數,並節約系統資源

單例模式的使用場合
在整個應用程序中,共享一份資源(這份資源只需要創建初始化1次)

單例模式在ARC\MRC環境下的寫法有所不同需要編寫2套不同的代碼
可以用宏判斷是否爲ARC環境

#if __has_feature(objc_arc)

// ARC

#else

// MRC

#endif

2.ARC中,單例模式的實現
.m中保留一個全局的static的實例

static id_instance;

重寫allocWithZone:方法,在這裏創建唯一的實例(注意線程安全)

+ (id)allocWithZone:(struct _NSZone*)zone {

   if (_instance == nil) { // 防止頻繁加鎖

        @synchronized(self) {

            if (_instance == nil) { // 防止創建多次

    _instance = [super allocWithZone:zone];

            }

        }

   }

   return _instance;

}

提供1個類方法讓外界訪問唯一的實例

+ (instancetype)sharedMusicTool {

   if (_instance == nil) { // 防止頻繁加鎖

          @synchronized(self) {

            if (_instance == nil) { // 防止創建多次

               _instance = [[self alloc] init];

            }

        }

   }

   return _instance;

}

實現copyWithZone:方法

- (id)copyWithZone:(struct _NSZone*)zone {

   return _instance;

}


3.ARC中(MRC),單例模式的實現ARC多了幾個步驟)
p實現內存管理方法

- (id)retain { return self; }

- (NSUInteger)retainCount { return 1; }

- (oneway void)release{}

- (id)autorelease { return self; }


八 .代碼示例:

<span style="font-size:18px;">//1.串行隊列 + 同步執行函數
//結論1. 沒有開啓新線程
//結論2. 按順序執行
//開發中布經常用
- (void)serialAddSync
{
    NSLog(@"serialAddSycn%@",[NSThread currentThread]);
    //1.創建串行隊列
    dispatch_queue_t queue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL);
    //2.同步執行函數 將任務添加到串行隊列中 交給同步執行函數執行
    dispatch_sync(queue, ^{
        //任務1
        NSLog(@"耗時任務1:%@",[NSThread currentThread]);
        
    });
    //往串行隊列中 添加多個任務
    dispatch_sync(queue, ^{
        //任務2
        NSLog(@"耗時任務2:%@",[NSThread currentThread]);
        
    });dispatch_sync(queue, ^{
        //任務3
        NSLog(@"耗時任務3:%@",[NSThread currentThread]);
        
    });
}
</span>



//2.串行隊列 + 異步執行函數

//結論1.開啓新線程
//2.同一隊列的任務由同一個線程來執行,肯定是按順序執行
//一個串行隊列對應一條線程
- (void)serialAddAsync{
NSLog(@"serialAddAsycnBegan%@",[NSThread currentThread]);

//1.創建串行隊列
dispatch_queue_t queue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue1 = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL);

//2.異步執行函數 將任務添加到串行隊列中 交給異步執行函數執行
dispatch_async(queue, ^{
//任務1
NSLog(@"耗時任務1:%@",[NSThread currentThread]);

});
dispatch_async(queue, ^{
//任務2
NSLog(@"耗時任務2:%@",[NSThread currentThread]);

});
dispatch_async(queue, ^{
//任務3
NSLog(@"耗時任務3:%@",[NSThread currentThread]);

});
dispatch_async(queue1, ^{
//任務1
NSLog(@"耗時任務4:%@",[NSThread currentThread]);

});
dispatch_async(queue1, ^{
//任務2
NSLog(@"耗時任務5:%@",[NSThread currentThread]);

});

NSLog(@"serialAddAsycnEnd%@",[NSThread currentThread]);


}

//3.併發隊列 + 同步執行函數
//沒有開啓新線程
//任務順序執行(在同一線程(當前線程)中執行)
- (void)concurrentAddSync
{
    NSLog(@"concurrentAddSync%@",[NSThread currentThread]);
    //1.創建全局併發隊列
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    //2.將任務添加到隊列中
    dispatch_sync(queue, ^{
        //任務
        NSLog(@"任務1:%@",[NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        //任務
        NSLog(@"任務2:%@",[NSThread currentThread]);
    });dispatch_sync(queue, ^{
        //任務
        NSLog(@"任務3:%@",[NSThread currentThread]);
    });
}

//4.併發隊列 + 異步執行函數(開發中使用最多)
//開啓多條線程
//任務同時執行的
- (void)concurrentAddAsync {
    NSLog(@"concurrentAddAsync%@",[NSThread currentThread]);
    //1.創建全局併發隊列
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    //2.將任務添加到隊列
    dispatch_async(queue, ^{
        //任務
        NSLog(@"任務1:%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        //任務
        NSLog(@"任務2:%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        //任務
        NSLog(@"任務3:%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        //任務
        NSLog(@"任務4:%@",[NSThread currentThread]);
    });
}

//5.主隊列 + 同步執行函數
    //1.如果當前線程爲主線程 會照成主隊列和主線程中的任務相互等待 無法執行 主線程卡死
    //主隊列的任務都交給主線程執行
    
    //主隊列和主線程中的任務相互等待 無法執行
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"renwu1%@",[NSThread currentThread]);
    });
    NSLog(@"touchesEnd%@",[NSThread currentThread]);

 //6.主隊列 + 異步執行函數 (開發中需要回到主線程 使用 主隊列 + 異步函數)
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"renwu1%@",[NSThread currentThread]);
    });
    NSLog(@"touchesEnd%@",[NSThread currentThread]);
    


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章