开发技术文章

ios多线程同步异步、串行并行队列、死锁

2018-08-01  本文已影响0人  CharmecarWang

队列

概念:队列只负责任务的调度,而不负责任务的执行,任务是在线程中执行的。(可以理解成任务是放在队列里面的,要被调度到线程中去执行)
特点:队列先进先出,排在前面的任务最先执行。
分类:队列分为串行、并行、主队列、全局队列。

任务的执行是在线程上去执行的。分为同步和异步。

所以就可以分成:串行队列同步执行、串行队列异步执行、并行队列同步执行、并行队列异步执行。

GCD实现原理:
GCD有一个底层线程池,这个池中存放的是一个个的线程。之所以称为“池”,是因为这个“池”中的线程是可以重用的,当一段时间后没有任务在这个线程上执行的话,这个线程就会被销毁。注意:开多少条线程是由底层线程池决定的(线程建议控制再3~5条),池是系统自动来维护,不需要我们程序员来维护。
我们只关心的是向队列中添加任务,队列调度即可。

死锁

定义:调用方法(viewDidLoad)的队列(主队列)恰好是同步操作(dispatch_sync)所针对的队列(dispatch_get_main_queue)。
示例1:

NSLog(@"1"); // 任务1
dispatch_sync(dispatch_get_main_queue(), ^{
    NSLog(@"2"); // 任务2
});
NSLog(@"3"); // 任务3

输出结果:

1

dispatch_sync 和 dispatch_async 区别:
dispatch_async(queue,block) async 异步队列,dispatch_async 函数会立即返回, block会在后台异步执行。
dispatch_sync(queue,block) sync 同步队列,dispatch_sync 函数不会立即返回,及阻塞当前线程,等待 block同步执行完成。

以上例子就会死锁,因为viewDidLoad的这个任务是被主队列调用的的,而dispatch_sync不会立即返回,而是先阻塞当前的主线程,直到这个block执行完毕,因为主线程被阻碍了,啥也干不了了(只有一个线程还被阻塞了,就会造成死锁),所以这个block就永远没有机会执行了,所以就会造成死锁。

示例2:

- (void)viewDidLoad {
    [super viewDidLoad];    
    NSLog(@"1");
    dispatch_async(dispatch_get_main_queue(0, 0), ^{
        NSLog(@"2");
    });
    NSLog(@"3");
}

输出结果:

1
3
2

示例2就不会造成死锁,因为dispatch_async会立即返回,所以会先输出3,而异步会创建一个新的线程来执行block块,所以2最后输出。但是2和3的顺序不一定。

示例3:

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    NSLog(@"1");//任务1
    dispatch_sync(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"2");//任务2
    });
    NSLog(@"3");//任务3
}

输出结果:

1
2
3

示例3也不会造成死锁,因为dispatch_sync不会立即返回,而是先阻塞主线程,再将任务2加入到一个全局队列的一个线程上去执行,执行完之后返回到主队列,此时主线程不在阻塞,再继续执行任务3。
示例4:

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    NSLog(@"1");//任务1
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"2");//任务2
        dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@"3");//任务3
        });
        NSLog(@"5");//任务5
    });
    NSLog(@"4");//任务4
}

输出结果:

1
4
2
3
5

因为dispatch_async不会等待,所以顺序是1-4-2-3-5或1-2-4-3-5,其中任务1和4是在主线程执行的,而2是在全局队列上被调用的,执行完2之后,会阻塞当前的线程(全局队列上的),紧接着把任务3放在主线程执行,执行完之后再回到主队列,此时主队列上的线程已经不阻塞了,所以就会继续执行任务5.

注意:线程同步阻塞后不一定能造成死锁,还要看看还有没有其他线程去执行那个block,如果能有,就能解锁阻塞的线程,继续执行任务。如果没有,那就是死锁了。

参考链接

上一篇 下一篇

猜你喜欢

热点阅读