这两天撸了撸多线程,对苹果的这套c语言框架gcd很感兴趣,索性撸下去,发现撸的时候很多概念傻傻分不清楚,鉴于我这跟鱼一样的记忆力,要记忆一下
1.最先接触的概念肯定是进程和线程,what?进程和线程还需要记忆,那么别搞it了,不过还是要阐述一下,进程就像一个个运行着的程序,线程就是程序内部代码的执行路线,如果程序中有多个代码的执行路线,那么就涉及多线程了。
2.操作队列,搞这么个东西很容易让人误解为队列就是线程,但是其实不是,这个玩意只是一个队列(FIFO),队列里面放的是任务,也就是代码。
3.主队列,主队列并没有什么神奇,它也是操作队列,只不过它是由系统创建的队列,是类似串行队列,优先级很高
全局队列,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);,与并行队列类似,但是无法确定是哪个队列。
4.同步任务,同步任务的优先级高,并且在同一个队列中有执行顺序,必须等同步任务执行完了才会执行后续的任务,有可能会阻塞线程。
5.异步任务,异步任务的优先级低,等系统比较闲了没什么事做的时候就会执行它,在队列中没有执行顺序,不会阻塞线程。
6.串行队列,这个串行队列,本质上也是队列,加上“串行”二字,就说明串行队列要像电路中串并联的串联一样,任务要一个挨一个的执行,不管你这个任务是异步的还是同步的。
7.并行队列,本质也是队列,加上“并行”二字,就说明并行队列像并联电路一样,任务可以(同时)执行,这里的同时并非真正意义上的同时,具体的解释在操作系统里面的cpu工作方式上有阐述,我们只要关心它类似“同时”,可以达到“同时”执行的效果就可以了。
那么问题来了,队列与任务的组合关系:
1.串行 + 同步
串行队列中的任务是一个挨一个执行,同步任务也是有执行顺序,也要一个挨一个执行,所以得出的结论是,串行队列中的同步任务要一个挨一个执行
dispatch_queue_t q1 = dispatch_queue_create("串行队列", DISPATCH_QUEUE_SERIAL);
dispatch_sync(q1, ^{
[NSThread sleepForTimeInterval:5];
NSLog(@"串行队列同步任务1 %@",[NSThread currentThread]);
});
dispatch_sync(q1, ^{
NSLog(@"串行队列同步任务2 %@",[NSThread currentThread]);
});
dispatch_sync(q1, ^{
NSLog(@"串行队列同步任务3 %@",[NSThread currentThread]);
});
打印结果:
2014-12-09 17:43:55.991 多线程test[4696:942016] 串行队列同步任务1 <NSThread: 0x7fac3bc24860>{number = 1, name = main}
2014-12-09 17:43:55.992 多线程test[4696:942016] 串行队列同步任务2 <NSThread: 0x7fac3bc24860>{number = 1, name = main}
2014-12-09 17:43:55.992 多线程test[4696:942016] 串行队列同步任务3 <NSThread: 0x7fac3bc24860>{number = 1, name = main}
很容易发现问题,串行队列中的同步任务会自动加入到主线程中,并且会阻塞主线程,任务完成后才会更新UI
2.串行 + 异步
串行队列任务要一个挨一个执行,异步任务无顺序,这两个组合在一起,要遵循队列的规则,也就是说,不管你是同步还是异步,需要遵守队列的规则,所以任务也是要一个挨一个有顺序执行。
dispatch_queue_t q1 = dispatch_queue_create("串行队列", DISPATCH_QUEUE_SERIAL);
dispatch_async(q1, ^{
[NSThread sleepForTimeInterval:5];
NSLog(@"串行队列异步任务1 %@",[NSThread currentThread]);
});
dispatch_async(q1, ^{
NSLog(@"串行队列异步任务2 %@",[NSThread currentThread]);
});
dispatch_async(q1, ^{
NSLog(@"串行队列异步任务3 %@",[NSThread currentThread]);
});
打印结果:
2014-12-09 17:49:54.906 多线程test[4834:957312] 串行队列异步任务1 <NSThread: 0x7fa35bd13750>{number = 2, name = (null)}
2014-12-09 17:49:54.907 多线程test[4834:957312] 串行队列异步任务2 <NSThread: 0x7fa35bd13750>{number = 2, name = (null)}
2014-12-09 17:49:54.907 多线程test[4834:957312] 串行队列异步任务3 <NSThread: 0x7fa35bd13750>{number = 2, name = (null)}
很容易看出问题,串行队列的异步任务确实也是按顺序执行的,但是它不会进入主线程中,不会阻塞主线程,先更新UI,后显示结果。
3.串行 + 同步 + 异步
dispatch_queue_t q1 = dispatch_queue_create("串行队列", DISPATCH_QUEUE_SERIAL);
dispatch_async(q1, ^{
NSLog(@"串行队列异步任务1 %@",[NSThread currentThread]);
});
dispatch_sync(q1, ^{
[NSThread sleepForTimeInterval:5];
NSLog(@"串行队列同步任务2 %@",[NSThread currentThread]);
});
dispatch_async(q1, ^{
NSLog(@"串行队列异步任务3 %@",[NSThread currentThread]);
});
打印结果:
2014-12-09 17:56:56.339 多线程test[5117:972472] 串行队列异步任务1 <NSThread: 0x7fc4217564f0>{number = 2, name = (null)}
2014-12-09 17:57:01.342 多线程test[5117:972174] 串行队列同步任务2 <NSThread: 0x7fc421416db0>{number = 1, name = main}
2014-12-09 17:57:01.342 多线程test[5117:972472] 串行队列异步任务3 <NSThread: 0x7fc4217564f0>{number = 2, name = (null)}
很容易发现问题,有异步有同步,还是要遵守串行队列的任务顺序来执行,但是执行到同步任务时依然会加入到主线程,并且阻塞主线程,影响UI显示。
4. 串行 + 同步(嵌套异步)
dispatch_queue_t q1 = dispatch_queue_create("串行队列", DISPATCH_QUEUE_SERIAL);
dispatch_sync(q1, ^{
NSLog(@"串行队列同步任务1 %@",[NSThread currentThread]);
[NSThread sleepForTimeInterval:5];
dispatch_async(q1, ^{
NSLog(@"串行队列异步任务2 %@",[NSThread currentThread]);
});
});
打印结果:
2014-12-09 18:01:12.259 多线程test[5276:982408] 串行队列同步任务1 <NSThread: 0x7fa56a516280>{number = 1, name = main}
2014-12-09 18:01:17.262 多线程test[5276:982631] 串行队列异步任务2 <NSThread: 0x7fa56a712aa0>{number = 2, name = (null)}
很容易看出问题,任务仍然顺序执行,正常。
5.串行 + 异步(嵌套同步)
dispatch_queue_t q1 = dispatch_queue_create("串行队列", DISPATCH_QUEUE_SERIAL);
dispatch_async(q1, ^{
NSLog(@"串行队列异步任务1 %@",[NSThread currentThread]);
dispatch_sync(q1, ^{
NSLog(@"串行队列同步任务2 %@",[NSThread currentThread]);
});
});
打印结果:
2014-12-09 18:04:03.168 多线程test[5389:990941] 串行队列异步任务1 <NSThread: 0x7fa399599d40>{number = 2, name = (null)}
问题来了,任务2没有执行,结果并不是我粘贴少了,程序确实执行到这里就阻塞住不再执行了,下面我们来分析一下原因
串行队列需要按照顺序执行,那么任务1要先执行完,才可以执行任务2,但是任务1里面又有一个同步的任务2,同步任务不会开辟新线程,会自动加入主线程,这样任务2永远都无法执行到,任务2不执行任务1就永远不会结束,任务1不结束,任务2就不会执行.....(开启唐三藏模式)
6.主队列 + 同步
dispatch_queue_t q = dispatch_get_main_queue();
dispatch_sync(q, ^{
NSLog(@"主队列同步任务1 %@",[NSThread currentThread]);
});
打印结果无
主队列是一个运行循环,如果加入同步任务,会造成主队列阻塞,程序会锁死,(再次开启唐三藏模式),运行循环不结束,不执行同步任务,同步任务不执行,运行循环不结束...。
7.主队列 + 异步
dispatch_queue_t q = dispatch_get_main_queue();
dispatch_async(q, ^{
NSLog(@"主队列异步任务1 %@",[NSThread currentThread]);
});
dispatch_async(q, ^{
NSLog(@"主队列异步任务2 %@",[NSThread currentThread]);
});
dispatch_async(q, ^{
NSLog(@"主队列异步任务3 %@",[NSThread currentThread]);
});
打印结果:
2014-12-10 13:34:13.427 多线程test[1570:369316] 主队列异步任务1 <NSThread: 0x7fc9a2611fc0>{number = 1, name = main}
2014-12-10 13:34:13.427 多线程test[1570:369316] 主队列异步任务2 <NSThread: 0x7fc9a2611fc0>{number = 1, name = main}
2014-12-10 13:34:13.428 多线程test[1570:369316] 主队列异步任务3 <NSThread: 0x7fc9a2611fc0>{number = 1, name = main}
主队列的异步任务等同于同步任务,异步和同步是针对主线程来说的,那么在主线程上跑的任务肯定都是有顺序的。
8.并行 + 同步
dispatch_queue_t q = dispatch_queue_create("并行队列", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(q, ^{
NSLog(@"并行队列同步任务1 %@",[NSThread currentThread]);
});
dispatch_sync(q, ^{
NSLog(@"并行队列同步任务2 %@",[NSThread currentThread]);
});
dispatch_sync(q, ^{
NSLog(@"并行队列同步任务3 %@",[NSThread currentThread]);
});
打印结果:
2014-12-10 13:38:51.408 多线程test[1709:378774] 并行队列同步任务1 <NSThread: 0x7fb7ca516520>{number = 1, name = main}
2014-12-10 13:38:51.409 多线程test[1709:378774] 并行队列同步任务2 <NSThread: 0x7fb7ca516520>{number = 1, name = main}
2014-12-10 13:38:51.409 多线程test[1709:378774] 并行队列同步任务3 <NSThread: 0x7fb7ca516520>{number = 1, name = main}
按顺序执行。
9. 并行 + 异步
dispatch_queue_t q = dispatch_queue_create("并行队列", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(q, ^{
NSLog(@"并行队列异步任务1 %@",[NSThread currentThread]);
});
dispatch_async(q, ^{
NSLog(@"并行队列异步任务2 %@",[NSThread currentThread]);
});
dispatch_async(q, ^{
NSLog(@"并行队列异步任务3 %@",[NSThread currentThread]);
});
打印结果:
2014-12-10 13:40:52.680 多线程test[1754:384474] 并行队列异步任务1 <NSThread: 0x7fe9087034f0>{number = 4, name = (null)}
2014-12-10 13:40:52.680 多线程test[1754:384476] 并行队列异步任务3 <NSThread: 0x7fe90863c660>{number = 3, name = (null)}
2014-12-10 13:40:52.680 多线程test[1754:384475] 并行队列异步任务2 <NSThread: 0x7fe9084792a0>{number = 2, name = (null)}
开启多个线程,任务无顺序,并发执行
10.并行 + 同步(嵌套异步)
dispatch_queue_t q = dispatch_queue_create("并行队列", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(q, ^{
NSLog(@"并行队列同步任务1 %@",[NSThread currentThread]);
dispatch_async(q, ^{
NSLog(@"并行队列异步任务2 %@",[NSThread currentThread]);
});
});
打印结果:
2014-12-10 13:43:34.638 多线程test[1831:391846] 并行队列同步任务1 <NSThread: 0x7fddd3d281f0>{number = 1, name = main}
2014-12-10 13:43:34.639 多线程test[1831:391864] 并行队列异步任务2 <NSThread: 0x7fddd3c0a4e0>{number = 2, name = (null)}
并发执行。
11.并发 + 异步(嵌套同步)
dispatch_queue_t q = dispatch_queue_create("并行队列", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(q, ^{
NSLog(@"并行队列异步任务1 %@",[NSThread currentThread]);
dispatch_sync(q, ^{
NSLog(@"并行队列同步任务2 %@",[NSThread currentThread]);
});
dispatch_sync(q, ^{
NSLog(@"并行队列同步任务3 %@",[NSThread currentThread]);
});
dispatch_sync(q, ^{
NSLog(@"并行队列同步任务4 %@",[NSThread currentThread]);
});
dispatch_sync(q, ^{
NSLog(@"并行队列同步任务5 %@",[NSThread currentThread]);
});
dispatch_sync(q, ^{
NSLog(@"并行队列同步任务6 %@",[NSThread currentThread]);
});
});
打印结果:
2014-12-10 13:51:42.396 多线程test[2409:421421] 并行队列异步任务1 <NSThread: 0x7f9cebf0dab0>{number = 2, name = (null)}
2014-12-10 13:51:42.396 多线程test[2409:421421] 并行队列同步任务2 <NSThread: 0x7f9cebf0dab0>{number = 2, name = (null)}
2014-12-10 13:51:42.396 多线程test[2409:421421] 并行队列同步任务3 <NSThread: 0x7f9cebf0dab0>{number = 2, name = (null)}
2014-12-10 13:51:42.396 多线程test[2409:421421] 并行队列同步任务4 <NSThread: 0x7f9cebf0dab0>{number = 2, name = (null)}
2014-12-10 13:51:42.397 多线程test[2409:421421] 并行队列同步任务5 <NSThread: 0x7f9cebf0dab0>{number = 2, name = (null)}
2014-12-10 13:51:42.397 多线程test[2409:421421] 并行队列同步任务6 <NSThread: 0x7f9cebf0dab0>{number = 2, name = (null)}
并行队列 + A异步任务 (嵌套B同步) 这时B同步任务会和父任务也就是A任务同步到同一个线程上去。(经过这个研究可以证明,所有在主队列中的任务都会加到主线程,异步任务是在cpu空闲的时候执行,任务默认都不会开新线程,只有串行队列加异步会开1个线程、并行加异步会开n个线程、全局加异步会加n个线程)
全局同并发...
总结出暴力记忆法,这里面主要要理解好,队列,线程,同步,异步的概念。
暴力记忆法:主队列任务都在主线程,性质同串行。
异步任务等cpu空闲执行。
任务不会开线程,串行加异步开一个线程,并行加异步开n个线程,全局同并行。
串行加任意任务嵌套同步任务会死锁,其他队列不执行,主队列阻塞程序。
摘抄网友的一些解释,觉得很到位:
ios三种多线程技术:
1.NSThread
(1)使用NSThread对象建立一个线程非常方便
(2)但是!要使用NSThread管理多个线程非常困难,不推荐使用
(3)技巧!使用[NSThread currentThread]跟踪任务所在线程,适用于这三种技术
2.NSOperation/NSOperationQueue
(1)是使用GCD实现的一套Objective-C的API
(2)是面向对象的线程技术
(3)提供了一些在GCD中不容易实现的特性,如:限制最大并发数量、操作之间的依赖关系
3.GCD —— Grand Central Dispatch
(1)是基于C语言的底层API
(2)用Block定义任务,使用起来非常灵活便捷
(3)提供了更多的控制能力以及操作队列中所不能使用的底层函数
1---- 队列和线程的区别:
队列:是管理线程的,相当于线程池,能管理线程什么时候执行。
队列分为串行队列和并行队列等
串行队列:队列中的线程按顺序执行(不会同时执行)
并行队列:队列中的线程会并发执行,可能会有一个疑问,队列不是先进先出吗,如果后面的任务执行完了,怎么出去的了。这里需要强调下,任务执行完毕了,不一定出队列。只有前面的任务执行完了,才会出队列。
2----- 主线程队列和GCD创建的队列也是有区别的。
主线程队列和GCD创建的队列是不同的。在GCD中创建的队列优先级没有主队列高,所以在GCD中的串行队列开启同步任务里面没有嵌套任务是不会阻塞主线程,只有一种可能导致死锁,就是串行队列里,嵌套开启任务,有可能会导致死锁。
主线程队列中不能开启同步,会阻塞主线程。只能开启异步任务,开启异步任务也不会开启新的线程,只是降低异步任务的优先级,让cpu空闲的时候才去调用。而同步任务,会抢占主线程的资源,会造成死锁。
3----- 线程:里面有非常多的任务(同步,异步)
同步与异步的区别:
同步任务优先级高,在线程中有执行顺序,不会开启新的线程。
异步任务优先级低,在线程中执行没有顺序,看cpu闲不闲。在主队列中不会开启新的线程,其他队列会开启新的线程。
4----主线程队列注意:
下面代码执行顺序
1111
2222
主队列异步 <NSThread: 0x8e12690>{name = (null), num = 1}
在主队列开启异步任务,不会开启新的线程而是依然在主线程中执行代码块中的代码。为什么不会阻塞线程?
> 主队列开启异步任务,虽然不会开启新的线程,但是他会把异步任务降低优先级,等闲着的时候,就会在主线程上执行异步任务。
在主队列开启同步任务,为什么会阻塞线程?
> 在主队列开启同步任务,因为主队列是串行队列,里面的线程是有顺序的,先执行完一个线程才执行下一个线程,而主队列始终就只有一个主线程,主线程是不会执行完毕的,因为他是无限循环的,除非关闭应用程序。因此在主线程开启一个同步任务,同步任务会想抢占执行的资源,而主线程任务一直在执行某些操作,不肯放手。两个的优先级都很高,最终导致死锁,阻塞线程了。