工作忙完一段时间,整理资料,总结知识,发现对多线程这块有点遗忘,写篇博客谈谈多线程,温故而知新。
大家面试,想必都会被问到,你理解多线程吗?还可能追问道
1、有哪几种多线程,基于什么语言的?
2、生命周期是如何管理的?
3、你更倾向于那种?现在常用的两种,谈谈你的看法?
第一种:pthread
特点:
1、一套通用的多线程API
2、适用于Unix、Linux、Windows等系统
3、跨平台、可移植
4、使用难度大
5、使用语言:C语言
6、开发使用频率:几乎不用,
7、线程生命周期:由程序员进行管理
第二种:NSThread
特点:
1、使用更加面向对象
2、简单易用,可直接操作线程对象
3、使用语言:OC语言
4、开发使用频率:偶尔使用
5、线程生命周期:由程序员进行管理
第三种:GCD
特点:
1、旨在替换NSThread等线程技术
2、充分利用设备的多核(自动)
3、使用语言:C语言
4、开发使用频率:经常使用
5、线程生命周期:自动管理
第四种:NSOperation
特点:
1、基于GCD(底层是GCD)
2、比GCD多了一些更简单的实用的功能
3、使用更加面向对象
4、使用语言:OC语言
5、开发使用频率:经常使用
6、线程生命周期:自动管理
多线程的原理
同一时间,CPU只能处理1条线程,只有一条线程在工作,多线程并发执行,其实就是CPU快速的在多条线程之间调度,如果CPU调度线程的时间足够快,就造成了多线程并发的假象了;
思考 如果线程非常多,会发生什么情况?
CPU会在N多线程之间调度,CPU会累死,消耗大量的CPU资源,每条线程被调度执行的频率被大大降低。
多线程优点
能适当的提高程序执行的频率
能适当提高资源利用率(CPU)
多线程缺点
开启线程需要占用一定的内存空间(默认情况下,主线程占用1M,子线程占用512KB),如果开启大量的线程,会占用大量的内存空间,降低程序的性能,线程越多,CPU在调度线程上的开销就越大,程序设计更加复杂:比如线程之间的通信,多线程的数据共享。
你更倾向于哪一种?
就本人而已我是倾向于GCD的 所以下面主要结合实例谈谈GCD
GCD技术是一个轻量级,底层实现隐藏的申请技术,我们能够通过GCD和Block轻松实现多线程编程,有时候,GCD相比其他系统提供的多线程方法更加有效,当然,有时候GCD不是最佳选择,另一个多线程技术NSOperationQueue让我们能够将后台线程以队列方式依序执行,并提供更多操作入口,这和GCD的实现有些类似。
GCD执行原理
GCD有一个底层线程池,这个池中的线程可以重用,当一段时间后这个线程没有被调用的话,这个线程就会被销毁。注意:开多少线程是由底层线程池决定的(建议3-5),池是系统自动来维护,我们只需要关系的是向队列中添加任务,队列调度即可。
1.如果队列中存放都是同步任务,则任务出队后,底层线程池会提供一条线程供和这个任务执行,任务执行完毕后这条线程在回到线程池,这样队列中的任务反复调度,因为是同步的,所以当我们用currentThread打印的时候,就是同一条线程、
2.如果队列中存放的是异步任务,当任务出队后,底层线程池会提供一个线程供任务执行,因为是异步执行,队列中的任务不需要等待当前任务执行完毕就可以调度下一个任务,这时底层线程池中会再次提供一个线程供第二个任务执行,执行完毕后在回到底层的线程池中。
通过案例了解GCD的执行原理
案例一
分析 首先执行任务1,接下来程序遇到了同步线程,那么它会进入等待,等待任务2执行完,然后在执行任务3。但是这是队列,有任务来,当然会将任务加到队尾,然后遵循FIFO原则执行任务,那么,现在任务2就被加到最后了,任务3排在了任务2前面,问题来了:任务3要等任务2执行完才能执行,任务2又排在任务3后面,意味着任务2要在任务3执行完才能执行,所以他们进入了互相等等的局面,就卡在这里,发生死锁。
案例二
分析 首先执行任1,接下来会遇到一个同步线程,程序会进入等待,等待任务2执行完成以后,才能继续任务3,从dispatch_get_global_queue可以看出,任务2被加入到了全局的并行队列中,当并行队列执行完成任务2后,返回到主队列,继续执行任务3
案例三
案例四
分析 首先将【任务1、异步线程、任务5】加入到MainQueue中,异步线程中的任务是,【任务2,同步线程、任务4】。所以,先执行任务1,然后将异步线程中的任务加入到GlobalQueue中,因为异步线程,所以任务5不用等待,结果就是2和5的输出顺序不一定。然后在看异步线程中的任务执行顺序。任务2执行完以后,遇到同步线程,将同步线程中的任务加入到MainQueue中,这时加入的任务3在任务5的后面,当任务3执行完以后,没有了阻塞,程序继续执行任务4
案例五
分析 和上面几个案例的分析类似,先来看看都有哪些任务加入了Main_Queue:【异步线程、任务4、死循环、任务5】。加入到Global_Queue异步线程中的任务有:【任务1、同步任务、任务3】。第一个就是异步线程,任务4不用等待,所以结果任务1,和任务4顺序不一定,任务4完成后,程序进入死循环,Main_Queue阻塞。但是加入到Global_Queue的异步线程不受影响,继续执行任务1后面的同步线程。同步线程中,将任务2加入到了主线程,并且,任务3等待任务2完成以后才能执行。这时的主线程,已经被死循环阻塞了。所以任务2无法执行,当然任务3也无法执行,在死循环后的任务5也不会执行。