今天阿里的面试官问了一些关于多线程的问题,感觉自己对这一方面不太了解,于是便google了一些文章,然后又复习了之前学习的操作系统的基础知识,在此进行一下总结,下一篇进行一下java线程相关类的源码分析。
首先是关于进程和线程的基本概念。
- 进程是为了准确描述运行程序的状态和系统动态变化状况的数据结构,进程既能描述程序的并发性,也能共享系统的资源
- 线程的引入是为了减少程序并发执行时所付出的时空开销,使得并发粒度更细,并发更好。这个思路下,“独立分配资源”的任务仍由进程完成,作为系统资源保护和分配的基本单位,而“被调度分派执行”的任务被交付给线程的实体完成,线程作为系统调度和分配的基本单位,会被频繁的调度和切换。
与进程相比,线程的有点为:
- 快速线程切换,同一个进程中的多线程切换,只需要改变堆栈和寄存器,地址空间不用变。
- 通信易于实现。自动共享进程的内存和文件,线程可以自由访问全局变量,通信十分方便,而且不需要通过内核
- 减少管理开销。线程创建和撤销的工作比进程少。
- 并发程度高。多线程适合并行工作
进程的属性:
- 动态性:进程是程序在数据集合上的一次执行过程,是动态概念,而程序是静态概念
- 独立性:每个进程是操作系统中的一个独立的实体,有自己的虚存空间,程序计数器和内部状态。
线程的状态和转换:
线程有三态模型和七态模型,我们就只说明七态模型啦。
需要解释的几个地方:
- 就绪态,进程具备了运行的条件,等待系统分配处理器以便运行,比如所java的Thread.start()之后,其线程就处于就绪态,可以执行,但是可能还未执行
- 两种挂起态,当系统资源尤其是内存资源不能再满足进程运行的要求,就必须把一些进程挂起,对换到磁盘交换区,释放掉它占有的资源,暂时不参与低级调度。就是挂起就绪态也无法执行,挂起等待态等待的事件完成,也不能导致进程具备可执行的状态。
- 两种等待态,进程不具备运行条件,正在等待某个事件完成的状态。
线程是进程中能够并发执行的实体,是进程的组成部分,也是处理器调度和分派的基本单位,允许线程包含多个进程,这些进程共享进程所获得的内存空间和资源。
线程的实现方式:
- 内核级线程:线程的管理工作有内核完成,并提供线程API来使用线程,操作系统在内核空间建立和维护进程控制块PCB和线程控制块TCB,内核调度在线程的基础上进行。优点:多处理器上内核可以同时调度同一进程中的多线程并执行,进程中一个线程被阻塞,内核可以调用同一进程的其他线程;缺点:线程在用户态运行,而线程的调度和管理在内核完成,同一进程中,控制权的转移需要经历用户态-内核态-用户态的转变,系统开销大
- 用户级线程:线程的管理工作由应用程序来做,在用户空间内实现,内核不知道线程的存在。优点:线程转换不需要内核特权,线程管理的数据在用户空间,节省了线程切换的花费和内核宝贵的资源,运行应用程序按照需要选择线程的调度算法;缺点:一个用户级线程的阻塞会引起整个进程的阻塞,用户线程不能利用多重处理的优点。
- 混合式线程,一些操作系统既支持用户级线程,也支持内核级线程,用户层线程在用户线程库中实现,内核层线程在操作系统内核中实现,在这种模式下,一个应用程序中的多个用户级线程能分配或者对于于一个或者多个内核层线程,内核级线程可以在多处理器上并行执行。优缺点都是上述两种模式的中和。