操作系统是什么(粗浅的解释就可以)
操作系统首先是一个程序,是世界上最早的并发程序之一。操作系统很重要的一个功能就是让多个程序可以加载到计算机内存能够一起运行,并且它们互相之间隔离,没有干扰。
什么是进程?什么是线程?二者有什么关联
进程
- 程序执行时的一个实例
- 每个进程都有独立的内存地址空间
- 系统进行资源分配和调度的基本单位
- 进程里的堆,是一个进程中最大的一块内存,被进程中的所有线程共享的,进程创建时分配,主要存放 new 创建的对象实例
- 进程里的方法区,是用来存放进程中的代码片段的,是线程共享的 在多线程 OS中,进程不是一个可执行的实体,即一个进程至少创建一个线程去执行代码
线程
- 进程中的一个实体
- 进程的一个执行路径
- CPU 调度和分派的基本单位
- 线程本身是不会独立存在
- 当前线程 CPU 时间片用完后,会让出 CPU 等下次轮到自己时候在执行
- 系统不会为线程分配内存,线程组之间只能共享所属进程的资源
- 线程只拥有在运行中必不可少的资源(如程序计数器、栈)
- 线程里的程序计数器就是为了记录该线程让出 CPU 时候的执行地址,待再次分配到时间片时候就可以从自己私有的计数器指定地址继续执行
- 每个线程有自己的栈资源,用于存储该线程的局部变量和调用栈帧,其它线程无权访问
进程和线程为什么存在
进程存在的意义:为了实现多道程序的并发。
线程存在的意义:每个进程都有自己的地址空间,即进程空间。一个服务器通常需要接收大量并发请求,为每一个请求都创建一个进程系统开销大、请求响应效率低,因此操作系统引进线程。其实线程也就是进程的弱化版。
线程和进程之间存在什么关系
-
进程是CPU资源分配的最小单位;线程是CPU调度的最小单位
-
一个线程只能属于一个进程;而一个进程可以有多个线程,但至少有一个线程。线程依赖进程而存在。
-
进程有独立的系统资源,而同一进程内的线程共享进程的大部分系统资源,包括堆、代码段、数据段;每个线程只拥有一些在运行中必不可少的私有属性,如TCB、线程ID、栈、寄存器。
-
系统开销:
在创建或撤销进程时,系统都要为之分配或回收资源,如内存空间、I/O设备等,因此开销较大;
而线程切换只需保存和设置少量的寄存器内容,并不涉及存储器管理方面的操作。 -
通信:进程通信比较复杂;而同一进程的线程由于共享代码段和数据段,所以线程通信比较方便。由于同一进程中的多个线程具有相同的地址空间,致使它们之间的同步通信的实现比较容易。线程的切换、同步和通信都无需操作系统内核的干预。
-
进程间不会相互影响;一个线程挂掉将导致同一进程内的其他线程也挂掉。多进程程序更加安全,进程间互不影响;多线程程序不易维护,线程间相互影响
-
进程适用于多核、多机分布;线程适用与多核
多进程和多线程之间应该如何选择
- 多进程适用场景:弱相关的任务,需要扩展到多机分布的任务
- 多线程适用场景:需要频繁创建和销毁的任务(如Web服务器),需要进行大量计算的任务,强相关的任务,需要扩展到多核分布的任务
多线程模型主要优势在于线程间切换代价较小,
- 适用于I/O密集型的工作场景;//因此I/O密集型的工作场景经常由于I/O阻塞导致频繁的切换线程。
- 适用于单机多核分布式场景。
多进程模型:
- 适用于CPU密集型
- 适用于多机分布式场景,//易于多机扩展
线程应该共享什么?不应该共享什么?
共享的资源有:
-
堆。 由于堆是在进程空间中开辟出来的,所以它是理所当然地被共享的;因此new出来的都是共享的(16位平台上分全局堆和局部堆,局部堆是独享的)
-
全局变量 。它是与具体某一函数无关的,所以也与特定线程无关;因此也是共享的
-
静态变量。 虽然对于局部变量来说,它在代码中是“放”在某一函数中的,但是其存放位置和全局变量一样,存于堆中开辟的.bss和.data段,是共享的
-
文件等公用资源。 这个是共享的,使用这些公共资源的线程必须同步。Win32 提供了几种同步资源的方式,包括信号、临界区、事件和互斥体。
独享的资源有:
- 栈 。栈是独享的
- 寄存器 。 这个可能会误解,因为电脑的寄存器是物理的,每个线程去取值难道不一样吗?其实线程里存放的是副本,包括程序计数器PC
什么是并发?什么是并行?两者有什么异同?
并发(Concurrent),在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行。
打游戏和听音乐两件事情在同一个时间段内都是在同一台电脑上完成了从开始到结束的动作。那么,就可以说听音乐和打游戏是并发的。
并行(Parallel),当系统有一个以上CPU时,当一个CPU执行一个进程时,另一个CPU可以执行另一个进程,两个进程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)。
这里面有一个很重要的点,那就是系统要有多个CPU才会出现并行。在有多个CPU的情况下,才会出现真正意义上的『同时进行』。
例子:我们两个人在吃午饭。你在吃饭的整个过程中,吃了米饭、吃了蔬菜、吃了牛肉。吃米饭、吃蔬菜、吃牛肉这三件事其实就是并发执行的。对于你来说,整个过程中看似是同时完成的的。但其实你是在吃不同的东西之间来回切换的。还是我们两个人吃午饭。在吃饭过程中,你吃了米饭、蔬菜、牛肉。我也吃了米饭、蔬菜和牛肉。我们两个人之间的吃饭就是并行的。两个人之间可以在同一时间点一起吃牛肉,或者一个吃牛肉,一个吃蔬菜。之间是互不影响的。
并发是指在一段时间内宏观上多个程序同时运行。并行指的是同一个时刻,多个任务确实真的在同时运行。
并发和并行的区别
并发,指的是多个事情,在同一时间段内同时发生了。
并行,指的是多个事情,在同一时间点上同时发生了。
并发的多个任务之间是互相抢占资源的。
并行的多个任务之间是不互相抢占资源的。
并发,并行,进程,线程,它们之间有什么关联吗?
并行与并发都是程序多线程处理场景,因此,一旦提到并行与并发,那首先想到的是多线程。
- 在CPU比较繁忙,资源不足的时候(开启了很多进程),操作系统只为一个含有多线程的进程分配仅有的CPU资源,这些线程就会为自己尽量多抢时间片,这就是通过多线程实现并发,线程之间会竞争CPU资源争取执行机会。
在CPU资源比较充足的时候,一个进程内的多线程,可以被分配到不同的CPU资源,这就是通过多线程实现并行。 - 至于多线程实现的是并发还是并行?上面所说,所写多线程可能被分配到一个CPU内核中执行,也可能被分配到不同CPU执行,分配过程是操作系统所为,不可人为控制。所有,如果有人问我我所写的多线程是并发还是并行的?只能说,都有可能。
- 不管并发还是并行,都提高了程序对CPU资源的利用率,最大限度地利用CPU资源。
为什么编写c程序的时候,即使你使用的是root的权限,你程序中的指针仍然不能访问其他程序的地址空间?这到底是是为什么?
这是因为操作系统提供了一种安全机制,称为内存保护,用于防止一个程序访问另一个程序的内存区域。内存保护通过内存管理硬件来实现,它可以阻止一个程序访问另一个程序的内存空间。因此,即使是root权限,也无法绕过保护机制,也无法访问另一个程序的地址空间。
内存保护机制是怎么工作的
内存保护机制是一种硬件机制,用于防止一个程序访问另一个程序的内存空间。它的工作原理是,当程序试图访问另一个程序的内存时,操作系统会检查相应的内存页表,看看是否有访问权限,如果没有访问权限,则会报错。
内存保护机制可以防止程序访问其他程序的内存,从而有效保护系统安全。而且,它还可以防止程序之间的竞争,防止程序之间的数据混乱,提高系统的稳定性。
多线程库应该怎么使用?能不能给出一些具体的例子?
1、Future模型
该模型通常在使用的时候需要结合Callable接口配合使用。
Future是把结果放在将来获取,当前主线程并不急于获取处理结果。允许子线程先进行处理一段时间,处理结束之后就把结果保存下来,当主线程需要使用的时候再向子线程索取。
Callable是类似于Runnable的接口,其中call方法类似于run方法,所不同的是run方法不能抛出受检异常没有返回值,而call方法则可以抛出受检异常并可设置返回值。两者的方法体都是线程执行体。
2、fork&join 模型
该模型包含递归思想和回溯思想,递归用来拆分任务,回溯用合并结果。 可以用来处理一些可以进行拆分的大任务。其主要是把一个大任务逐级拆分为多个子任务,然后分别在子线程中执行,当每个子线程执行结束之后逐级回溯,返回结果进行汇总合并,最终得出想要的结果。
这里模拟一个摘苹果的场景:有 100 棵苹果树,每棵苹果树有 10 个苹果,现在要把他们摘下来。为了节约时间,规定每个线程最多只能摘 10 棵苹树以便于节约时间。各个线程摘完之后汇总计算总苹果树。
package thread.blogs.threadmodel;
import scala.Console;
import java.util.concurrent.*;
import java.util.concurrent.locks.ReentrantLock;
public class ForkJoin {
public static void main(String[] args) {
test