面试遇到的GCD的两个问题

  1. 以下代码在主线程调用,结果是什么?
NSLog("之前 - %@", NSThread.currentThread()) 
dispatch_sync(dispatch_get_main_queue(), { () -> Void in 
        NSLog("sync - %@", NSThread.currentThread()) 
})
 NSLog("之后 - %@", NSThread.currentThread())

答案:
只会打印第一句:之前- <NSThread: 0x7fb3a9e16470>{number = 1, name = main},然后主线程就卡死了,你可以在界面上放一个按钮,你就会发现点不了了。
解释
同步任务会阻塞当前线程,然后把 Block 中的任务放到指定的队列中执行,只有等到 Block 中的任务完成后才会让当前线程继续往下运行。
那么这里的步骤就是:打印完第一句后,dispatch_sync 立即阻塞当前的主线程,然后把 Block 中的任务放到 main_queue 中,可是 main_queue 中的任务会被取出来放到主线程中执行,但主线程这个时候已经被阻塞了,所以 Block 中的任务就不能完成,它不完成,dispatch_sync 就会一直阻塞主线程,这就是死锁现象。导致主线程一直卡死。

  1. 以下代码会产生什么结果?
let queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL) 
NSLog("之前 - %@", NSThread.currentThread()) 
dispatch_async(queue, { () -> Void in 
    NSLog("sync之前 - %@", NSThread.currentThread()) 
    dispatch_sync(queue, { () -> Void in 
        NSLog("sync - %@", NSThread.currentThread()) 
    }) 
    NSLog("sync之后 - %@", NSThread.currentThread()) 
}) 
NSLog("之后 - %@", NSThread.currentThread())

答案:
2017-04-11 10:06:51.058 test[33329:8793087] 之前 - <NSThread: 0x7fe32050dbb0>{number = 1, name = main}
2017-04-11 10:06:51.059 test[33329:8793356] sync之前 - <NSThread: 0x7fe32062e9f0>{number = 2, name = (null)}
2017-04-11 10:06:51.059 test[33329:8793087] 之后 - <NSThread: 0x7fe32050dbb0>{number = 1, name = main}
很明显 sync - %@sync之后 - %@没有被打印出来!这是为什么呢?我们再来分析一下:

分析

  1. 使用 DISPATCH_QUEUE_SERIAL 这个参数,创建了一个 串行队列。

  2. 打印出 之前- %@这句。

  3. dispatch_async 异步执行,所以当前线程不会被阻塞,于是有了两条线程,一条当前线程继续往下打印出 之后 - %@这句, 另一台执行 Block 中的内容打印 sync之前 - %@ 这句。因为这两条是并行的,所以打印的先后顺序无所谓。

  4. 注意,重点来了。现在的情况和上一个例子一样了。dispatch_sync同步执行,于是它所在的线程会被阻塞,一直等到sync里的任务执行完才会继续往下。于是sync 就高兴的把自己 Block中的任务放到 queue中,可谁想 queue 是一个串行队列,一次执行一个任务,所以 syncBlock必须等到前一个任务执行完毕,可万万没想到的是 queue正在执行的任务就是被 sync阻塞了的那个。于是又发生了死锁。所以sync所在的线程被卡死了。剩下的两句代码自然不会打印。

推荐阅读更多精彩内容