(Java 高并发程序设计) 一篇文章带你深入了解 Java 中的进程和线程
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体
用一句简单的话来说,你在Windows中看到的后缀为.exe
的文件都是程序。不过程序是“死”的,静态的。当你双击这个.exe
程序的时候,这个.exe
文件中的指令就会被加载,那么你就能得到一个有关这个.exe
程序的进程。进程是“活”的,或者说是正在被执行的。图示使用任务管理器显示了当前系统中的进程。
进程中可以容纳若干个线程。它们并不是看不见、摸不着的,可以使用工具看到它们,如图所示。
那么线程和进程之间究竟是一种什么样的关系呢?
简单地说,进程是一个容器。比如一间漂亮的小别墅。别墅里有卧室、厨房、书房、洗手间等。当然,还有一家三口住在里面。当妈妈带女儿外出游玩时,爸爸一个人在家。这时爸爸一个人在家里爱去哪里去哪里、爱干什么干什么,这时爸爸就像一个线程(这个进程中只有一个活动线程),小别墅就像一个进程,家里的厨房、书房就像这个进程占有的资源。当三个人住在一起时(相当于三个线程),有时候可能就会有些小冲突,比如,当女儿占着电视机看动画片时,爸爸就不能看体育频道了,这就是线程间的资源竞争。当然,大部分时候,线程之间还是协作关系(如果我们创建线程是用来打架的,那么创建它干什么呢?)。比如,妈妈在厨房为爸爸和女儿做饭,爸爸在书房工作赚钱养家糊口,女儿在写作业,各司其职,那么这个家就其乐融融了,相应地,这个进程也就在健康地执行。
用稍微专业点的术语说,线程就是轻量级进程,是程序执行的最小单位。使用多线程而不是用多进程去进行并发程序的设计,是因为线程间的切换和调度的成本远远小于进程。
接下来让我们更细致地观察一个线程的生命周期。我们可以绘制一张简单的状态图来描述这个概念,如图所示。
线程的所有状态都在Thread中的State枚举中定义,如下所示:
NEW
状态表示刚刚创建的线程,这种线程还没开始执行。等到线程的start()
方法调用时,才表示线程开始执行。
当线程执行时,处于RUNNABLE
状态,表示线程所需的一切资源都已经准备好了。
如果线程在执行过程中遇到了synchronized
同步块,就会进入BLOCKED
阻塞状态,这时线程就会暂停执行,直到获得请求的锁。WAITING
和TIMED_WAITING
都表示等待状态,它们的区别是WAITING
会进入一个无时间限制的等待,TIMED_WAITING
会进行一个有时限的等待。那么等待的线程究竟在等什么呢?
一般来说,WAITING
的线程正是在等待一些特殊的事件。比如,通过wait()
方法等待的线程在等待notify()
方法,而通过join()
方法等待的线程则会等待目标线程的终止。一旦等到了期望的事件,线程就会再次执行,进入RUNNABLE
状态。当线程执行完毕后,则进入TERMINATED
状态,表示结束。
注意:从NEW
状态出发后,线程不能再回到NEW
状态,同理,处于TERMINATED
状态的线程也不能再回到RUNNABLE
状态