0


【秋招冲刺篇】5.20的正确操作===操作系统八股文

操作系统八股文

一,产生线程不安全的原因

1.线程是抢占式执行
导致两个线程里的先后顺序无法确定~
这样的随机性,是由操作系统内核决定的,是导致线程安全问题的根本所在。

2.多个线程修改同一个变量:

3.原子性
像++这样的操作就不是原子性的操作,我们可以加锁。
赋值或者一个步骤的操作是原子的
4.内存可见性
单线程下没有什么影响,但是到了多线程,就会引发不安全,
假设:
如果某个线程进行循环自增,那么涉及到多次LOAD,ADD,SAVE。
为了使结果读的更快,提高程序的效率,线程会把多次的LOAD和SAVE省略。变成了LOAD,ADD,ADD,SAVE,此时我另外一个线程去读取这个值,会发现值没有改变,是因为线程2还在add,值还在cpu里面。
(解决方法加上volatile,可以防止优化操作)
5.指令重排序
编译器会按照一个较为节省时间(或资源的路径去执行)

二.线程的所有状态

NEW:安排了,还没有开始工作
RUNNABLE:可工作的,又可以分为正在工作,和即将开始工作。
BLOCKED和WAITING:这几个都表示排队等待。
TERMINATED:工作完成了。

三, synchronized和volatile

synchronized:(既可以原子性,又可以保证内存可见性)
的本质功能,就是把并行变成串行,通过加锁,
锁竞争多个线程争同一个锁。
当然,为了防止程序员犯蠢,synchronized内部记录了这个锁是哪个线程所持有的。
synchronized修饰普通方法相当于,对this进行加锁,
synchronized修饰静态方法,相当于对类对象进行加锁。
内寸可见性:直接对内存进行操作。

volatile
往往一个线程读一个线程写会用到这个volatile
计算机中一般理解成可变的,用来保证内存可见性,但不能保证原子性

四.Wait和notify(都是Object方法)

举例:比如,亿万富翁小明去银行的ATM机去取钱,同样,在他身后还有一群人准备取钱,小明发现ATM钱不够,可是他又着急取钱,此时就需要我们的工作人员把他带走,去取钱,让后面的人先取钱。
如果,工作人员,直接放,无限多的钱到ATM机中,这些人又需要同时的去竞争这个ATM。

这就好比,从一个就绪队列转换到阻塞队列中去,

Wait 的作用
1.将当前代码执行的线程,放到等待队列中。
2.释放当前锁
3. 满足一定条件被唤醒,重新获取到锁。

在这里插入图片描述
结果是 Wait之前证明是在Wait之前就结束了

Wait的使用

Wait的使用必须要在synchronized中且调用Wait的锁对象是同一个才可以使用
这个条件之一就是 Notify,有了Notify才能重新获取到锁。

Notify和NotifyAll
一个是唤醒Wait的线程,另外一个全部线程唤醒。

Wait和Sleep的区别
1.等待时间
Sleep可以指定一个固定时间进行阻塞等待,
Wait既可以指定时间,也可以无限等待。
2.唤醒方式
Wait使用notify来唤醒,而sleep等到时间到了或者interrup来唤醒
3.用途
Wait是用来调整线程的先后顺序,Sleep单纯让某一线程休眠,并不涉及多线程(虽然Sleep也能进行顺序控制,但是这种控制不可靠。)

五.单例模式以及单例模式的实现

(这里的设计模式就相当于棋谱一样,程序员按照相应的模式,来进行相应的操作)
懒汉模式:用到的时候才创建实例

publicclassMain{staticclassSingleton{//饿汉模式privateSingleton(){}privatestatic Singleton instance =null;publicstatic  Singleton getInstance(){if(instance==null){
              instance =newSingleton();}return instance;}}publicstaticvoidmain(String[] args){
      Singleton instance =   Singleton.getInstance();}}

我们仔细看这个代码会发现问题,当这个代码的main中没有实例的
instance的话,直接调用getInstance()方法会出错,涉及到线程安全问题。
所以我们需要把这个判断全部加上锁,保证这两个操作都是原子性的
(但是锁会导致资源开销变大,所以再进行判断,目的要让第一次成为线程安全的)

if(instance==null){
synchronized(Singleton.class)
if(instance==null){
              instance =newSingleton();}return instance;}}

饿汉模式:开始的时候直接创建实例

publicclassMain{staticclassSingleton{//饿汉模式privateSingleton(){}privatestatic Singleton instance =newSingleton();publicstatic  Singleton getInstance(){return instance;}}}

六.队列的分类

都知道有栈和对列,但是实际上对列才是最常用的,栈不常用。
这里的对列又分为。
优先队列:按优先级先进先出的对列

消息队列:对列里的数据有一定的分类信息,出队列的时候,不是单纯的先进先出,而是按照分类作为维度,让某个类的元素先进先出。
详细用到的场景:医院里面 做检查有很多类型。

阻塞对列:阻塞对列和以上两种对列不同,阻塞队列不为空,线程是安全的。
从以下两方面来谈
当对列为空,我们出对列会发生阻塞,直到有元素为止。
当对列满了,入队列会发生阻塞,直到有元素出队列为止。
有了阻塞对列就可以实现生产者消费者模型。
在计算机中,生产者是一组线程,消费者也是一组线程
判断一个代码是否好的标准指的是看代码,是否是高内聚,低耦合
低耦合指的是两个代码片段关系是否,比较紧密。
用这个模型可以有效的解耦合,
1.解耦合
因为假设A要给B传输数据,只能a和b传,到时候我想让a传给c,需要该大量的代码。
因此我们使用生产者消费者模型,在a和b的中间加入一个阻塞队列。a把数据产生到对列,b从对列里面拿数据。这样就让耦合降低了。
2.肖峰填谷
有了大坝我们的水就可以得到有效的保护,避免水流太大。
把高峰填到低谷期。
当用户一大批需求冲入网关(服务器入口)会有一个阻塞队列将需求缓存,然后被具体服务器接受。避免服务器崩溃。
在这里插入图片描述


本文转载自: https://blog.csdn.net/m0_57315623/article/details/124677112
版权归原作者 卷测开的快乐人 所有, 如有侵权,请联系我们删除。

“【秋招冲刺篇】5.20的正确操作===操作系统八股文”的评论:

还没有评论