进程和线程

1. 进程

1.1 进程的概念

进程是操作系统对一个正在运行的程序的一种抽象,换言之,可以把进程看做程序的一次运行过程。当一个程序被执行时,操作系统会为该程序创建一个进程,进程是程序执行过程中的一个实体,它包括程序的代码、数据、堆栈和其他与程序执行相关的资源。

1.2 进程的描述—进程控制块抽象(PCB Process Control Block)

在操作系统中如何管理进程?

  • 先描述:使用类/结构体,把被管理的对象,各个属性都描述出来(系统中专门使用的是结构体来描述进程的各个属性,这个结构体称为PCB)
  • 再组织:使用数据结构,类似双向链表来组织多个PCB

进程控制块(Process Control Block)的缩写,也称为进程描述符(Process Descriptor),是操作系统中用来管理和维护进程信息的数据结构。

PCB存储了一个进程的各种重要信息,包括但不限于:

  • 进程状态(运行、就绪、阻塞等)和优先级
  • 程序计数器(Program Counter,PC):指向当前正在执行的指令的地址
  • 寄存器信息:包括通用寄存器、堆栈指针等
  • 进程ID(PID,进程标识符)和父进程ID
  • 进程所占用的资源信息,如内存分配情况、打开的文件列表等
  • 进程调度信息,如优先级、时间片大小等

PCB是操作系统进行进程调度和管理的基础,当操作系统需要切换进程时,会保存当前进程的上下文信息到其对应的PCB中,然后加载下一个将要执行的进程的PCB,并将其上下文信息恢复,从而实现进程的切换。PCB的创建和维护由操作系统负责。

2. 线程(Thread)

2.1 概念

线程-----“轻量级进程”,线程不能独立存在,必须依附于进程(进程包含线程,可以是一个也可以是多个)。

2.1.1 线程出现的原因

并发编程成为刚需。虽然多进程也能实现 并发编程,但是由于进程太重量,效率不高,创建进程、销毁进程、进程调度时间的消耗较多,主要消耗在申请资源, 线程比进程更轻量,线程之间共享进程的内存空间和硬盘资源,创建线程,不需要重复去申请资源,省去了这一部分的开销 ,提高了系统的效率和资源利用率。

2.1.2 线程的创建

创建线程需要两个步骤,首先,明确线程要执行的任务。其次,调用系统API创建出线程。

方法1 继承 Thread 类

  1. 继承 Thread 来创建一个线程类
class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("这里是线程运行的代码");
   }
}
  1. 创建 MyThread 类的实例
  2. 调用 start 方法启动线程
MyThread t = new MyThread();
t.start();//真正调用系统API,在系统中创建线程,再让线程调用run

方法2 实现 Runnable 接口

  1. 实现 Runnable 接口
class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("这里是线程运行的代码");
   }
}
  1. 创建 Thread 类实例, 调用 Thread 的构造方法时将 Runnable 对象作为 target 参数.
  2. 调用 start 方法
Thread t = new Thread(new MyRunnable());
t.start();

对比上面两种方法:

  • 继承 Thread 类, 直接使用 this 就表示当前线程对象的引用.
  • 实现 Runnable 接口, this表示的是 MyRunnable 的引用. 需要使用 Thread.currentThread()

方法3 匿名内部类创建 Thread 子类对象

// 使用匿名类创建 Thread 子类对象
Thread t1 = new Thread() {
    @Override
    public void run() {
        System.out.println("使用匿名类创建 Thread 子类对象");
   }
};

方法4 匿名内部类创建 Runnable 子类对象

// 使用匿名类创建 Runnable 子类对象
Thread t2 = new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("使用匿名类创建 Runnable 子类对象");
   }
});

方法5 lambda 表达式创建 Runnable 子类对象

// 使用 lambda 表达式创建 Runnable 子类对象
Thread t3 = new Thread(() -> System.out.println("使用匿名类创建 Thread 子类对象"));
Thread t4 = new Thread(() -> {
    System.out.println("使用匿名类创建 Thread 子类对象");
});

2.3 线程的状态

  • NEW: 安排了工作, 还未开始行动(Thread对象已经有了,start方法还没有被调用)
  • RUNNABLE: 可工作的. 又可以分成正在工作中和即将开始工作. (线程已经在CPU上执行了或者线程正在等待在CPU上执行)
  • BLOCKED: 这几个都表示排队等着其他事情(由于锁竞争产生的阻塞)
  • WAITING: 这几个都表示排队等着其他事情(不固定时间的方式产生的阻塞)
  • TIMED_WAITING: 这几个都表示排队等着其他事情(固定时间产生的阻塞)
  • TERMINATED: 工作完成了. (内核中的线程已经运行结束了,但是Thread对象还存在)
    在这里插入图片描述

3. 进程和线程的区别

  1. 进程包含线程,一个进程可以有一个线程,也可以有多个线程。每个进程至少有一个线程存在,即主线程。

  2. 进程和线程都可以实现并发编程,但是线程更加轻量、高效。
    同一个进程中的线程共用一份内存资源和硬盘资源,省去了申请资源的开销。

  3. 由于进程间的独立性,一个进程的崩溃不会影响其他进程。
    线程之间共享相同的内存空间,一个线程的错误可能会影响整个进程的稳定性。

  4. 进程拥有独立的地址空间和资源,每个进程之间相互独立,通信需要通过进程间通信机制来实现;而线程在同一进程中共享资源,可以直接访问进程中的所有数据,线程之间的通信更加方便。

  5. 由于进程拥有独立的内存空间,进程切换的开销通常比线程切换的开销更大。
    线程切换通常只涉及线程上下文的切换,而不涉及内存空间的切换。

  6. 进程是系统资源分配的最小单位,线程是系统调度的最小单位。
    在这里插入图片描述

  • 27
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux中的进程线程有以下几个区别: 1. 数据结构:在Linux中,线程是通过进程模拟出来的,没有真正意义上的线程数据结构。而在Windows中,操作系统为线程创建了thread_struct数据结构,因此有真正意义上的线程。 2. 执行流:在Linux中,每个线程实体对应着操作系统下的一条执行流,通过PCB(task_struct)来模拟。而用户态下创建的线程是通过线程库(pthread_struct)来进行管理。 3. 标识作用:在Linux中,轻量级进程ID(tid)对不同的线程起标识作用,操作系统在进行调度时使用tid。而进程ID(pid)对不同的进程起标识作用。在只有一个线程的进程中,tid的值等于pid的值。 4. 线程私有部分:线程私有部分包括运行时栈、一组寄存器/硬件上下文/任务状态段等。 5. 多线程提高效率:多线程能够提高效率的原因是多核和单核环境下的不同。在多核环境下,多线程可以将庞大的任务分成若干份,并交给不同的线程进行处理,同时执行不同步骤的代码,从而提高效率。而在单核环境下,多线程并发执行,使用线程切换来提高整体代码的运行效率。 6. 进程线程的区别:进程是程序运行的实例,是系统分配资源的基本单位,拥有独立的地址空间;线程是进程中的一条执行流,是CPU调度的基本单位,共享同一地址空间。创建和撤销进程的开销大于线程,不同进程间不会互相影响,而一个线程挂掉可以将整个进程挂掉。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值