GCD

走進GCD
前言:本文章第一時間出現(xiàn)在一個程序猿的秘密基地專題中,如果您喜歡類似的文章,請您點擊一個程序猿的秘密基地進行關(guān)注,在以后的日子里與小編共同成長!

1.GCD是什么?
2.GCD的優(yōu)勢
3.GCD的核心理念
4.GCD的隊列類型
5.自定義串行和并行隊列
6.全局并行隊列的優(yōu)先級
7.主線程中的串行隊列
8.調(diào)度組
9.調(diào)度組(擴展)
10.造成線程死鎖的兩種情況
11.線程鎖(NSLock)
12.通過GCD實現(xiàn)單例類(ARC)
13.通過GCD實現(xiàn)單例類(MRC)


1.GCD是什么?

   GCD全稱Grand Central Dispath(宏大的的中央調(diào)度),是蘋果開發(fā)的一種支持并行操作的機制。
   它的主要部件是一個FIFO隊列和一個線程池,前者用來添加任務(wù),后者用來執(zhí)行任務(wù)。
   GCD中的FIFO隊列稱為dispatch queue,它可以保證先進來的任務(wù)先得到執(zhí)行(但不
保證一定先執(zhí)行結(jié)束)。
   GCD中的函數(shù)大多數(shù)都以dispatch開頭

2.GCD的優(yōu)勢

1.它是蘋果公司為多核的并行運算提出的解決方案
2.它在工作的時候會自動利用更多的處理器核心
3.不用關(guān)心線程代碼的實現(xiàn),即不需要關(guān)心什么時候開啟線程、關(guān)閉線程,GCD會負責(zé)創(chuàng)建線程調(diào)度你的任務(wù)
4.只需要創(chuàng)建出來你要執(zhí)行的任務(wù),然后把任務(wù)添加到適當(dāng)?shù)年犃兄?

3.GCD的核心理念

將長期運行的任務(wù)拆分成多個工作單元,并把這些工作單元添加調(diào)度隊列

4.GCD的隊列類型

分為兩種類型:
1.串行隊列(需要自己創(chuàng)建隊列):排成一隊,一次只能執(zhí)行一個任務(wù),當(dāng)前的任務(wù)完成之后開始出列,
  啟動下一個任務(wù)
2.并行隊列(不需要自己創(chuàng)建隊列):同時排成N個隊,可以讓多個任務(wù)同時執(zhí)行,即啟動多個線程同時
  執(zhí)行任務(wù),并發(fā)功能只有在異步(dispatch_async)函數(shù)下才有效
ps:并行隊列依舊按照任務(wù)添加的順序啟動任務(wù),但是,后一個任務(wù)無須等待前一個任務(wù)執(zhí)行完畢,而是
  啟動第一個任務(wù)后,立即啟動下一個任務(wù)。至于同一時刻允許同時運行多少個任務(wù)由系統(tǒng)決定,任務(wù)各自
  運行在并行隊列為它們提供的獨立線程上,并行隊列中同時運行多少個任務(wù),就必須維護多少個線程。

5.自定義串行和并行隊列。

/*
 *  (1)串行隊列,添加同步任務(wù)
 *  串行隊列中的任務(wù)按照添加順序執(zhí)行,不會開啟新線程.
 */
- (void)demo1
{
    //創(chuàng)建串行隊列
    //參數(shù)1:表示隊列的標(biāo)識符,一般以反域名的形式命名
    //參數(shù)2:隊列樣式,DISPATCH_QUEUE_SERIAL或者NULL,表示串行隊列
    dispatch_queue_t mySerialQueue = dispatch_queue_create("com.zhiyou.aaa", DISPATCH_QUEUE_SERIAL);
    
    //將任務(wù)添加到隊列中.
    //sync(同步):阻塞當(dāng)前線程,當(dāng)block塊中的任務(wù)執(zhí)行完畢之后,再執(zhí)行后續(xù)代碼
    NSLog(@"111111");
    
    dispatch_sync(mySerialQueue, ^{
        NSLog(@"--------%@",[NSThread currentThread]);
        for (int i = 0; i < 100; i++)
        {
            NSLog(@"2222222");
        }
        
    });
    dispatch_sync(mySerialQueue, ^{
        NSLog(@"--------%@",[NSThread currentThread]);
        for (int i = 0; i < 100; i++)
        {
            NSLog(@"33333333");
        }
        
    });
    
    for (int i = 0; i < 100; i++)
    {
        NSLog(@"44444444");
    }
    
}

/*
 * (2)串行隊列,添加異步任務(wù).
 * 只開辟一條新線程,新線程中的任務(wù)還是按照添加順序執(zhí)行,但是與主線程中任務(wù)是并發(fā)執(zhí)行.
 */
- (void)demo2
{
    dispatch_queue_t mySerialQueue = dispatch_queue_create("com.zhiyou.bbb", DISPATCH_QUEUE_SERIAL);
    //async(異步):不阻塞當(dāng)前線程.block塊中的任務(wù)與后續(xù)代碼同時執(zhí)行.
    NSLog(@"1111111");
    
    dispatch_async(mySerialQueue, ^{
        NSLog(@"------%@",[NSThread currentThread]);
        
        for (int i = 0; i < 50; i++)
        {
            NSLog(@"22222");
        }
    });
    dispatch_async(mySerialQueue, ^{
        NSLog(@"------%@",[NSThread currentThread]);
        
        for (int i = 0; i < 50; i++)
        {
            NSLog(@"33333");
        }
    });
    
    for (int i = 0; i < 50; i++)
    {
        NSLog(@"44444");
    }
}

/*
 * (3)并行隊列,添加同步任務(wù)(并無任何意義)
 * 不會開辟新線程,任務(wù)按添加順序執(zhí)行.
 */
- (void)demo3
{
    //DISPATCH_QUEUE_CONCURRENT:表示并行隊列
    dispatch_queue_t myConcurrentQurue = dispatch_queue_create("com.zhiyou.ccc", DISPATCH_QUEUE_CONCURRENT);
    NSLog(@"1111");
    
    dispatch_sync(myConcurrentQurue, ^{
        NSLog(@"-----%@",[NSThread currentThread]);
        for (int i = 0; i < 50; i++)
        {
            NSLog(@"2222");
        }
    });
    dispatch_sync(myConcurrentQurue, ^{
        NSLog(@"-----%@",[NSThread currentThread]);
        for (int i = 0; i < 50; i++)
        {
            NSLog(@"333");
        }
    });
    dispatch_sync(myConcurrentQurue, ^{
        NSLog(@"-----%@",[NSThread currentThread]);
        for (int i = 0; i < 50; i++)
        {
            NSLog(@"444");
        }
    });
    
    for (int i = 0; i < 50; i++)
    {
        NSLog(@"5555");
    }
}
/*
 * 并行隊列,添加異步任務(wù)
 * 會開辟多條新線程,任務(wù)并發(fā)執(zhí)行.
 */
- (void)demo4
{
    dispatch_queue_t myConcurrentQurue = dispatch_queue_create("com.zhiyou.ccc", DISPATCH_QUEUE_CONCURRENT);
    NSLog(@"1111");
    
    dispatch_async(myConcurrentQurue, ^{
        NSLog(@"-----%@",[NSThread currentThread]);
        for (int i = 0; i < 50; i++)
        {
            NSLog(@"2222");
        }
    });
    dispatch_async(myConcurrentQurue, ^{
        NSLog(@"-----%@",[NSThread currentThread]);
        for (int i = 0; i < 50; i++)
        {
            NSLog(@"333");
        }
    });
    dispatch_async(myConcurrentQurue, ^{
        NSLog(@"-----%@",[NSThread currentThread]);
        for (int i = 0; i < 50; i++)
        {
            NSLog(@"444");
        }
    });
    
    for (int i = 0; i < 50; i++)
    {
        NSLog(@"5555");
    }

}

6.全局并行隊列的優(yōu)先級

/*
 * 2.運行在分線程的四個優(yōu)先級不同全局并行隊列,globalQueue
 * 開辟多條線程,并發(fā)執(zhí)行任務(wù)
 */
- (void)demo5
{
    //獲取 globalQueue
    //參數(shù)1:表示隊列的優(yōu)先級
    //參數(shù)2:預(yù)留參數(shù),設(shè)置為0.
    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
   
    
    dispatch_queue_t globalQueue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    dispatch_queue_t globalQueue2 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
    
    dispatch_async(globalQueue, ^{
        NSLog(@"------%@",[NSThread currentThread]);
        for (int i = 0; i < 5; i++)
        {
            NSLog(@"2222");
        }
    });
    
    
   
    
    dispatch_async(globalQueue1, ^{
        NSLog(@"------%@",[NSThread currentThread]);
        for (int i = 0; i < 5; i++)
        {
            NSLog(@"1111111");
        }
    });

    
    
    
   
    dispatch_async(globalQueue2, ^{
        NSLog(@"------%@",[NSThread currentThread]);
        for (int i = 0; i < 5; i++)
        {
            NSLog(@"000000");
        }
    });

    
    
        for (int i = 0; i < 5; i++)
        {
            NSLog(@"5555");
        }
}

7.主線程中的串行隊列

PS:在主線程中,主隊列中使用同步任務(wù)會造成死鎖
/*
 主隊列
 運行在主線程的串行隊列,mainQueue。
 */
- (void)demo6
{
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    
    NSLog(@"11111");
    dispatch_async(mainQueue, ^{
       
        NSLog(@"-----%@",[NSThread currentThread]);
        for (int i = 0; i < 20; i++)
        {
            NSLog(@"22222");
        }
        
    });
    for (int i = 0; i < 20; i++)
    {
        NSLog(@"33333");
    }
}

8.調(diào)度組

//  群組-統(tǒng)一監(jiān)控一組任務(wù)
    dispatch_group_t group = dispatch_group_create();
    
    dispatch_queue_t q = dispatch_get_global_queue(0, 0);
    // 添加任務(wù)
    // group 負責(zé)監(jiān)控任務(wù),queue 負責(zé)調(diào)度任務(wù)
    dispatch_group_async(group, q, ^{
        [NSThread sleepForTimeInterval:1.0];
        NSLog(@"任務(wù)1 %@", [NSThread currentThread]);
    });
    dispatch_group_async(group, q, ^{
        NSLog(@"任務(wù)2 %@", [NSThread currentThread]);
    });
    dispatch_group_async(group, q, ^{
        NSLog(@"任務(wù)3 %@", [NSThread currentThread]);
    });
   
    // 監(jiān)聽所有任務(wù)完成 - 等到 group 中的所有任務(wù)執(zhí)行完畢后,"由隊列調(diào)度 block 中的任務(wù)異步執(zhí)行!"
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        // 修改為主隊列,后臺批量下載,結(jié)束后,主線程統(tǒng)一更新UI
        NSLog(@"OK %@", [NSThread currentThread]);
    });
    
    NSLog(@"come here");

9.調(diào)度組(擴展)

調(diào)度組中還有一個添加任務(wù)的函數(shù):
dispatch_group_enter(dispatch_group_t group)
dispatch_group_leave(dispatch_group_t group)
這兩個函數(shù)要配對出現(xiàn) 例如:

// 群組-統(tǒng)一監(jiān)控一組任務(wù)
dispatch_group_t group = dispatch_group_create();
 
dispatch_queue_t q = dispatch_get_global_queue(0, 0);
 
// 1> 入組 -> 之后的 block 會被 group 監(jiān)聽
// dispatch_group_enter 一定和 dispatch_group_leave 要配對出現(xiàn)
dispatch_group_enter(group);
dispatch_async(q, ^{
    NSLog(@"task1 %@", [NSThread currentThread]);
     
    // block 的末尾,所有任務(wù)執(zhí)行完畢后,添加一個出組
    dispatch_group_leave(group);
});
 
//  再次入組
dispatch_group_enter(group);
dispatch_async(q, ^{
    [NSThread sleepForTimeInterval:1.0];
     
    NSLog(@"task2 %@", [NSThread currentThread]);
     
    // block 的末尾,所有任務(wù)執(zhí)行完畢后,添加一個出組
    dispatch_group_leave(group);
});
 
// 群組結(jié)束
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    NSLog(@"OVER");
});  
NSLog(@"come here");

10.造成線程死鎖的兩種情況

《1》請回看本文中第七條 條目下的注釋,講述的是第一種死鎖情況。
《2》串行隊列在使用的過程中容易出現(xiàn)死鎖,調(diào)用 同步函數(shù)的隊列 和 同步函數(shù)添加任務(wù)的目標(biāo)隊列 是同一個隊列.
如果不是同一個隊列, 是沒有問題的.
dispatch_queue_t queue = dispatch_queue_create("com.zhiyou.queue", DISPATCH_QUEUE_SERIAL);
 NSLog(@"任務(wù)一");
dispatch_sync(queue, ^{
NSLog(@"任務(wù)二");
//queue隊列在調(diào)用同步函數(shù)
        dispatch_sync(queue, ^{
           
            NSLog(@"任務(wù)三");
        });
        
        NSLog(@"任務(wù)四");
    });
    
    NSLog(@"任務(wù)五");

11.線程鎖(NSLock)

//Demo介紹:模擬售票員買票,展示不加鎖和加鎖的區(qū)別
#import "ViewController.h"

@interface ViewController ()
{
    NSInteger _ticketNum;
    NSLock *_lock;
}
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self sellTicket];
}

- (void)sellTicket
{
    //所剩下的票數(shù)
    _ticketNum = 6;
    
    //創(chuàng)建鎖
    _lock = [[NSLock alloc]init];

    NSThread *theard1 = [[NSThread alloc]initWithTarget:self selector:@selector(buyTicket) object:nil];
    theard1.name = @"售票員1";
    [theard1 start];
    
    NSThread *theard2 = [[NSThread alloc]initWithTarget:self selector:@selector(buyTicket) object:nil];
    theard2.name = @"售票員2";
    [theard2 start];
    
    NSThread *theard3 = [[NSThread alloc]initWithTarget:self selector:@selector(buyTicket) object:nil];
    theard3.name = @"售票員3";
    [theard3 start];
    
}
- (void)buyTicket
{
    while (YES)
    {
        //鎖
//        [_lock lock];
        
 
        
            if (_ticketNum > 0)
            {
                [NSThread sleepForTimeInterval:0.1];
                
                _ticketNum--;
                
                NSLog(@"%@賣了一張票,還剩余 %d 張票",[NSThread currentThread].name,_ticketNum);
            }
            else
            {
                return;
            }
        
        //解鎖
//        [_lock unlock];
    }
}
@end
下面是我捕捉到的不加鎖控制面板的輸入?

·


情況一:錯序

情景二:出現(xiàn)兩個售票員同時操作同一張票,導(dǎo)致票數(shù)錯誤

12.通過GCD實現(xiàn)單例類(ARC)

#import "Singleton.h"

static Singleton *singleton = nil;

@implementation Singleton

//通過GCD來實現(xiàn)單例模式
+ (instancetype)shareSingleton
{
    //參數(shù)1:謂詞,用來判斷block塊是否已經(jīng)被執(zhí)行.
    //參數(shù)2:只會被調(diào)用一次的block
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
        singleton = [[super allocWithZone:NULL]init];
        
    });
    
    return singleton;
}
+ (id)allocWithZone:(struct _NSZone *)zone
{
    return [self shareSingleton];
}


@end

13.通過GCD實現(xiàn)單例類(MRC)

danlilei.h

#import <Foundation/Foundation.h>

@interface danlilei : NSObject
+(instancetype)danlilei;

@end

danlilei.m

//需要確保單例類的原則:一個類只有一個對象。所以要重寫以下所有方法
#import "danlilei.h"
static danlilei4*danli=nil;
@implementation danlilei
+(instancetype)danlilei
{
    @synchronized(self)
    {
        danli=[danlilei4 new];
    }
    return danli;
}
-(id)init
{
    self=[super init];
    if (self)
    {
        
    }
    return self;
}
+(instancetype)allocWithZone:(struct _NSZone *)zone
{
    return [self danlilei];
}
+(id)copyWithZone:(struct _NSZone *)zone
{
    return [self danlilei];
}
-(instancetype)retain
{
    return danli;
}
-(oneway void)release
{
    
}
-(id)autorelease
{
    return danli;
}
-(NSUInteger)retainCount
{
    return 1;
}

@end
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容