1.向并行队列提交同步任务,(根据显示结果可知:所有任务全部在主线程执行,所有任务都是按顺序执行的)
//线程与线程之间的执行速度可能是不确定的 //1. 创建一个并行队列 dispatch_queue_t concurrentQueue = dispatch_queue_create("com.concurrentQueue", DISPATCH_QUEUE_CONCURRENT); //并行队列中提交多个异步任务,任务的顺序不能确定 //同步提交任务任务的顺序可以确定 dispatch_sync(concurrentQueue, ^{ if ([NSThread isMainThread]) { NSLog(@"主线程"); }else{ NSLog(@"非主线程"); } for (int i = 0; i < 100; i++) { NSLog(@"任务一:%d", i); } }); NSLog(@"---1---"); dispatch_sync(concurrentQueue, ^{ if ([NSThread isMainThread]) { NSLog(@"主线程"); }else{ NSLog(@"非主线程"); } for (int i = 0; i < 100; i++) { NSLog(@"任务二:%d", i); } }); NSLog(@"---2---"); dispatch_sync(concurrentQueue, ^{ if ([NSThread isMainThread]) { NSLog(@"主线程"); }else{ NSLog(@"非主线程"); } for (int i = 0; i < 100; i++) { NSLog(@"任务三:%d", i); } }); NSLog(@"---3---");
2.向并行队列提交异步任务(根据结果:所有任务都是在非主线程中执行的,而且任务执行的顺序是不确定的)
//并行队列中提交多个异步任务,任务的顺序不能确定 dispatch_async(concurrentQueue, ^{ if ([NSThread isMainThread]) { NSLog(@"主线程"); }else{ NSLog(@"非主线程"); } for (int i = 0; i < 100; i++) { NSLog(@"任务一:%d", i); } }); NSLog(@"---1---"); dispatch_async(concurrentQueue, ^{ if ([NSThread isMainThread]) { NSLog(@"主线程"); }else{ NSLog(@"非主线程"); } for (int i = 0; i < 100; i++) { NSLog(@"任务二:%d", i); } }); NSLog(@"---2---"); dispatch_async(concurrentQueue, ^{ if ([NSThread isMainThread]) { NSLog(@"主线程"); }else{ NSLog(@"非主线程"); } for (int i = 0; i < 100; i++) { NSLog(@"任务三:%d", i); } }); NSLog(@"---3---");
1.向串行队列同步提交任务(从结果可知:所有任务都在主线程中执行,所有任务都是按顺序执行的)
//1. 创建串行队列,一个串行队列对应一个线程 //1.1. 第一个参数是队列的名称 //1.2. 第二个参数是队列的类型,NULL表示串行队列 dispatch_queue_t serialQueue = dispatch_queue_create("com.serialQueue", DISPATCH_QUEUE_SERIAL); //2. 如果任务在不同的线程中执行,那么它们的执行顺序是不确定的 dispatch_sync(serialQueue, ^{ if ([NSThread isMainThread]) { NSLog(@"主线程"); }else{ NSLog(@"非主线程"); } for (int i = 0; i < 100; i++) { NSLog(@"任务一:%d", i); } }); NSLog(@"---1---"); dispatch_sync(serialQueue, ^{ if ([NSThread isMainThread]) { NSLog(@"主线程"); }else{ NSLog(@"非主线程"); } for (int i = 0; i < 100; i++) { NSLog(@"任务二:%d", i); } }); NSLog(@"---2---"); dispatch_sync(serialQueue, ^{ if ([NSThread isMainThread]) { NSLog(@"主线程"); }else{ NSLog(@"非主线程"); } for (int i = 0; i < 100; i++) { NSLog(@"任务三:%d", i); } }); NSLog(@"---3---");
2.向串行队列提交异步任务(从结果可知:所有的任务都是在非主线程中执行的,所有的任务都是按顺序执行的)
dispatch_async(serialQueue, ^{ if ([NSThread isMainThread]) { NSLog(@"主线程"); }else{ NSLog(@"非主线程"); } for (int i = 0; i < 100; i++) { NSLog(@"任务一:%d", i); } }); NSLog(@"---1---"); dispatch_async(serialQueue, ^{ if ([NSThread isMainThread]) { NSLog(@"主线程"); }else{ NSLog(@"非主线程"); } for (int i = 0; i < 100; i++) { NSLog(@"任务二:%d", i); } }); NSLog(@"---2---"); dispatch_async(serialQueue, ^{ if ([NSThread isMainThread]) { NSLog(@"主线程"); }else{ NSLog(@"非主线程"); } for (int i = 0; i < 100; i++) { NSLog(@"任务三:%d", i); } }); NSLog(@"---3---");
结果对比:
1.不管是串行队列还是并行队列,同步提交任务都是在主线程中执行的,异步提交任务都是在非主线程中执行的(这里相对于3.4来讲的)
2.并行队列的任务,如果不在同一线程,可以与主线程同时执行,主线程中的任务优先其他线程的任务执行,但不排除其他线程的任务和主线程的任务同时间进行
3.同步提交任务,任务所在的线程与提交任务所在的线程是一样的
4.异步提交任务,任务所在的线程与提交任务所在的线程是不一样的
5.同一线程,所有任务都是先进先出按顺序来的(串行同步,并行同步都在主线程)
6.串行异步,任务在同一个线程,任务所在的线程与提交任务所在的线程是不一样的(所以出现任务一和主线程的任务先执行,任务二和任务三后执行,因为任务一二三在同一个线程)
7.并行异步,任务在不同线程,任务所在的线程与提交任务所在的线程是不一样的(所以出现任务和主线程的任务都是同时执行)
所以根据上面的总结可以体会到,任务的执行顺序和会不会阻塞,我门只需要判断清楚任务所在的线程就可以了,不同线程可以同时执行,同一线程只能按顺序执行
最后只需记住多个任务同时执行用: 并行异步 两个任务同时执行用:串行异步 所有任务按先后顺序执行 :串行同步,并行同步 但是这里只是相对于一个线程编程的时候,比如主线程,如果在主线程里面创建一个其他的线程,然后同步提交任务,我们是不是也可以实现两个甚至是多个任务同时运行了,这个还有待验证
概念这里参考 http://www.mamicode.com/info-detail-1010323.html 为了不麻烦就直接复制粘贴了
首先明确一下“同步&异步”“串行&并发”这两组基本概念:
同步执行:比如这里的dispatch_sync,这个函数会把一个block加入到指定的队列中,而且会一直等到执行完blcok,这个函数才返回。因此在block执行完之前,调用dispatch_sync方法的线程是阻塞的。
与之对应的就有“异步执行”的概念:
异步执行:一般使用dispatch_async,这个函数也会把一个block加入到指定的队列中,但是和同步执行不同的是,这个函数把block加入队列后不等block的执行就立刻返回了。
接下来看一看另一组相对的概念:“串行&并发”
串行队列:比如这里的dispatch_get_main_queue。这个队列中所有任务,一定按照先来后到的顺序执行。不仅如此,还可以保 证在执行某个任务时,在它前面进入队列的所有任务肯定执行完了。对于每一个不同的串行队列,系统会为这个队列建立唯一的线程来执行代码。
与之相对的是并发队列:
并发队列:比如使用dispatch_get_global_queue。这个队列中的任务也是按照先来后到的顺序开始执行,注意是开始,但是它们的执行结束时间是不确定的,取决于每个任务的耗时。对于n个并发队列,GCD不会创建对应的n个线程而是进行适当的优化
总结一下,到底什么是死锁。首先,虽然刚刚我们提到了队列和线程,以及它们之间的对应关系,但是死锁一定是针对线程 而言的,队列只是GCD给出的抽象数据结构。所谓的死锁,一定是发生在一个或多个线程之间的。那么死锁和线程阻塞的关系呢,可以这么理解,双向的阻塞导致 了死锁。因为阻塞是线程中经常发生的事情,最多就是主线程的阻塞影响了用户体验。而一旦出现了双向的阻塞,就导致了死锁。我们可以看到,主线程是串行的, 在执行某一个任务的时候线程被阻塞了,而这个任务(dispatch_sync)在执行时,又要求阻塞主线程,从而导致了互相的阻塞,也就是死锁
分析:如果阻塞时间过长久会形成“界面假死”,如果双向阻塞就会形成死锁,这两种情况的形成我们就不考虑异步提交了,因为异步提交是根本不会形成阻塞,所以我们只看同步提交的情况
//1. 主队列里的任务一定在主线程上执行 //2. 不应该在主线程中执行耗时的任务,否则会导致主线程阻塞,从而使界面“假死” dispatch_queue_t concurrentQueue = dispatch_queue_create("com.concurrentQueue", DISPATCH_QUEUE_CONCURRENT); dispatch_queue_t serialQueue = dispatch_queue_create("com.serialQueue", DISPATCH_QUEUE_SERIAL); dispatch_queue_t mainQueue = dispatch_get_main_queue(); dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0); dispatch_sync(concurrentQueue, ^{ if ([NSThread isMainThread]) { NSLog(@"主线程"); }else{ NSLog(@"非主线程"); } //获取当前时间,秒钟 CFAbsoluteTime begin = CFAbsoluteTimeGetCurrent(); //整个管理文件或者文件夹 [[NSFileManager defaultManager] copyItemAtPath:@"/Users/zhouzhi/百度云同步盘/电子专业书籍" toPath:@"/Users/zhouzhi/Desktop/电子书" error:nil]; //获取结束时间点 CFAbsoluteTime end = CFAbsoluteTimeGetCurrent(); //打印消耗的时间 NSLog(@"%.2f秒", end - begin); }); NSLog(@"任务执行完成了");
除了同步提交任务到mainQueue会形成死锁,其他都是界面假死
看到这个结果,到这里我已经云里雾里了,为什么mainQueue会形成死锁,其他的没有形成死锁,我提交任务在主线程进行,然后任务的执行也是在主线程执行,为什么没形成死锁而是阻塞
还有上面的“串行同步”,“并行同步”提交任务和任务运行也都是在主线程中进行的,为什么还可以按顺序执行,求解答,我到底错在了哪里,难道我这整个想法都是错的?