多线程

2018-09-10  本文已影响4人  曹来东

iOS中的常见多线程方案

image.png

GCD的常用函数

GCD中有2个用来执行任务的函数

dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);

queue:队列; block:任务

dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

GCD的队列

GCD的队列可以分为2大类型

容易混淆的术语

有4个术语比较容易混淆:同步、异步、并发、串行

各种队列的执行效果

image.png

使用sync函数往当前串行队列中添加任务,会卡住当前的串行队列(产生死锁)

队列组的使用

思考:如何用gcd实现以下功能

  1. 异步并发执行任务1、任务2
  2. 等任务1、任务2都执行完毕后,再回到主线程执行任务3
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    
    //创建队列组
    dispatch_group_t group = dispatch_group_create();
    //创建并发队列
    dispatch_queue_t queue = dispatch_queue_create("queueGroup", DISPATCH_QUEUE_CONCURRENT);
    //添加异步函数
    dispatch_group_async(group, queue, ^{
    
        for (int i = 0; i < 5; i++) {
            NSLog(@"任务一%d == %@",i,[NSThread currentThread]);
        }
        
    });
    
    dispatch_group_async(group, queue, ^{
        
        for (int i = 0; i < 5; i++) {
            NSLog(@"任务二%d == %@",i,[NSThread currentThread]);
        }
        
    });
    //前两个异步任务执行完成,会自动唤醒,执行当前任务
    dispatch_group_notify(group, queue, ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            for (int i = 0; i < 5; i++) {
                NSLog(@"任务三%d == %@",i,[NSThread currentThread]);
            }
        });
        
    });
//同义代码
//前两个异步任务执行完成,会自动唤醒,执行当前任务
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            for (int i = 0; i < 5; i++) {
                NSLog(@"任务三%d == %@",i,[NSThread currentThread]);
            }
        });
}
//打印结果
 任务二0 == <NSThread: 0x60400027c080>{number = 4, name = (null)}
 任务一0 == <NSThread: 0x608000274400>{number = 3, name = (null)}
 任务二1 == <NSThread: 0x60400027c080>{number = 4, name = (null)}
 任务一1 == <NSThread: 0x608000274400>{number = 3, name = (null)}
 任务二2 == <NSThread: 0x60400027c080>{number = 4, name = (null)}
任务一2 == <NSThread: 0x608000274400>{number = 3, name = (null)}
任务二3 == <NSThread: 0x60400027c080>{number = 4, name = (null)}
任务一3 == <NSThread: 0x608000274400>{number = 3, name = (null)}
任务二4 == <NSThread: 0x60400027c080>{number = 4, name = (null)}
任务一4 == <NSThread: 0x608000274400>{number = 3, name = (null)}
任务三0 == <NSThread: 0x604000263a00>{number = 1, name = main}
任务三1 == <NSThread: 0x604000263a00>{number = 1, name = main}
任务三2 == <NSThread: 0x604000263a00>{number = 1, name = main}
任务三3 == <NSThread: 0x604000263a00>{number = 1, name = main}
任务三4 == <NSThread: 0x604000263a00>{number = 1, name = main}

//前两个异步任务执行完成,会自动唤醒,异步执行任务三四
    dispatch_group_notify(group, queue, ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            for (int i = 0; i < 5; i++) {
                NSLog(@"任务三%d == %@",i,[NSThread currentThread]);
            }
        });
        
    });
    
    dispatch_group_notify(group, queue, ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            for (int i = 0; i < 5; i++) {
                NSLog(@"任务四%d == %@",i,[NSThread currentThread]);
            }
        });
        
    });

面试题

image.png
- (void)test{
    NSLog(@"2");
}
- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"1");
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_async(queue, ^{
        [self performSelector:@selector(test) withObject:nil afterDelay:.0];
        //NSPort可以不添加,因为在NSRunLoop中已经添加了定时器.
        [[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSRunLoopCommonModes];
        //只需要执行run就可以了
        [[NSRunLoop currentRunLoop] run];
    });
    NSLog(@"3");
}

打印结果为1,且Crash

- (void)test{
    NSLog(@"2");
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    NSThread * thread = [[NSThread alloc] initWithBlock:^{
        NSLog(@"1");
    }];
    [thread start];
    [self performSelector:@selector(test) onThread:thread withObject:nil waitUntilDone:YES];
}

修改代码,但是又产生了新问题

- (void)test{
    NSLog(@"2");
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    NSThread * thread = [[NSThread alloc] initWithBlock:^{
        NSLog(@"1");
        //[[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];
        //RunLoop会执行一次,停止的时候只需要停止当次runLoop即可
        //        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
        //        //RunLoop会一直运行,无法停止;
        //        [[NSRunLoop currentRunLoop] run];
    }];
    [thread start];
    
    //上面代码执行完,runloop当中没有source observer timer runloop就会退出
    //线程就会销毁.再次使用该线程执行test方法就会Crash
    [self performSelector:@selector(test) onThread:thread withObject:nil waitUntilDone:NO];
    //如果传参数为NO,为什么不会crash
}
上一篇下一篇

猜你喜欢

热点阅读