线程这个词,我们都很熟悉,写代码的时候也都用过多线程,可是,你知道多线程是怎么被我们聪明人类发明而来的吗?了解了多线程的发展历程,和每个阶段核面临要解决的问题,你就自然而然的理解了为什么现在多线程是这样设计的,下次面试也有了吹牛的底气。知其然,更要知其所以然。
多线程的发展历程
1)纸带机
在最开始的时候,计算机是通过穿孔打卡实现的,将程序预先写到纸上,穿孔成卡片,将卡片上的程序输入到计算机上,计算机运行完当前的任务之后,把结果从打印机上进行输出,然后计算机等待下一个程序的输入。
这种处理会造成计算机极大空闲。比如程序输入时,计算机是处在等待输入的空闲状态的。
2)单道批处理系统
为了减少机器的空闲等待时间,后续出现了单道批处理系统,系统对作业处理是成批进行的。需要把一批作业输入到磁带上, 使得程序能一个接一个的连续处理,但是在内存中始终值保持一道作业。由于内存中只有一道程序,在程序运行中涉及IO操作较多时,CPU只能阻塞直到该IO完成,因此造成CPU资源浪费。
3)多道批处理系统
为了更高的利用CPU资源,便出现了多道程序的设计。系统中存在多个程序,当一个进程需要等待IO操作完成时,CPU可以切换到另一个进程。任务执行的这一小段时间叫做时间片,由于CPU在不同的进程间进行时间片切换,CPU的执行效率非常高,时间短,所以可以让操作系统从宏观层面看,是多应用并行运行。在CPU微观层面上,对于单核CPU来说,一个时刻只有一个进程在执行,底层就是通过CPU时间片不断切换来实现的。
4)多线程
为了对CPU进一步的压榨,将进程再进行切分更小的颗粒,这些进程的小颗粒可以并行执行,共享进程的资源,如同上面介绍的多道批处理系统一样的原理,从而提高了进程整体的执行速度。这些小颗粒就是线程,这就像学习物质组成一样,分子,再到原子,再到原子核、电子等类似的原理。后续由于硬件的发展,随着多核CPU等计算机的出现,多核CPU利用多线程实现了真正意义上的并行执行。多线程可以提高程序的并发和响应,减少切换开销,并且可以方便地共享数据。
5)纤程(协程)
随着技术的发展现在出现了纤程,纤程是用户管理的线程,是一种更轻量级的线程。线程属于操作系统管理。每一个线程创建都需要向操作系统申请创建,与操作系统交互,这样每启一个线程的代价都很高。一个线程可以拥有多个纤程。纤程目前使用的还不是很广,大多数还是使用的线程。
线程VS进程
通过上述介绍,我们知道,计算机最开始都是围绕着进程进行优化,那为什么有了进程,后面又有了线程呢?
进程是一个“执行中的程序”,例如我们的淘宝app就是一个进程,进程可以看作一个独立的应用。它是系统进行资源分配的基本单位。创建进程需要通过系统调用来分配内存空间、加载程序代码、设置进程环境等。进程的管理也需要通过系统调用来实现,比如进程的调度、进程的终止、进程的通信等。进程独占内存空间,保存各自的运行状态,相互间不打扰。进程切换时,涉及到当前进程的CPU环境的保存和被调度运行进程的CPU环境的设置。
线程是进程的一个实体,一个进程拥有多个线程,例如淘宝的订单页面,可能包含获取订单商品详情的线程、获取订单的线程等,两个线程同时执行,当然要比一个线程线性执行要快。一个进程的线程之间共享地址空间和其它资源,所以通信和同步等操作线程比进程更加容易。线程是CPU运行的基本单位,CPU调度的基本单位。线程切换仅需要保存和设置少量的寄存器内容,不涉及存储管理方面的操作。多核CPU利用多线程,实现了真正意义上的并行执行。
一个进程,会存在多个同时执行的任务,如果一个任务被阻塞,将会引起不依赖该任务的任务也被阻塞,通过对不同任务创建不同的线程去单独执行,可以提升程序的运行速度,提高CPU的利用效率。线程可以认为是轻量级的进程,线程的创建、销毁比进程更快。
既然线程有这么多好处,那是不是线程越多效率越高呢?
当然不是,多线程,意味着cpu要进行频繁的上下文切换,切换也是需要消耗资源的,(上下文切换:将原来执行的线程数据保存起来,将将要执行的线程数据加载进来执行)。因此如果线程太多,时间都耗费在了上下文切换上了。
线程和进程都可以进行相互切换的,那他们之间在切换时,通讯有什么区别呢?
进程依赖IPC资源,例如:管道、套接字等。线程间通讯依靠JVM提供的API,例如wait()、notify()、notifyAll()等方法,线程间还可以通过共享的主内存来进行值的传递,因此线程之间的通信通常比进程之间的通信更快,更易于实现。
说了这么多,总之进程和线程的主要区别在于它们的内存空间和资源共享方式、创建和管理的系统调用数量、以及它们的通信方式。进程是独立的,有自己的内存空间和资源,而线程则共享它们所在的进程的内存和资源。进程需要更多的系统调用进行创建和管理,而线程是在进程内部创建的,只需要较少系统调用。进程需要使用IPC资源进行通信,而线程可以直接通信。
说了这么多线程内部实现机制,那我们怎么在代码中启动一个线程呢?线程的生命周期是什么样的呢?我们下一期详细介绍。
碎碎念
我输出的文章都是我多年面试大厂总结的经验,将各系列面试高频知识点抽出来进行全面解析,还有一些个人感悟等等。如果恰好对你有用处,**【点赞、关注、在看】**是我创作的最大动力!!!
我这里有份非常全的面试题,长达20万字,算是 Java 一整套技术栈都写了,包括 Java 基础,虚拟机,消息队列,框架等等。当然,还有通用基础知识,例如计算机网络,操作系统,Mysql,Redis 也都整理了,给大家看一下目录。
如何获取这份资料
关注公众号「话猫」,回复「1024」即可获取下载链接哦,以下是公众号
作者简洁
2018年非科班选手,2020花费两年时间从小厂跳入美团搬砖,2023年来到了职业的下一站~快手,这里有我5年职场故事与未来憧憬,欢迎围观一枚女程序猿的故事~