在程序开发中如果要用到线程,第一反应非GCD莫属。感觉只需要弄懂任务,和队列两个概念,一般问题就会迎刃而解。
同步:会阻塞当前线程,直到Block任务结束。
异步:它不会阻塞当前线程。
队列主要分为两种:串行和并行
串行:放到串行的任务,GCD会取出一个,等到这个执行结束,再取出下一个。
并行:放到并行的任务,GCD也是一个一个取出来,但是他不同的是,会把这些任务放到别的线程,速度很快,快到我们以为是同时取出来的。不过需要注意,GCD 会根据系统资源控制并行的数量,所以如果任务很多,它并不会让所有任务同时执行。
系统给我们提供了一个串行队列:
dispatch_queue_t mainqueue = dispatch_get_main_queue();
我向这个队列添加了一个提交了一个串行任务
NSLog(@"同步开始------%@",[NSThread currentThread]);
dispatch_sync(mainqueue, ^{
NSLog(@"%@",[NSThread currentThread]);
});
NSLog(@"同步结束------%@",[NSThread currentThread]);
打印结果如下:
[5330:2817984] 同步开始------{number = 1, name = main}
同步任务会阻塞当前线程的执行,直到该任务结束,否则线程都会一直堵塞下去。很不巧的是,此时GCD不会开辟新的线程,它会把任务放到主线程中执行。因为主线程已经堵塞,该任务也就永远不会被完成。造成这种死锁的原因就是:线程在等待同步任务的完成,而线程确被卡死,这就是所谓的相互等待。令我感到迷惑的是:另外一种串行和同步的结合,我们也可以自己创造串行队列:
dispatch_queue_t queue1 = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL);//这里有两个参数第一个参数是代表队列的唯一标示,可以传空,第二个参数表示创建的队列是串行的还是并行的,传入 DISPATCH_QUEUE_SERIAL 或 NULL 表示创建串行队列。
NSLog(@"同步开始------%@",[NSThread currentThread]);
dispatch_sync(queue1, ^{
NSLog(@"%@",[NSThread currentThread]);
});
NSLog(@"同步结束------%@",[NSThread currentThread]);
打印结果;
同步开始------<NSThread:0x13fd0dba0>{number = 1, name = main}
<NSThread:0x13fd0dba0>{number = 1, name = main}
同步结束------<NSThread:0x13fd0dba0>{number = 1, name = main}
错误理解:我以为这种也会造成死锁,结果很明显没有。都是串行队列,提交任务,不同的是一种是主队列,它用于刷新 UI。一种是手动创建的。让人疑惑的是[NSThread currentThread]打印的地址是一样的,让我误以为queue1这种队列,也是将任务提交给了当前执行队列。
正确理解:经过大神的开导,地址一致只不过是线程的重用而已,这两种队列是将任务提交给了不同线程。线程的死锁用大神的话来讲就是dispatch_sync的当前执行队列和提交Block任务的队列一致的时候才会发生。至于Block输出的的线程是主线程,只不过是线程池里面线程的重用。感谢这位作者对GCD的解释