GCD

来源:互联网 发布:linux永久挂载硬盘 编辑:程序博客网 时间:2024/06/08 05:51

GCD的介绍有另外一篇博客专门写了下,需要看的可以点击以下传送门GCD线程死锁解锁案例分析,这里主要记录下基本的API使用以及两种单例的创建方式

1.GCD同步异步并发串行排列组合的集中基本形式

/* *  异步串行   --->       不阻塞当前线程,会开多一条线程,在这个线程中是串行执行的 */- (void)asynchSerial{    // 全局并发队列    //    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);    // 自定义并发队列    dispatch_queue_t queue1 = dispatch_queue_create("COM.MKJ.COM", DISPATCH_QUEUE_SERIAL);    dispatch_async(queue1, ^{        NSLog(@"------1,%@",[NSThread currentThread]);    });    dispatch_async(queue1, ^{        NSLog(@"------2,%@",[NSThread currentThread]);    });    dispatch_async(queue1, ^{        NSLog(@"------3,%@",[NSThread currentThread]);    });    NSLog(@"asynchSerial------end");//    2016-12-21 09:34:16.222 GCDBasicAPI[1137:38266] asynchSerial------end//    2016-12-21 09:34:16.222 GCDBasicAPI[1137:38300] ------1,<NSThread: 0x60000007a640>{number = 3, name = (null)}//    2016-12-21 09:34:16.223 GCDBasicAPI[1137:38300] ------2,<NSThread: 0x60000007a640>{number = 3, name = (null)}//    2016-12-21 09:34:16.223 GCDBasicAPI[1137:38300] ------3,<NSThread: 0x60000007a640>{number = 3, name = (null)}}/* *  同步串行   --->       阻塞当前线程,不开多条线程,在当前线程执行,顺序执行 */- (void)synchSerial{    // 全局并发队列    //    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);    // 自定义并发队列    dispatch_queue_t queue1 = dispatch_queue_create("COM.MKJ.COM", DISPATCH_QUEUE_SERIAL);    dispatch_sync(queue1, ^{        NSLog(@"------1,%@",[NSThread currentThread]);    });    dispatch_sync(queue1, ^{        NSLog(@"------2,%@",[NSThread currentThread]);    });    dispatch_sync(queue1, ^{        NSLog(@"------3,%@",[NSThread currentThread]);    });    NSLog(@"synchSerial------end");//    2016-12-21 09:32:25.878 GCDBasicAPI[1117:36348] ------1,<NSThread: 0x600000075700>{number = 1, name = main}//    2016-12-21 09:32:25.878 GCDBasicAPI[1117:36348] ------2,<NSThread: 0x600000075700>{number = 1, name = main}//    2016-12-21 09:32:25.879 GCDBasicAPI[1117:36348] ------3,<NSThread: 0x600000075700>{number = 1, name = main}//    2016-12-21 09:32:25.879 GCDBasicAPI[1117:36348] synchSerial------end}/* *  同步并发   --->       阻塞当前线程,不开多条线程,在当前线程执行,顺序执行 */- (void)synchConcurrent{    // 全局并发队列    //    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);    // 自定义并发队列    dispatch_queue_t queue1 = dispatch_queue_create("COM.MKJ.COM", DISPATCH_QUEUE_CONCURRENT);    dispatch_sync(queue1, ^{        NSLog(@"------1,%@",[NSThread currentThread]);    });    dispatch_sync(queue1, ^{        NSLog(@"------2,%@",[NSThread currentThread]);    });    dispatch_sync(queue1, ^{        NSLog(@"------3,%@",[NSThread currentThread]);    });    NSLog(@"synchConcurrent------end");//    2016-12-21 09:29:47.575 GCDBasicAPI[1071:33607] ------1,<NSThread: 0x60000006b900>{number = 1, name = main}//    2016-12-21 09:29:47.575 GCDBasicAPI[1071:33607] ------2,<NSThread: 0x60000006b900>{number = 1, name = main}//    2016-12-21 09:29:47.576 GCDBasicAPI[1071:33607] ------3,<NSThread: 0x60000006b900>{number = 1, name = main}//    2016-12-21 09:29:47.576 GCDBasicAPI[1071:33607] synchConcurrent------end}/* *  异步并发   --->       不阻塞当前线程,可以开多条线程,并发执行,顺序不一定 */- (void)asynchConcurrent{    // 全局并发队列//    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);    // 自定义并发队列    dispatch_queue_t queue1 = dispatch_queue_create("COM.MKJ.COM", DISPATCH_QUEUE_CONCURRENT);    dispatch_async(queue1, ^{        NSLog(@"------1,%@",[NSThread currentThread]);    });    dispatch_async(queue1, ^{        NSLog(@"------2,%@",[NSThread currentThread]);    });    dispatch_async(queue1, ^{        NSLog(@"------3,%@",[NSThread currentThread]);    });    NSLog(@"asynchConcurrent------end");//    2016-12-21 09:28:23.895 GCDBasicAPI[1050:32223] asynchConcurrent------end//    2016-12-21 09:28:23.895 GCDBasicAPI[1050:32292] ------1,<NSThread: 0x60800026e180>{number = 3, name = (null)}//    2016-12-21 09:28:23.895 GCDBasicAPI[1050:32293] ------3,<NSThread: 0x60800026fbc0>{number = 5, name = (null)}//    2016-12-21 09:28:23.895 GCDBasicAPI[1050:32295] ------2,<NSThread: 0x60000026e0c0>{number = 4, name = (null)}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125

简单概括如下:

项目同步(sync)异步(async)串行当前线程,顺序执行另一个线程,顺序执行并发当前线程,顺序执行另一个线程,同时执行

可以看出同步和异步就是开线程的能力,同步执行必然一个个顺序执行在当前线程,而异步执行可以根据队列不同来确定顺序还是同步并发执行

2.最基本的线程间通讯方式

// 不阻塞当前线程,后台拉取图片资源    dispatch_async(dispatch_get_global_queue(0, 0), ^{        NSURL *url = [NSURL URLWithString:@"https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcRCfHVwGXGvrpCBplQieSKsLgfBULL8ZZXSzosPFdoZsvjDlqnOrKK_w58"];        NSData *data = [NSData dataWithContentsOfURL:url];        UIImage *image = [UIImage imageWithData:data];        NSLog(@"获取资源%@",[NSThread currentThread]);        // 下载完之后回到主线程        dispatch_async(dispatch_get_main_queue(), ^{            self.imageView.image = image;            NSLog(@"加载资源%@",[NSThread currentThread]);        });    });    //    2016-12-21 09:43:51.675 GCDBasicAPI[1237:45972] 获取资源<NSThread: 0x6000002742c0>{number = 3, name = (null)}    //    2016-12-21 09:43:51.676 GCDBasicAPI[1237:45929] 加载资源<NSThread: 0x60000007b680>{number = 1, name = main}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

3.其他Barrier,apply,after,Group等常用API

  • dispatch_barrier_async
/* *  barrier函数可以阻塞任务,执行到他这里,要等之前的任务执行完才能执行之后的任务 */- (void)barrier{    dispatch_queue_t queue = dispatch_queue_create("com.mkj.hehe", DISPATCH_QUEUE_CONCURRENT);    dispatch_async(queue, ^{        NSLog(@"--------1,%@",[NSThread currentThread]);    });    dispatch_async(queue, ^{        for (NSInteger i = 0; i < 10; i ++)        {           NSLog(@"--------2%ld,%@",i,[NSThread currentThread]);        }    });    dispatch_barrier_async(queue, ^{        NSLog(@"--------3,%@",[NSThread currentThread]);    });    dispatch_async(queue, ^{        NSLog(@"--------4,%@",[NSThread currentThread]);    });    dispatch_async(queue, ^{        NSLog(@"--------5,%@",[NSThread currentThread]);    });//    2016-12-21 09:58:09.231 GCDBasicAPI[1392:57437] --------1,<NSThread: 0x60000007f400>{number = 5, name = (null)}//    2016-12-21 09:58:09.231 GCDBasicAPI[1392:57807] --------20,<NSThread: 0x60000007e780>{number = 7, name = (null)}//    2016-12-21 09:58:09.232 GCDBasicAPI[1392:57807] --------21,<NSThread: 0x60000007e780>{number = 7, name = (null)}//    2016-12-21 09:58:09.233 GCDBasicAPI[1392:57807] --------22,<NSThread: 0x60000007e780>{number = 7, name = (null)}//    2016-12-21 09:58:09.233 GCDBasicAPI[1392:57807] --------23,<NSThread: 0x60000007e780>{number = 7, name = (null)}//    2016-12-21 09:58:09.233 GCDBasicAPI[1392:57807] --------24,<NSThread: 0x60000007e780>{number = 7, name = (null)}//    2016-12-21 09:58:09.233 GCDBasicAPI[1392:57807] --------25,<NSThread: 0x60000007e780>{number = 7, name = (null)}//    2016-12-21 09:58:09.233 GCDBasicAPI[1392:57807] --------26,<NSThread: 0x60000007e780>{number = 7, name = (null)}//    2016-12-21 09:58:09.234 GCDBasicAPI[1392:57807] --------27,<NSThread: 0x60000007e780>{number = 7, name = (null)}//    2016-12-21 09:58:09.234 GCDBasicAPI[1392:57807] --------28,<NSThread: 0x60000007e780>{number = 7, name = (null)}//    2016-12-21 09:58:09.234 GCDBasicAPI[1392:57807] --------29,<NSThread: 0x60000007e780>{number = 7, name = (null)}//    2016-12-21 09:58:09.234 GCDBasicAPI[1392:57807] --------3,<NSThread: 0x60000007e780>{number = 7, name = (null)}//    2016-12-21 09:58:09.235 GCDBasicAPI[1392:57807] --------4,<NSThread: 0x60000007e780>{number = 7, name = (null)}//    2016-12-21 09:58:09.235 GCDBasicAPI[1392:57437] --------5,<NSThread: 0x60000007f400>{number = 5, name = (null)}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • dispatch_apply
/* *  apply 无序快速遍历,可以用于文件移动等需求 */- (void)apply{    dispatch_apply(10, dispatch_get_global_queue(0, 0), ^(size_t index) {        NSLog(@"%ld,%@",index,[NSThread currentThread]);    });//    2016-12-21 10:04:01.487 GCDBasicAPI[1485:63041] 0,<NSThread: 0x600000069940>{number = 1, name = main}//    2016-12-21 10:04:01.487 GCDBasicAPI[1485:63172] 2,<NSThread: 0x60800007a940>{number = 7, name = (null)}//    2016-12-21 10:04:01.487 GCDBasicAPI[1485:63845] 1,<NSThread: 0x60800007a8c0>{number = 6, name = (null)}//    2016-12-21 10:04:01.487 GCDBasicAPI[1485:63873] 3,<NSThread: 0x60800007ab00>{number = 8, name = (null)}//    2016-12-21 10:04:01.487 GCDBasicAPI[1485:63041] 4,<NSThread: 0x600000069940>{number = 1, name = main}//    2016-12-21 10:04:01.488 GCDBasicAPI[1485:63172] 5,<NSThread: 0x60800007a940>{number = 7, name = (null)}//    2016-12-21 10:04:01.488 GCDBasicAPI[1485:63845] 6,<NSThread: 0x60800007a8c0>{number = 6, name = (null)}//    2016-12-21 10:04:01.488 GCDBasicAPI[1485:63873] 7,<NSThread: 0x60800007ab00>{number = 8, name = (null)}//    2016-12-21 10:04:01.488 GCDBasicAPI[1485:63041] 8,<NSThread: 0x600000069940>{number = 1, name = main}//    2016-12-21 10:04:01.488 GCDBasicAPI[1485:63172] 9,<NSThread: 0x60800007a940>{number = 7, name = (null)}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • dispatch_after
/* *  延时执行 */ - (void)delay{    // 方法1    NSLog(@"开始了");    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0*NSEC_PER_SEC)), dispatch_get_main_queue(), ^{        NSLog(@"我才开始");    });    // 方法2    [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:NO];}- (void)run{    NSLog(@"run");}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • dispatch_group_async
/* *  线程组  实现多个请求完成之后同时刷新UI的问题 *  把多个任务加入到队列里面,最后都完成之后会调用Notify的方法进行通知,最终刷新UI */- (void)group{    // 并发队列    dispatch_queue_t queue = dispatch_queue_create("com.mkj.hh", DISPATCH_QUEUE_CONCURRENT);    // 线程组    dispatch_group_t group = dispatch_group_create();    // 任务1加入组    dispatch_group_async(group, queue, ^{        NSURL *url = [NSURL URLWithString:@"https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcQxex7CvJ0pArQ8NHwXMaZ8fSt3ALAZBlljTQVlDsh6AIegeMjWWMoSVtej"];        NSData *data = [NSData dataWithContentsOfURL:url];        self.image1 = [UIImage imageWithData:data];    });    // 任务2加入组    dispatch_group_async(group, queue, ^{        // 这里可以一样是耗时的网络请求,暂时处理成本地的        self.image2 = [UIImage imageNamed:@"Play"];    });    // 任务完成之后统一通知    dispatch_group_notify(group, queue, ^{        // 这里的queue如果是mainQueue的话就可以直接回到主线程操作需要的UI        // 现在还是在并发队列里面  进行图片合成  还是放在子线程        UIGraphicsBeginImageContext(CGSizeMake([UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.width));        [self.image1 drawInRect:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.width)];        [self.image2 drawInRect:CGRectMake([UIScreen mainScreen].bounds.size.width/2, [UIScreen mainScreen].bounds.size.width/2, 30, 40)];        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();        UIGraphicsEndImageContext();        // 回到主线程刷新UI        dispatch_async(dispatch_get_main_queue(), ^{            self.imageView.image = image;        });    });}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

这里写图片描述 

4.两种方式实现单例

  • 自己加锁实现
static id obj;+ (instancetype)shareInstance{    @synchronized (self) {        if (!obj) {            obj = [[self alloc] init];        }    }    return obj;}+ (instancetype)allocWithZone:(struct _NSZone *)zone{    @synchronized (self) {        if (!obj) {            obj = [super allocWithZone:zone];        }    }    return obj;}- (id)copyWithZone:(NSZone *)zone{    return obj;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • GCD实现(直接抽成宏)
#define MKJSingletonH + (instancetype)shareManager;#define MKJSinletonM \static id obj; \ \+ (instancetype)shareManager \{ \    static dispatch_once_t onceToken; \    dispatch_once(&onceToken, ^{ \        obj = [[self alloc] init]; \    }); \    return obj; \} \ \+ (instancetype)allocWithZone:(struct _NSZone *)zone \{ \    static dispatch_once_t onceToken; \    dispatch_once(&onceToken, ^{ \        obj = [super allocWithZone:zone]; \    }); \    return obj; \} \ \- (id)copyWithZone:(NSZone *)zone \{ \    return obj; \}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

抽成宏之后可以直接进行调用就OK

@interface ManagerHelper : NSObjectMKJSingletonH@end@implementation ManagerHelperMKJSinletonM@end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

注:这里为什么需要用Static进行修饰,static保证只有本文件才能访问,这样就能形成单例,但是如果不用static修饰,外部也一样能访问,这个时候外部如果置为nil之后,这个对象就不存在了,再也不会创建了,dispatch_once只会执行一次,这样肯定不对的



非常简单的介绍,这里有个Demo,需要的朋友可以下载看看基础用法先,文章头部有介绍GCD死锁解锁的案例文章,需要的也可以看看 
本文Demo传送门

0 0