为什么要使用多线程技术

来源:互联网 发布:创维25t15aa 4t60数据 编辑:程序博客网 时间:2024/04/20 13:43

前言

为什么要使用多线程技术,这本来应该是个基础的问题,是在学习多线程的时候应该搞懂的问题,可我却在学了多线程之后才开始搞懂这个问题。(敲黑板!)这是本末倒置,大家要注意。

确实,如果连为什么要使用多线程都没搞懂,就别指望能把多线程给学好了。

为什么要使用多线程技术?

像我们一开始学习 JAVA 还没学多线程时,所以代码都是在 main 线程中执行,这没问题。但是,假如我们有多个任务,并且其中有耗时的任务。比方说有三个任务,并且执行顺序依次为任务A,任务B,任务C,假设,任务A是一个耗时的 IO 操作(如读取一个文件中的全部信息),那么,在单线程中,当执行到任务A时,由于任务A进行的是 IO 操作,因此线程会挂起并让出 CPU(注意,IO 操作并不会一直占着 CPU),直到DMA(Direct Memory Access)处理器完成任务(这个过程可能会很久,这是操作系统的知识!!操作系统很重要!),再通过中断告诉CPU完成了,该线程才会再次运行,任务A才可以继续往下执行。因为是单线程,所以任务B必须等到任务A执行完才能执行,任务C必须等到任务B执行完才能执行。如果任务B又是一个耗时的操作,那么任务C要等待的时间就会更久了。

如果使用了多线程,为两个耗时的任务分别开启线程去执行的话,那么由于三个任务是并发执行的,因此,即使任务A和任务B是耗时操作,那也和任务C没关系,因为他们在不同的线程之间了。

一个生动形象的例子

举个例子——在汽车客运站的售票厅(有个不太合理的假设,售票员只有一个)。假设某个窗口有100个人在排队,前三个的人分别是老爷爷、老奶奶、以及赶着去签合同的小明。
假设老爷爷的记性不太好,当售票员问他要定去往哪里的汽车票时,老爷爷说忘不起了,要打个电话问一问儿子,等问到了,再告诉售票员。(着急的小明黑人问号脸????)于是售票员就跑去其他窗口为其他排队的人服务了。这时排在最后的小明,只能干着急!
等老爷爷打完电话,并且售票员过来时,老爷爷总算订到票并离开了。(老爷爷的操作可以理解为IO操作)这时,老奶奶便上场了。当售票员问老奶奶要定去往哪里的票的时候,老奶奶竟然说还没想好,要再想一想。排在后面的小明一脸茫然,可是他除了等还能怎样。毕竟这里是公共场所,毕竟人家是老奶奶。于是售票员就走去其他窗口服务了。
小明此时在想,要是能专门开个窗口为这些慢吞吞的老爷爷老奶奶开个窗口给他们服务就好了,这样他们要考虑多久都没关系,因为在他们考虑的时候售票员可以去其他窗口为其他赶时间的乘客服务。(这就是使用多线程的好处)
等到老奶奶想好了,然后等到售票员来到老奶奶所在的窗口时,老奶奶也订到她的票了。然后就到小明了,还没等小明开口,可是这时售票员又跑去其他窗口服务了。(毕竟其他窗口也有乘客啊,不能只为你一个窗口服务吧)
最后,售票员总算来到小明所在的窗口了,售票员在服务的时候,小明抱怨说要是能为那些慢吞吞的设立专门的窗口就好了。售票员微笑表示同意并回答:“这是个好建议,我会跟上级反映一下”。(这里向上级反映就相当于告诉设计程序的人,为耗时的操作开启专门的线程,以不至于导致其他操作一直干等。)小明笑着说:“要是为我这种赶时间速度又快的人设立专门的窗口我觉得也是可以的。”售票员却摇了摇头,并有礼貌的回答:“这可不行,因为像你这样办理速度快的人占的是绝大多数,要是为你们都开启专门的窗口,那得开多少个窗口才够啊,且不说面积够不够,就算够,我跑来跑去,也花掉不少时间啊”。(开启线程是要付出代价的,并不是越多线程效率就越高)
小明不好意思的点了点头,并问售票员姐姐要了微信。后来…(开玩笑)

这个例子中,售票员就相当于 cpu,线程就相当于窗口,排队的人就相当于各个任务,售票员跑去哪个窗口就相当于哪个线程获得时间分片。然后还得假设售票员在同一个窗口停留的时间很短,以纳秒为单位,这样以秒为单位来看,售票员就相当于同时服务了很多个窗口,这就是并发。

并发与并行

并发是指一个很短的时间间隔内,执行了多个任务。
并行是指在同一个时刻,执行了多个任务。
并发也称为伪并行,也就是说,并发,就好像同一时刻,可以执行多个任务。那是因为时间间隔足够短让你以为多个任务是在同一时刻发生了。

谈到并发,默认前提都是单核 CPU。由于只有一个核,所以同一时刻,只能有处理一件事情。又由于多线程的存在以及 CPU 的效率极高,结果就造就了并发——看起来好像同一时刻 CPU 可以处理多件事情。
而并行,默认前提则是多核多线程。

最后

使用多线程就只有好处没有坏处吗?并不是,使用多线程是要付出代价的,如果没有耗时的任务,使用多线程,效率反而更低,因为cpu 在线程间的切换也需要耗费时间。引用知乎上看到的一句话:

多线程在CPU密集型的作业下的确不能提高性能甚至更浪费时间,但是在IO密集型的作业下则可以提升性能(或者更准确点说叫平均响应时间)。

由上得出的结论是,正确的使用多线程可以提高程序的运行效率。

不过,也由于多线程的存在,带来了线程安全的问题,因此我们要去学线程池、锁机制、CAS、线程安全的容器类等知识去解决线程安全问题。


如有哪里写的不对,请帮忙指出,感谢!

原创粉丝点击