线程/进程
王道–操作系统 https://blog.csdn.net/weixin_43914604/article/details/104415990
进程和线程的区别-重点
进程和线程的区别:
-
进程是调度资源的基本单位,线程是执行任务的基本单位。
-
进程有自己的独立数据空间,程序切换的开销大,线程共享一个进程的数据空间,每个线程有自己独立的运行栈和程序计数器,线程之间开销小。
-
进程之间的资源隔离,共享复杂,线程的共享资源简单。
-
线程的目的是为了并发,因为线程上下文的切换快,可以提高并发效率。
为什么线程切换快
最主要的一个区别在于进程切换涉及虚拟地址空间的切换而线程不会。因为每个进程都有自己的虚拟地址空间,而线程是共享所在进程的虚拟地址空间的,因此同一个进程中的线程进行线程切换时不涉及虚拟地址空间的转换。
有的同学可能还是不太明白,为什么虚拟地址空间切换会比较耗时呢?
现在我们已经知道了进程都有自己的虚拟地址空间,把虚拟地址转换为物理地址需要查找页表,页表查找是一个很慢的过程,因此通常使用Cache来缓存常用的地址映射,这样可以加速页表查找,这个cache就是TLB(translation Lookaside Buffer,我们不需要关心这个名字只需要知道TLB本质上就是一个cache,是用来加速页表查找的)。由于每个进程都有自己的虚拟地址空间,那么显然每个进程都有自己的页表,那么当进程切换后页表也要进行切换,页表切换后TLB就失效了,cache失效导致命中率降低,那么虚拟地址转换为物理地址就会变慢,表现出来的就是程序运行会变慢,而线程切换则不会导致TLB失效,因为线程线程无需切换地址空间,因此我们通常说线程切换要比较进程切换块,原因就在这里。https://blog.csdn.net/qq_34417408/article/details/110393655
进程间通信方式,6种-重点
1.管道:单向的,所以需要两条管道;只能用于父子进程,兄弟进程(亲缘关系);数据先进先出;缓冲区是一个循环队列,满了之后会扔到阻塞队列里面
2.有名管道:不需要必须父子进程,兄弟进程;也是先进先出
3.信号:比如kill -9会发送SIGKILL信号
4.消息队列:消息队列在内存中,允许多个进程写入或者读取;也是先进先出
5.共享内存:多个进程可以读写同一块空间
6.socket
https://cloud.tencent.com/developer/article/1690556
孤儿进程和僵尸进程
孤儿进程表示父进程退出了,但是子进程还在运行,这些就是孤儿进程,孤儿进程会被init进程(进程号为1)回收,所以基本不会有问题。
僵尸进程是子进程正常退出,会给父进程发送信号,告诉父进程释放掉进程号,但是如果父进程不选择接受,不调用wait/waitpid,进程号将不会被释放。
https://www.cnblogs.com/anker/p/3271773.html
select,poll和epoll-重点
https://www.cnblogs.com/aspirant/p/9166944.html
https://www.bilibili.com/video/BV1uK4y1S7iQ
epoll两种工作模式
水平触发(没写完不断通知),边缘触发(只通知一次),LT是默认的模式,ET是“高速”模式。LT模式下,只要这个fd还有数据可读,每次 epoll_wait都会返回它的事件,提醒用户程序去操作,而在ET(边缘触发)模式中,它只会提示一次,直到下次再有数据流入之前都不会再提示了,无 论fd中是否还有数据可读 => https://www.jianshu.com/p/73e9ef7902e1
进程调度算法
先进先出,最短耗时优先,时间片轮转,多级反馈队列。
https://www.jianshu.com/p/ecfddbc0af2d
Java中创建线程的四种方式
https://www.huaweicloud.com/articles/c0553b1cde014350e91620af1ce89f68.html
1.继承Thread类
2.实现runable接口
3.callabel和future接口
4.线程池
怎样判断一个线程是否是启动状态
isAlive()
进程的同步与互斥
信号量机制 --> 多线程
多线程
线程池 参数
7大参数 核心线程数 最大线程数 阻塞队列 拒绝策略 超时释放 超时单位 线程工厂
拒绝策略handler种类
-
AbortPolicy
-
CallerRunsPolicy
-
DiscardPolicy
-
DiscardOldestPolicy
线程池中初始化线程种类
线程池执行过程
1.核心线程数>? 2.阻塞队列>? 3.最大线程数>? 决绝策略?
死锁
四个条件,预防检测,都必须理解。
死锁四个条件
互斥(每个资源只能被一个进程占用)
不可抢占(进程已获得的资源,在末使用完之前,不能强行剥夺)
占有且等待(一个进程因请求资源而阻塞时,对已获得的资源保持不放
循环等待(若干进程之间形成环状的等待)。
死锁预防:破坏四个条件其中一个。
https://blog.csdn.net/zhangpower1993/article/details/89518780
- 破坏互斥:使资源同时访问而非互斥使用,就没有进程会阻塞在资源上,从而不发生死锁。
只读数据文件、磁盘等软硬件资源均可采用这种办法管理;
但是许多资源是独占性资源,如可写文件、键盘等只能互斥的占有;
所以这种做法在许多场合是不适用的。 - 破坏占有且等待条件:
采用静态分配的方式,静态分配的方式是指进程必须在执行之前就申请需要的全部资源,且直至所要的资源全部得到满足后才开始执行
实现简单,但是严重的减低了资源利用率。
因为在每个进程占有的资源中,有些资源在运行后期使用,有些资源在例外情况下才被使用,可能会造成进程占有一些几乎用不到的资源,而使其他想使用这些资源的进程等待。 - 剥夺调度能够防止死锁,但是只适用于内存和处理器资源。
方法一:占有资源的进程若要申请新资源,必须主动释放已占有资源,若需要此资源,应该向系统重新申请。
方法二:资源分配管理程序为进程分配新资源时,若有则分配;否则将剥夺此进程已占有的全部资源,并让进程进入等待资源状态,资源充足后再唤醒它重新申请所有所需资源。 - 破坏循环等待:
给系统的所有资源编号,规定进程请求所需资源的顺序必须按照资源的编号依次进行。
采用层次分配策略,将系统中所有的资源排列到不同层次中
一个进程得到某层的一个资源后,只能申请较高一层的资源
当进程释放某层的一个资源时,必须先释放所占有的较高层的资源
当进程获得某层的一个资源时,如果想申请同层的另一个资源,必须先释放此层中已占有的资源
死锁检测算法:
每种类型一个资源的死锁检测算法是通过检测有向图是否存在环来实现,从一个节点出发进行深度优先搜索,对访问过的节点进行标记,如果访问了已经标记的节点,就表示有向图存在环,也就是检测到死锁的发生。
java的检测方式-建议大家动手实践一下
https://blog.csdn.net/weixin_43767015/article/details/104710979
jps查看日志,jconsole可视化界面。
java解决死锁
加锁顺序一致,统一各个线程获取锁的顺序,并强制线程按照指定的顺序获取锁;
请求锁超时则返回,尝试获取锁时加一个超时时间,没获取到则不断回退,释放所有已经得到的锁;
等待中断,死锁后发送中断信号,利用ReentrantLock的lock.lockInterruptibly()方法接受中断,并释放锁。
哲学家就餐问题
https://blog.csdn.net/qq_28602957/article/details/53538329
虚拟内存
虚拟内存 使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上。每个进程有独立的地址空间,这个空间有许多页,这些页不用所有都在内存中才能运行程序,所以一部分存在磁盘中,需要的时候再映射
分段,分页
分段:进程被分为很多的段,要装入一个进程,需要将进程所有的段装入主存中不一定连续的动态分区。;分页:主存被分为很多大小相同的帧,进程被分为很多与帧大小相同的页。要装入一个进程,需要将进程所有的页装入主存,可以是不连续的帧中。https://blog.csdn.net/zouliping123/article/details/8869455
内核态和用户态的区别
内核态可以访问所有数据,包括硬盘,网卡,也可以切换程序。
用户态只能访问受限的内存,不能访问外围设备,占用CPU的能力被剥夺。
页面置换算法
先进先出,最近最久未使用LRU,opt最佳置换算法(理想情况)