首先我们要清楚程序、线程和进程的概念
一、程序是什么?
程序是含有指令和数据的文件,被存储在磁盘或其他的数据存储设备中,可以理解为程序是包含静态代码的文件。例如:酷狗音乐软件、浏览器软件等软件的安装目录及文件。
二、进程是什么?
进程是程序的一次执行过程,是系统运行程序和分配资源的的基本单位。系统运行一个程序,就会创建一个对应的进程。
在 windows 系统中,每一个正在执行的 exe 文件或后台服务,都是一个进程,由操作系统统一管理并分配资源,因此进程是动态的。例如:正在运行的酷狗是一个独立的进程,正在运行的浏览器是一个独立的进程,一台电脑同时登录运行的两个qq也是两个独立的进程,互不影响的进程,这些都可以在任务管理器中看到。
操作系统运行一个程序,即是一个进程从创建、运行到消亡的过程。简单来说,一个进程就是一个执行中的程序,它在计算机中一个指令接着一个指令的执行着,同时,每个进程还占有某些系统资源,如 CPU 时间,内存空间,文件,输入输出设备的使用权等。
三、线程是什么?
线程是系统进行调度执行的基本单位,系统会以线程为单位,执行程序指令。
一个进程可以有一个或多个线程,但至少会有一个主线程。可以这样理解。一个程序可以实现多个功能,每一个功能可以理解为一个线程,例如:我们在使用 WPS 时,WPS 可以让我们一边打字,一边进行拼写检查,同时还可以在后台进行自动保存和上传云文档, 也就是说,进程内部有一个或多个子任务在执行,这些子任务就是线程。线程是进程划分的更小的运行单位。
例如:我们启动 JVM 运行一个 Java 程序,实际上就是启动了一个 JVM 的·进程。在 JVM 的进程中,又包含了 main 主线程、Reference Handler 清理线程、Finalizer 线程(用于调用对象的 finalize() 方法)等线程。
线程是一个比进程更小的执行单位( CPU 的最小执行单位)。一个进程在其执行的过程中可以产生多个线程。与进程不同的是,同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间切换工作时,负担要比进程小得多。
四、进程与线程的区别?
- 根本区别:进程是操作系统资源分配的基本单位 ( cpu,内存,网络连接等),每个进程都有自己的地址空间;而线程是处理器任务调度和执行的基本单位,是进程内的一个执行流。
- 资源开销: 每个进程都有独立的代码副本和数据空间,进程之间的切换,资源开销较大;线程可以看作轻量级的进程,每个线程都有自己独立的运行栈和程序计数器,线程之间切换,资源开销小。
- 包含关系:一个进程可以包含一个或多个线程,在执行过程,线程的执行不是线性串行的,而是多条线程并行共同完成。
- 内存分配:同一进程内的所有线程共享本进程的内存空间和资源;进程之间的内存空间和资源相互独立分配。
- 影响关系:一个进程崩溃后,在保护模式下不会对其它进程产生影响;一个线程崩溃,会导致整个进程退出,所以多进程要比多线程健壮。
- 执行过程:每个独立的进程有程序运行的入口和程序出口,但是线程不能独立执行,必须依存应用程序(进程)中,由应用程序提供多个线程执行控制。
- 通信和同步:进程间通信 ( IPC ) 较为复杂,通常需要消息传递、管道、共享内存等方式实现;同一进程的线程间通信直接且快捷,可以通过共享内存区域直接访问。
- 系统开销:创建和销毁进程的开销大,因为涉及资源的分配和回收;创建和销毁线程的开销相对较小,因为他们共享进程的资源。
- 控制和影响:子进程不会直接影响父进程的状态,进程间相对独立;子线程可以影响主(父)线程,若主线程发生异常,可能会影响到所有子线程。
- 并发性:进程提供较低级别的并行性,因为进程间的切换开销大;线程提供高级别的并行性,因为线程间的切换开销小,可以更快地在多个线程之间切换执行。
- 安全性:进程间的数据隔离性好,一个进程的错误不会影响到其它进程;同一进程内的线程共享数据,如果没有适当的同步机制,可能会导致数据竞争和死锁。
五、JVM 进程
JVM 进程的内存区域分配
JVM 进程启动时,自动创建 Heap (堆区) 和 Metaspace (元空间,JDK1.8 以前叫 Method Area 方法区);
多个线程共享 JVM 进程的 Heap (堆区) 和 Metaspace (元空间)资源,但每个线程都有自己的程序计数器、虚拟机栈和本地方法栈。系统在产生一个线程,或是在各个线程之间做切换工作时,负担要比进程小得多,因此,线程被称为轻量化进程。
JVM 进程由哪些线程组成?
代码实现:
package om.ape.boke; import java.lang.management.ManagementFactory; import java.lang.management.ThreadInfo; import java.lang.management.ThreadMXBean; public class JVMdZuCheng { public static void main(String[] args) { //获取 Java 线程管理对象 ThreadMXBean ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); /*不需要获取锁监视器 lockedMonitor 和 synchronizer 信息 * threadMXBean.dumpAllThreads(lockedMonitors, lockedSynchronizers)方法点进去看如下 * public ThreadInfo[] dumpAllThreads(boolean lockedMonitors, boolean lockedSynchronizers); } * threadMXBean.dumpAllThreads(lockedMonitors, lockedSynchronizers) * 取这两 布尔类型参数 为false就好 * */ //仅获取线程和线程信息 ThreadInfo[] ThreadInfo = threadMXBean.dumpAllThreads(false, false); //遍历线程信息,仅打印线程 id 和 线程名称信息 for(ThreadInfo threadInfo:ThreadInfo) { System.out.println("线程 id:"+threadInfo.getThreadId()); System.out.println("线程名称信息:"+threadInfo.getThreadName()); System.out.println(); } } }
运行结果:
结果解释:
线程 id:5
线程名称信息:Attach Listener《===========》添加事件监视器线程 id:4
线程名称信息:Signal Dispatcher《===========》分发处理给 JVM 信号的线程线程 id:3
线程名称信息:Finalizer《===========》调用对象 finalize 方法的线程线程 id:2
线程名称信息:Reference Handler《===========》清除 reference 线程线程 id:1
线程名称信息:main 《===========》主线程
未来多线程运行或重写 run 方法, run 模式在 JVM 中有一个独有线程
====》Monitor Ctrl-Break