串行任务

场景:现有3个耗时任务A,B,C 需要依次有序执行。
分析:为了不阻塞主线程,只能异步依次执行任务A,B,C

方式一:GCD串行队列 实现串行任务

特点:只需开启一个线程,串行执行多个任务

//创建串行队列  (DISPATCH_QUEUE_SERIAL:串行) (DISPATCH_QUEUE_CONCURRENT:并发)
dispatch_queue_t  queue = dispatch_queue_create("com.fw.queue", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        sleep(1);
        NSLog(@"任务A  thread:%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        sleep(1);
        NSLog(@"任务B  thread:%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        sleep(1);
        NSLog(@"任务C  thread:%@",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{    
        dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@"任务执行完毕,回到主线程 thread:%@",[NSThread currentThread]); 
        });
        
    });
    NSLog(@"结束");

打印结果

结束
2017-08-24 11:34:28.368057+0800 UIViewTest[27526:7523798] 结束
2017-08-24 11:34:29.376597+0800 UIViewTest[27526:7524243] 任务A  thread:<NSThread: 0x170279080>{number = 5, name = (null)}
2017-08-24 11:34:30.379257+0800 UIViewTest[27526:7524243] 任务B  thread:<NSThread: 0x170279080>{number = 5, name = (null)}
2017-08-24 11:34:31.384996+0800 UIViewTest[27526:7524243] 任务C  thread:<NSThread: 0x170279080>{number = 5, name = (null)}
2017-08-24 11:34:31.385371+0800 UIViewTest[27526:7523798] 任务执行完毕,回到主线程 thread:<NSThread: 0x17007a240>{number = 1, name = main}

可以看出任务A,B,C 是在同一个线程中,被一次执行的。执行完毕后,又可以回到主线程。

方式二:GCD后台线程+条件锁 实现串行任务

特点:需开启多个线程,利用条件锁依次执行

NSConditionLock  *lock = [[NSConditionLock alloc]initWithCondition:1];

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    
    [lock lockWhenCondition:3];
    sleep(1);
    NSLog(@"任务C  thread:%@",[NSThread currentThread]);
    [lock unlockWithCondition:4];
});

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    
    [lock lockWhenCondition:2];
    sleep(1);
    NSLog(@"任务B  thread:%@",[NSThread currentThread]);
    [lock unlockWithCondition:3];
});

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    
    [lock lockWhenCondition:1];
    sleep(1);
    NSLog(@"任务A  thread:%@",[NSThread currentThread]);
    [lock unlockWithCondition:2];
    
});

NSLog(@"结束");

打印结果

2017-08-24 11:42:39.911399+0800 UIViewTest[27529:7528485] 结束
2017-08-24 11:42:40.919128+0800 UIViewTest[27529:7528837] 任务A  thread:<NSThread: 0x170274e80>{number = 6, name = (null)}
2017-08-24 11:42:41.924922+0800 UIViewTest[27529:7528592] 任务B  thread:<NSThread: 0x170274600>{number = 7, name = (null)}
2017-08-24 11:42:42.926247+0800 UIViewTest[27529:7528836] 任务C  thread:<NSThread: 0x170263f00>{number = 8, name = (null)}

可以看出,任务A,B,C是按顺序执行的,每个任务都是在不同的线程中执行的。

方式三:NSOperationQueue

特点:若果添加依赖关系,那么多个任务在同一个线程中完成。如果没有依赖关系,那么多个任务在多个线程中完成

NSOperationQueue  *queue = [[NSOperationQueue alloc]init];


NSBlockOperation *opA = [NSBlockOperation blockOperationWithBlock:^{
    sleep(1);
    NSLog(@"任务A  thread:%@",[NSThread currentThread]);
}];

NSBlockOperation *opB = [NSBlockOperation blockOperationWithBlock:^{
    sleep(1);
    NSLog(@"任务B  thread:%@",[NSThread currentThread]);
}];

NSBlockOperation *opC = [NSBlockOperation blockOperationWithBlock:^{
    sleep(1);
    NSLog(@"任务C  thread:%@",[NSThread currentThread]);
}];

//添加依赖关系,保证执行顺序
[opC addDependency:opB];
[opB addDependency:opA];

 [queue addOperation:opB];
 [queue addOperation:opC];
 [queue addOperation:opA];

执行结果

2017-08-24 13:03:50.129224+0800 UIViewTest[27599:7554889] 任务A  thread:<NSThread: 0x170064480>{number = 3, name = (null)}
2017-08-24 13:03:51.132080+0800 UIViewTest[27599:7554889] 任务B  thread:<NSThread: 0x170064480>{number = 3, name = (null)}
2017-08-24 13:03:52.133824+0800 UIViewTest[27599:7554889] 任务C  thread:<NSThread: 0x170064480>{number = 3, name = (null)}
并发任务

特点:开启多条线程,同时执行多个任务。

方式一:采用dispatch_group,可以获取所有任务执行完毕的通知

场景:同时执行三个任务,所有任务执行完毕后,调用者可以得到通知。
dispatch_group是GCD的一项特性,能够给任务分组。调用者可以等待这组任务执行完毕,也可以在提供回调函数之后继续往下执行。这组任务完成时,调用者会得到通知。

//创建分组
dispatch_group_t dispatchGroup = dispatch_group_create();
//获取队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//添加并发任务
for (int i=1; i<=3; i++) {
    
    dispatch_group_async(dispatchGroup, queue, ^{
        
        sleep(1);
        NSLog(@"任务%d  thread:%@",i,[NSThread currentThread]);
    });
}
//任务执行完毕后,获取通知
dispatch_group_notify(dispatchGroup, queue, ^{
    
    NSLog(@"执行完毕  thread:%@",[NSThread currentThread]);
    
});

打印结果

2017-08-24 14:15:26.971016+0800 UIViewTest[27661:7571605] 任务1  thread:<NSThread: 0x170070d40>{number = 3, name = (null)}
2017-08-24 14:15:26.971405+0800 UIViewTest[27661:7571541] 任务2  thread:<NSThread: 0x170070d00>{number = 4, name = (null)}
2017-08-24 14:15:26.971735+0800 UIViewTest[27661:7571606] 任务3  thread:<NSThread: 0x170064440>{number = 5, name = (null)}
2017-08-24 14:15:26.971984+0800 UIViewTest[27661:7571606] 执行完毕  thread:<NSThread: 0x170064440>{number = 5, name = (null)}

从结果可以看出,最后的一个任务3执行完毕后,接着在同一个线程里,通知了调用者,所有任务执行完毕。

方式二:利用并发队列,直接执行并发任务

特点:不能获取所有任务执行完毕的通知

//串行:DISPATCH_QUEUE_SERIAL
//并发 DISPATCH_QUEUE_CONCURRENT

dispatch_queue_t  queue = dispatch_queue_create("com.fw.queue", DISPATCH_QUEUE_CONCURRENT);

dispatch_async(queue, ^{
    sleep(1);
    NSLog(@"任务A  thread:%@",[NSThread currentThread]);
});

dispatch_async(queue, ^{
    sleep(1);
    NSLog(@"任务B  thread:%@",[NSThread currentThread]);
});

dispatch_async(queue, ^{
    sleep(1);
    NSLog(@"任务C  thread:%@",[NSThread currentThread]);
});
NSLog(@"结束");

上面代码中的queue 也可以用GCD常用后台线程替换

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

打印结果

2017-08-24 14:33:35.523264+0800 UIViewTest[27666:7575286] 结束
2017-08-24 14:33:36.530702+0800 UIViewTest[27666:7575315] 任务A  thread:<NSThread: 0x17026f240>{number = 3, name = (null)}
2017-08-24 14:33:36.531057+0800 UIViewTest[27666:7575311] 任务B  thread:<NSThread: 0x17026f280>{number = 4, name = (null)}
2017-08-24 14:33:36.531344+0800 UIViewTest[27666:7575314] 任务C  thread:<NSThread: 0x17026f180>{number = 5, name = (null)}

可以看出三个任务,都在同一时刻完成