进程和线程是操作系统中的两个核心概念,它们的出现是为了更好地管理计算机资源和提高系统的运行效率,使用它们可以实现多任务同时运行,从而提高了系统资源的利用率。

定义

进程和线程的区别也是很明显的,进程是资源分配的最小单位,线程是 CPU 调度的最小单位。具体来说:

  • 进程(Process)是指正在运行的一个程序的实例。每个进程都拥有的资源:堆、栈、虚存空间(页表)、文件描述符等信息。在 Java 中,每个进程都由一个主线程(main thread)启动。当进程运行时,操作系统会为其分配一个进程号,并将其作为一个独立的实体来进行管理。
  • 线程(Thread)是指进程中的一个执行单元,是 CPU 调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。在 Java 中,每个线程都拥有自己的栈空间和程序计数器,并且可以访问共享的堆内存。

举例说明

举例例子,假设你正在玩一款游戏,那么这个过程可以被看作是一个进程。在这个进程中,有很多不同的任务需要同时运行,比如说渲染游戏画面、处理玩家的输入、播放音效等等,这些任务可以被看作是不同的线程。 具体来说,渲染游戏画面的任务可以被看作是一个线程,处理玩家的输入也是一个线程,播放音效也可以是一个线程。这些线程可以同时运行,并且它们之间可以共享进程的内存空间,以便彼此之间传递信息和数据。

另外,如果你同时打开了两个不同的游戏,那么这就是两个独立的进程。这两个进程之间无法直接共享内存空间,它们需要使用进程间通信(IPC)机制来进行通信和数据传递。而且如果一个游戏崩溃了,另一个游戏不会受到影响,因为它们是独立的进程。

代码使用

进程使用

在 Java 中,创建进程的示例代码如下:

public class CreateProcessDemo {
    public static void main(String[] args) {
        try {
            // 通过 ProcessBuilder 创建一个新的进程
            ProcessBuilder processBuilder = new ProcessBuilder("notepad.exe");
            Process process = processBuilder.start();

            // 等待进程结束
            int exitCode = process.waitFor();
            System.out.println("进程已结束,退出码为:" + exitCode);
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}

在这个示例中,我们使用了 ProcessBuilder 类来创建一个新的进程,这里我们创建了一个名为 notepad.exe 的进程,即打开记事本应用程序。

然后,我们调用 waitFor() 方法等待进程结束,并获取进程的退出码。最后,我们将退出码输出到控制台。 当你运行这个程序时,会看到一个新的记事本窗口弹出来,这就是我们创建的进程。当你关闭记事本窗口时,程序会继续执行,输出进程的退出码。

需要注意的是,使用进程时要格外小心,因为它们可以直接操作系统资源,并对系统造成影响。所以在使用进程时,一定要谨慎处理,并确保代码的安全性和稳定性。

线程使用

在 Java 中,创建线程的示例代码如下:

public class CreateThreadDemo {
    public static void main(String[] args) {
        // 创建一个新的线程
        Thread thread = new Thread(() -> {
            System.out.println("线程开始执行");
            try {
                Thread.sleep(5000); // 模拟线程执行耗时任务
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程执行完成");
        });
        // 启动线程
        thread.start();
        System.out.println("主线程继续执行");
    }
}

在这个示例中,我们使用了 Thread 类来创建一个新的线程。在 Thread 的构造函数中,我们传入了一个 Runnable 接口的实现,该实现定义了线程的任务,这里我们只是简单地输出一些信息并模拟了一个耗时任务。 然后,我们调用 start() 方法来启动线程。当线程启动后,它会执行 run() 方法中定义的任务,同时主线程会继续执行。在这个示例中,我们在主线程中输出了一条信息。

需要注意的是,使用线程时同样需要谨慎处理,因为线程可以直接操作共享资源,并对系统造成影响。在使用线程时,需要确保线程的安全性和稳定性,同时避免出现线程安全问题,比如死锁等问题。

进程 VS 线程

线程可以看作是轻量级的进程,一个进程中包含了多个线程,因此多个线程间可以共享进程资源,线程和进程的关系如下图所示: image.png 其中,堆和方法区是可以共享的区域,而程序计数器和栈是每个线程私有的。

  • 程序计数器是一块内存区域,用来记录线程当前要执行的指令地址。
  • 栈是用来记录每个线程自己的局部变量的。
  • 堆中存放的是当前程序创建的所有对象。
  • 方法区存放的是常量和静态变量等信息。

总的来说,进程和线程的区别主要有以下几点:

  1. 进程是系统分配资源的基本单位,线程是程序执行的基本单位;
  2. 进程拥有独立的内存空间和资源,而线程则共享进程的内存和资源;
  3. 进程之间的通信比较复杂,而线程之间可以直接共享数据;
  4. 进程的切换代价比较大,需要保存上下文和状态,而线程的切换代价比较小,因为它们共享进程的资源。

小结

进程是系统分配资源的基本单位,线程是程序执行的基本单位。一个进程中至少包含一个线程,线程不能独立于进程而存在。进程不能共享资源,而线程可以。线程可以看作是轻量级的进程,但它们的定义、资源共享方式、切换代价等都不同。

特殊说明

以上内容来自我的《Java 面试突击训练营》,这门课程是有着十几年工作经验(前 360 开发工程师),10 年面试官经验的我,花费 4 年时间打磨完成的一门视频面试课。学完训练营的课程之后,基本可以应对目前市面上绝大部分公司的面试了,并且课程配备了 9 大就业服务,帮助上千人找到 Java 工作,其中上百人拿到大厂 Offer,学员最高薪资 70W 年薪,面试课目录和 9 大服务如下:

加我微信咨询:vipStone【备注:训练营】