多线程代码执行先后的顺序问题

  • 前言
    • 多线程代码执行先后的是怎样的呢?我认为执行代码的先后顺序最外层的dispatch_sync(同步)和dispatch_async(异步)。究竟是不是这样呢?就让我来做以下验证吧。

1、同步(串行/并行)队列

- (void)viewDidLoad {
    [super viewDidLoad];
    [self test];
}

/** 输出
 *  DISPATCH_QUEUE_CONCURRENT : 1 2 3 4 13 14 7 8 5 6
 
 *  DISPATCH_QUEUE_SERIAL: 1 2 3 4 13 14 7 8 5 6
 */
- (void)test{
    NSLog(@"ming -- 1");
    NSLog(@"ming -- 2");
//                                                              DISPATCH_QUEUE_SERIAL
    dispatch_queue_t queue = dispatch_queue_create("mingming2", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_sync(queue, ^{
        NSLog(@"ming -- 3");
        NSLog(@"ming -- 4");
        NSLog(@"ming -- 13");
        NSLog(@"ming -- 14");
        
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"ming -- 5");
            [NSThread sleepForTimeInterval:5.0];
            NSLog(@"ming -- 6");
        });
        NSLog(@"ming -- 7");
    });
    NSLog(@"ming -- 8");
    NSLog(@"+=====+++++++++++++=============+++++++++++++++++++++++++====");
}
test结果.png

2、异步全局队列

- (void)viewDidLoad {
    [super viewDidLoad];
    [self test2];
}

/** 输出
 *  1 2 8 3 4 7 5 6
 */
- (void)test2{
    NSLog(@"ming -- 1");
    NSLog(@"ming -- 2");
    
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"ming -- 3");
        NSLog(@"ming -- 4");
        
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"ming -- 5");
            [NSThread sleepForTimeInterval:5.0];
            NSLog(@"ming -- 6");
        });
        NSLog(@"ming -- 7" );
    });
    NSLog(@"ming -- 8");
    NSLog(@"+=====+++++++++++++=============+++++++++++++++++++++++++====");
}
test2结果.png
  • 补充两张dispatch_async图片:



打印.png
  • 总结:异步同时执行,并没有明显的先后顺序之分。

3、同步全局队列

- (void)viewDidLoad {
    [super viewDidLoad];
    [self test3];
}

/** 输出
 *  1 2 3 4 7 8 5 6
 */
- (void)test3{
    NSLog(@"ming -- 1");
    NSLog(@"ming -- 2");
    
    dispatch_sync(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"ming -- 3");
        NSLog(@"ming -- 4");
        
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"ming -- 5");
            [NSThread sleepForTimeInterval:5.0];
            NSLog(@"ming -- 6");
        });
        NSLog(@"ming -- 7");
    });
    NSLog(@"ming -- 8");
}
test3结果.png

总结,通过三处代码。通过同步/异步、串行/并发(全局/主线程)的组合,可以看出,执行代码的先后顺序最外层的dispatch_sync(同步)和dispatch_async(异步)。

  • dispatch_sync(同步)——同步的话就按顺序执行,先执行最外层的dispatch_sync的代码,再执行NSLog(@"ming -- 8");,最后执行 dispatch_async(dispatch_get_main_queue(), ^{代码});里面的代码。

  • dispatch_async(异步)——异步的话就不按顺序执行,先执行NSLog(@"ming -- 8");,再执行最外层的dispatch_async的代码,最后执行 dispatch_async(dispatch_get_main_queue(), ^{代码});里面的代码。

  • Tip

值得注意的是dispatch_sync(同步)的时候,如果是

dispatch_sync(dispatch_get_global_queue(0, 0), ^{
     dispatch_sync(dispatch_get_main_queue(), ^{});
}

这种情况,在同步线程执行主队列,会造成死锁.如下图代码所示:

dispatch_sync(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"ming -- 3");

        dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@"ming -- 5");
            [NSThread sleepForTimeInterval:5.0];
            NSLog(@"ming -- 6");
        });
        NSLog(@"ming -- 7");
    });

推荐阅读更多精彩内容