线程之GCD

今天看了看线程,发现自己对线程还不是很了解,于是练了练手算是学习学习,iOS中线程一共分为四种:Pthread,NSThread,GCD 和 NSOperation.
Pthread基本不用,很多系统中都支持,iOS中也支持.但是基本不用.

NSThread我还很菜,也许是我知道的不多,我所知道的确实不难,具体有啥,在Xcode中点进去看看里面的属性和方法一目了然,这里多说一句在swift中,Thread取消了Perform.......的自启动方法.

GCD:根据目前本菜鸟所学,需要注意的关键点为队列(queue),任务,组(group).队列分串行队列(DISPATCH_QUEUE_SERIAL)和并行队列(DISPATCH_QUEUE_CONCURRENT) 任务分为同步(sync)和异步(async)

1.异步执行,并发队列

- (void)GCDasyncConcurrentThread {
    dispatch_queue_t queue1 = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue1, ^{
        NSLog(@"%@",[NSThread currentThread]);
//        NSLog(@"%@",[NSThread currentThread]);

        dispatch_async(queue1, ^{
            NSLog(@"zzz%@",[NSThread currentThread]);
        });
        NSLog(@"after1");
    });
    
    dispatch_async(queue1, ^{
        NSLog(@"%@",[NSThread currentThread]);
//        NSLog(@"%@",[NSThread currentThread]);

        dispatch_async(queue1, ^{
            NSLog(@"zzz%@",[NSThread currentThread]);
        });
        NSLog(@"after2");
    });
    
    dispatch_async(queue1, ^{
        NSLog(@"%@",[NSThread currentThread]);
//        NSLog(@"%@",[NSThread currentThread]);

        dispatch_async(queue1, ^{
            NSLog(@"zzz%@",[NSThread currentThread]);
        });
        NSLog(@"after3");
    });
    
    NSLog(@"after");
} 
2017-01-24 13:15:46.738 GCD学习[3445:112733] <NSThread: 0x6100000711c0>{number = 3, name = (null)}
2017-01-24 13:15:46.738 GCD学习[3445:112735] <NSThread: 0x61800006be40>{number = 5, name = (null)}
2017-01-24 13:15:46.738 GCD学习[3445:112732] <NSThread: 0x60000006f640>{number = 4, name = (null)}
2017-01-24 13:15:46.738 GCD学习[3445:112697] after
2017-01-24 13:15:46.738 GCD学习[3445:112733] after1
2017-01-24 13:15:46.738 GCD学习[3445:112761] zzz<NSThread: 0x6080000725c0>{number = 6, name = (null)}
2017-01-24 13:15:46.738 GCD学习[3445:112735] after3
2017-01-24 13:15:46.738 GCD学习[3445:112732] after2
2017-01-24 13:15:46.738 GCD学习[3445:112762] zzz<NSThread: 0x608000072440>{number = 7, name = (null)}
2017-01-24 13:15:46.738 GCD学习[3445:112763] zzz<NSThread: 0x60000006f580>{number = 8, name = (null)}

并发异步执行,会开启线程,并且队列中线程的执行顺序不确定,多写几个耗时不同的线程会发现,当开启新线程之前会检查当前队列中是否存在闲置线程 ,如果有闲置线程,便用闲置线程执行要执行的操作,如果没有闲置线程便新开一条线程。

2.异步执行 串行队列

//GCD 异步执行 串行队列 产生新线程   同一队列只会产生一个线程
- (void)GCDasyncSrialThread {
    NSLog(@"before");
    dispatch_queue_t queue = dispatch_queue_create("", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        NSLog(@"now:1");
        [NSThread currentThread].name = @"thread1";
        NSLog(@"%@",[NSThread currentThread]);
    });

    dispatch_async(queue, ^{
        NSLog(@"now:2");
        NSLog(@"%@",[NSThread currentThread]);
        dispatch_async(queue, ^{
            NSLog(@"now:4");
            NSLog(@"%@",[NSThread currentThread]);
        });
    });
    
    dispatch_async(queue, ^{
        NSLog(@"now:3");
        NSLog(@"%@",[NSThread currentThread]);
    });
    NSLog(@"after");
    NSLog(@"%@",[NSThread currentThread]);
}
2017-01-24 13:26:12.327 GCD学习[3537:116874] before
2017-01-24 13:26:12.328 GCD学习[3537:116874] after
2017-01-24 13:26:12.328 GCD学习[3537:116923] now:1
2017-01-24 13:26:12.328 GCD学习[3537:116874] <NSThread: 0x6000000682c0>{number = 1, name = main}
2017-01-24 13:26:12.328 GCD学习[3537:116923] <NSThread: 0x61000006cac0>{number = 3, name = thread1}
2017-01-24 13:26:12.328 GCD学习[3537:116923] now:2
2017-01-24 13:26:12.328 GCD学习[3537:116923] <NSThread: 0x61000006cac0>{number = 3, name = thread1}
2017-01-24 13:26:12.329 GCD学习[3537:116923] now:3
2017-01-24 13:26:12.329 GCD学习[3537:116923] <NSThread: 0x61000006cac0>{number = 3, name = thread1}
2017-01-24 13:26:12.329 GCD学习[3537:116923] now:4
2017-01-24 13:26:12.329 GCD学习[3537:116923] <NSThread: 0x61000006cac0>{number = 3, name = thread1}

一个串行队列中执行异步操作只会产生一个子线程,并且所有执行的异步操作先进入队列的先操作,后进入队列的后操作。此处now4实在子线程中开辟一条新线程,如果将now4的异步(async)改为同步(sync)程序会崩溃,产生线程阻塞,同步执行不会产生新线程,后面后提到.

3.同步执行 串行队列

//GCD 同步执行 串行队列 不产生新线程   线程阻塞
- (void)GCDsyncSrialThread {
    dispatch_queue_t queue = dispatch_queue_create("", DISPATCH_QUEUE_SERIAL);
    NSLog(@"before");
    dispatch_sync(queue, ^{
        
        NSLog(@"now1");
        [NSThread currentThread].name = @"thread1";
        NSLog(@"%@",[NSThread currentThread]);
    });
    
    dispatch_sync(queue, ^{
        
//        dispatch_sync(queue, ^{
//            NSLog(@"now4");
//            NSLog(@"%@",[NSThread currentThread]);
//        });
        
        NSLog(@"now2");
        NSLog(@"%@",[NSThread currentThread]);
    });
    
    dispatch_sync(queue, ^{
        NSLog(@"now3");
        NSLog(@"%@",[NSThread currentThread]);
    });
    NSLog(@"after");
}
2017-01-24 13:48:36.036 GCD学习[3729:125159] before
2017-01-24 13:48:36.036 GCD学习[3729:125159] now1
2017-01-24 13:48:36.036 GCD学习[3729:125159] <NSThread: 0x6000000778c0>{number = 1, name = thread1}
2017-01-24 13:48:36.036 GCD学习[3729:125159] now2
2017-01-24 13:48:36.036 GCD学习[3729:125159] <NSThread: 0x6000000778c0>{number = 1, name = thread1}
2017-01-24 13:48:36.037 GCD学习[3729:125159] now3
2017-01-24 13:48:36.037 GCD学习[3729:125159] <NSThread: 0x6000000778c0>{number = 1, name = thread1}
2017-01-24 13:48:36.037 GCD学习[3729:125159] after

串行队列中同步执行任务,不会产生新的子线程,并且执行顺序为先进入队列的任务先执行,后进入队列的后执行,前一个任务未完成不会进入后一个任务,所以上面代码中被注掉的部分打开运行时会卡在此处,产生线程阻塞.原因是因为在队列中,now4加入队列需要等待now2线程执行完才能进行,而now2中后面的语句执行要在now4执行后执行,这是互相等待都不执行就产生了线程阻塞.将now4的同步(sync)改为异步(async)就可以解决线程阻塞问题.但在实际开发中问题的解决并非这么简单,要考虑实际情况以及任务执行顺序.上面提到的线程阻塞也是相互等待产生的问题

4.同步执行 并行队列

//GCD 同步执行 并行队列 不产生新线程
- (void)GCDsyncConcurrentThread {
    dispatch_queue_t queue = dispatch_queue_create("", DISPATCH_QUEUE_CONCURRENT);
    
    NSLog(@"before");
    dispatch_sync(queue, ^{
        [NSThread currentThread].name = @"thread1";
        NSLog(@"now:1");
        NSLog(@"%@",[NSThread currentThread]);
    });
    
    dispatch_sync(queue, ^{
        NSLog(@"now:2");
        NSLog(@"%@",[NSThread currentThread]);
        
        dispatch_sync(queue, ^{
            NSLog(@"now:4");
            NSLog(@"%@",[NSThread currentThread]);
        });
    });
    
    dispatch_sync(queue, ^{
        NSLog(@"now:3");
        NSLog(@"%@",[NSThread currentThread]);
    });
    NSLog(@"after");
    NSLog(@"%@",[NSThread currentThread]);
}
2017-01-24 14:03:28.900 GCD学习[3904:132214] before
2017-01-24 14:03:28.900 GCD学习[3904:132214] now:1
2017-01-24 14:03:28.900 GCD学习[3904:132214] <NSThread: 0x608000066e00>{number = 1, name = thread1}
2017-01-24 14:03:28.900 GCD学习[3904:132214] now:2
2017-01-24 14:03:28.900 GCD学习[3904:132214] <NSThread: 0x608000066e00>{number = 1, name = thread1}
2017-01-24 14:03:28.901 GCD学习[3904:132214] now:4
2017-01-24 14:03:28.901 GCD学习[3904:132214] <NSThread: 0x608000066e00>{number = 1, name = thread1}
2017-01-24 14:03:28.901 GCD学习[3904:132214] now:3
2017-01-24 14:03:28.901 GCD学习[3904:132214] <NSThread: 0x608000066e00>{number = 1, name = thread1}
2017-01-24 14:03:28.901 GCD学习[3904:132214] after
2017-01-24 14:03:28.901 GCD学习[3904:132214] <NSThread: 0x608000066e00>{number = 1, name = thread1}

并行队列 同步执行不会产生新线程, 所有任务按代码顺序执行,在并同步任务中添加同步任务,可以在上层任务未完成时执行内部任务,可以想象为遇到什么事情 就解决什么事,不分进入队列时间,一切按执行过程走.

5.GCD 队列组

//GCD 队列组
- (void)GCDgroup{
    dispatch_group_t group = dispatch_group_create();
    
    dispatch_queue_t queue1 = dispatch_queue_create("", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_queue_t queue2 = dispatch_queue_create("", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_queue_t queue3 = dispatch_queue_create("", DISPATCH_QUEUE_SERIAL);

    dispatch_group_async(group, queue1, ^{
        NSLog(@"1");
    });
    dispatch_group_async(group, queue2, ^{
        NSLog(@"2");
    });
    dispatch_group_async(group, queue2, ^{
        NSLog(@"3");
    });
    dispatch_group_async(group, queue1, ^{
        NSLog(@"4");
    });
    dispatch_group_async(group, queue1, ^{
        NSLog(@"5");
    });
    dispatch_group_async(group, queue2, ^{
        NSLog(@"6");
    });
    dispatch_group_async(group, queue2, ^{
        NSLog(@"7");
    });
    dispatch_group_async(group, queue3, ^{
        NSLog(@"8");
    });
    dispatch_group_async(group, queue3, ^{
        NSLog(@"9");
    });
    dispatch_group_notify(group, queue1, ^{
        NSLog(@"wan");
    });
}
2017-01-24 15:01:17.948 GCD学习[4371:151987] 2
2017-01-24 15:01:17.948 GCD学习[4371:151971] 1
2017-01-24 15:01:17.948 GCD学习[4371:151972] 8
2017-01-24 15:01:17.948 GCD学习[4371:151974] 4
2017-01-24 15:01:17.948 GCD学习[4371:151990] 3
2017-01-24 15:01:17.948 GCD学习[4371:151991] 5
2017-01-24 15:01:17.948 GCD学习[4371:151992] 6
2017-01-24 15:01:17.949 GCD学习[4371:151993] 7
2017-01-24 15:01:17.949 GCD学习[4371:151987] 9
2017-01-24 15:01:17.949 GCD学习[4371:151993] wan

队列组中装的是队列,组中所有队列执行结束会执行dispatch_group_notify(<#dispatch_group_t _Nonnull group#>, <#dispatch_queue_t _Nonnull queue#>, <#^(void)block#>)

队列组中还有一些其他的API,如
dispatch_group_enter(dispatch_group_t group);在组内加入执行代码块 与leave要同时出现 不然会crash.
dispatch_group_leave(dispatch_group_t group);
dispatch_group_wait(dispatch_group_t group, dispatch_time_t timeout);检查组内任务多久之后是否完成是否完成,如果完成,返回值为0,否则不为0如:
dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5*NSEC_PER_SEC));设定等待5秒,观察五秒后是否组内任务全部完成,如果未完成继续执行组内任务 返回非0数继续执行,如果在5秒内完成则返回0,继续后续执行.所以此API无论返回什么,并不影响程序运行.
dispatch_apply API是sync与group的关联,将block中的执行加入到queue中关联一个组. iterations重复次数,queue队列,和带残block,index为每次任务标号,无序执行.可无序遍历容器类.

dispatch_apply(10, queue3, ^(size_t index) {
        
    });```
还有dispatch_after 延迟操作,延迟多久在哪个队列中执行什么操作.
dispatch_once 只执行一次的操作,可用于单例.在类方法中

static Class class = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
class = [[Class alloc]init];
});
return class;

还有另外一种单例写法,和两种的严格与不严格形式,啥时候有遇到相关内容再带一下吧.都很简单.
GCD功能无比强大,脑洞打开后,拥有无限可能.学的很肤浅,技术还很渣,仍需努力,继续革命.
第二篇渣文出炉.
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容