《Java 后端面试经》操作系统篇

  • 🚀进程和线程
  • 🚁系统调用
  • 🚁并发和并行有什么区别?
  • 🚁同步和异步的区别
  • 🚁什么是进程?什么是线程?进程和线程间的区别?
  • 🪂追问:线程和协程的区别?
  • 🪂什么是守护线程?
  • 🚁进程间通信的方式有哪些?
  • 🚁线程间同步的方式有哪些?
  • 🚁进度调度算法有哪些?
  • 🚁什么是死锁?产生死锁的原因是什么?死锁产生的必要条件是什么?
  • 🚁什么是中断,有什么作用?
  • 🚀什么是上下文切换?
  • 🚀什么是虚拟内存?


🚀进程和线程

🚁系统调用

系统调用是操作系统提供的用户接口之一,是由操作系统实现的所有系统调用所构成的集合,即程序接口或应用编程接口(Application Programming Interface, API),是应用程序同系统之间的接口。

每当应用程序要求操作系统提供某种服务(功能)时,便调用具有相应功能的系统调用(子程序)。

java并行查询mysql java并行调用接口_面试

🚁并发和并行有什么区别?

串行在时间上不可能发生重叠,前一个任务结束之后,后一个任务才能开始。

并发:两个或多个事件在同一时间间隔内发生。这些事件宏观上是同时发生的,微观上是交替发生的。

并行:两个或多个事件在同一时刻发生。

🚁同步和异步的区别

同步:指一个进程在执行某个请求的时候,若该请求需要一段时间才能返 回信息,那么这个进程将会一直等待下去,直到收到返回信息才继续执行下去。

异步:指进程不需要一直等下去, 而是继续执行下面的操作,不管其他进程的状态。当有消息返回时系统会通知进程进行处理,这样可以提高执行的效 率。

🚁什么是进程?什么是线程?进程和线程间的区别?

进程是对运行时程序的封装,是系统资源拥有和分配的的基本单位,实现了操作系统的并发。

线程是进程的子任务,是 CPU 调度执行的基本单位,用于保证程序的实时性 ,实现进程内部并发。

区别:

  1. 并发性:进程间的并发性较低,线程间的并发性高。
  2. 地址空间:进程有独立的地址空间,线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间。
  3. 拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源。
  4. 系统开销:进程和线程切换时,需要切换进程和线程的上下文,进程的上下文切换时间开销远远大于线程上下文切换时间,耗费资源较大,效率要低一些。

🪂追问:线程和协程的区别?

协程是微线程,在子程序内部执行,可在子程序内部中断,转而执行别的子程序,在适当的时候再返回来接着执行。

线程与协程的区别:

  • 协程执行效率极高,协程直接操作栈基本没有内核切换的开销,所以上下文的切换非常快,切换开销比线程更小。
  • 协程不需要多线程的锁机制,因为多个协程从属于一个线程,不存在同时写变量冲突,效率比线程高。
  • 一个线程可以有多个协程。

🪂什么是守护线程?

  • 守护线程:是指在程序运行时在后台提供一种通用服务的线程,这种线程并不属于程序中不可或缺的部分,任何一个守护线程都是整个 JVM 中所有非守护线程的"保姆"。
  • 守护线程一般具有较低的优先级,它并非只由 JVM 内部提供,用户在编写程序时也可以自己设置守护线程守护线程。

🚁进程间通信的方式有哪些?

  • 管道(Pipe):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有血缘关系的进程间使用。进程的血缘关系通常指父子进程关系。管道分为 Pipe(无名管道)和 FIFO(命名管道)两种,有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间通信。
  • 信号量(Semaphores) :信号量是一个计数器,用于多进程对共享数据的访问,信号量的意图在于进程间同步,这种通信方式主要用于解决与同步相关的问题并避免竞争条件。
  • 信号(Signal):信号是一种比较复杂的通信方式,用于通知接收进程某一事件已经发生。
  • 共享内存(Shared memory) :使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据的更新。这种方式需要依靠某种同步操作,如互斥锁和信号量等,可以说这是最有用的进程间通信方式。
  • 消息队列(Message queue):消息队列是由消息组成的链表,存放在内存中并由消息队列标识符标识。消息队列克服了信号传递信息少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。消息队列与管道通信相比,其优势是对每个消息指定特定的消息类型,接收的时候不需要按照队列次序,而是可以根据自定义条件接收特定类型的消息。
  • 套接字(Socket):Socket 套接字是一种通信机制,凭借这种机制,客户/服务器(即要进行通信的进程)系统的开发工作既可以在本地单机上进行,也可以跨网络进行。也就是说它可以让不在同一台计算机但通过网络连接计算机上的进程进行通信。也因为这样,套接字明确地将客户端和服务器区分开来

🚁线程间同步的方式有哪些?

线程同步是两个或多个共享关键资源的线程的并发执行。应该同步线程以避免关键的资源使用冲突,操作系统一般有下面三种线程同步的方式:

  • 互斥量(Mutex):采用互斥对象机制,只有拥有互斥对象的线程才有访问公共资源的权限。因为互斥对象只有一个,所以可以保证公共资源不会被多个线程同时访问。比如 Java 中的 synchronized 关键词和各种 Lock 都是这种机制。
  • 信号量(Semphares) :它允许同一时刻多个线程访问同一资源,但是需要控制同一时刻访问此资源的最大线程数量。
  • 事件(Event) :wait/notify,通过通知操作的方式来保持多线程同步,还可以方便的实现多线程优先级的比较操作。

🚁进度调度算法有哪些?

  • 先来先服务(FCFS)调度算法 : 从就绪队列中选择一个最先进入该队列的进程为之分配资源,使它立即执行并一直执行到完成或发生某事件而被阻塞放弃占用 CPU 时再重新调度。
  • 短作业优先(SJF)的调度算法 : 从就绪队列中选出一个估计运行时间最短的进程为之分配资源,使它立即执行并一直执行到完成或发生某事件而被阻塞放弃占用 CPU 时再重新调度。
  • 时间片轮转(RR)调度算法 : 时间片轮转调度是一种最古老,最简单,最公平且使用最广的算法,又称 RR(Round robin)调度。每个进程被分配一个时间段,称作它的时间片,即该进程允许运行的时间。
  • 优先级调度算法 : 为每个进程分配优先级,首先执行具有最高优先级的进程,依此类推。具有相同优先级的进程以 FCFS 方式执行。可以根据内存要求,时间要求或任何其他资源要求来确定优先级。
  • 多级反馈队列调度算法 :前面介绍的几种进程调度的算法都有一定的局限性。如短进程优先的调度算法,仅照顾了短进程而忽略了长进程 。多级反馈队列调度算法既能使高优先级的作业得到响应又能使短作业(进程)迅速完成,因而它是目前被公认的一种较好的进程调度算法,UNIX 操作系统采取的便是这种调度算法。

🚁什么是死锁?产生死锁的原因是什么?死锁产生的必要条件是什么?

定义:两个或两个以上的进程在执行过程中,因争夺共享资源而造成的一种互相等待的现象。若无外力作用,它们都将无法推进下去,此时称系统处于死锁状态或系统产生了死锁。

死锁产生的原因

  • 系统资源不足。
  • 进程运行推进的顺序不合适
  • 资源分配不当

死锁的发生必须具备以下四个条件(缺一不可)

  1. 互斥条件:一个资源每次只能给一个进程使用。
  2. 请求和保持条件:进程在申请新的资源的同时保持对原有资源的占有。
  3. 不可剥夺条件:资源申请者不能强行的从资源占有者手中夺取资源,资源只能由占有者自愿释放。
  4. 循环等待条件:存在一个进程等待队列 {P1 , P2 , … , Pn},其中 P1 等待 P2 占有的资源,P2 等待 P3 占有的资源,…,Pn 等待 P1 占有的资源,形成一个进程等待环路。

那么避免死锁问题就只需要破环其中⼀个条件就可以,最常见的并且可行的就是使用资源有序分配法,来破坏循环等待条件

🚁什么是中断,有什么作用?

CPU 上会运行两种程序,一种是操作系统内核程序,另一种是应用程序。其中,操作系统内核程序是整个系统的管理者。

中断,也称外中断,是系统正常功能的一部分。例如,因进程调度使系统停止当前进程的执行而转去执行其他的进程,或者因缺少所需资源而中断当前操作等待资源到达,在系统处理完其他事情之后,会继续执行中断前的进程。

异常,也成为内中断,是由错误引起的,如文件损坏、进程越界等。**通常异常引起中断,但是中断未必是由异常引起的。**中断是让操作系统夺回 CPU 使用权的唯一途径。

内核态→用户态:执行一条特权指令----修改PSW的标志位为 “用户态”,这个动作意味着操作系统主动让出 CPU 使用权。
用户态→内核态:由 “中断” 引发,硬件自动完成变态过程,触发中断信号意味着操作系统将强行夺回 CPU 的使用权。

java并行查询mysql java并行调用接口_操作系统_02

🚀什么是上下文切换?

线程在执行过程中会有自己的运行条件和状态(也称上下文),例如程序计数器,栈信息等。当出现如下情况的时候,线程会从占用 CPU 状态中退出。

  • 主动让出 CPU,比如调用了 sleep(), wait() 等
  • 时间片用完,因为操作系统要防止一个线程或者进程长时间占用CPU导致其他线程或者进程饿死
  • 调用了阻塞类型的系统中断,比如请求 IO,线程被阻塞
  • 被终止或结束运行

这其中前三种都会发生线程切换,线程切换意味着需要保存当前线程的上下文,留待线程下次占用 CPU 的时候恢复现场,并加载下一个将要占用 CPU 的线程上下文,这就是所谓的 上下文切换。

上下文切换是现代操作系统的基本功能,因其每次需要保存信息恢复信息,这将会占用 CPU,内存等系统资源进行处理,也就意味着效率会有一定损耗,如果频繁切换就会造成整体效率低下。

🚀什么是虚拟内存?

虚拟内存从逻辑上实现了对内存容量的扩充,让用户感觉到的内存容量比实际内存容量大得多,因此可以让内存空间更大的程序运行,或者让更多的用户程序并发运行,既满足了用户的需要又改善了系统的性能。

虚拟内存有三个特性:

  1. 多次性:一个作业中的程序和数据无需在作业运行时一次性全部装入内存,而是允许被分成多次调入内存运行,只需将当前要运行的那部分程序和数据装入内存即可开始运行,以后每当要运行到尚未调入的那部分程序时再将它调入。正是由于多次性的特征,才使它具有从逻辑上扩大内存的功能。
  2. 对换性:一个作业中的程序和数据,无需在作业运行时一直常驻内存,而是允许在作业的运行过程中进行换进、换出,亦即,在进程运行期间,允许将那些暂不使用的代码和数据从内存调至外存的对换区,待以后需要时再将从外存调至内存。
  3. 虚拟性:虚拟性是指能够从逻辑上扩充内存容量,使用户锁看到的内存容量远大于实际内存容量,有效改善内存的利用率并提高程序执行的并发程度,增加系统的吞吐量。