2020最新B站面试经历,含答案!

本文详述了一次2020年的B站面试经历,涉及操作系统中的自旋锁概念及其优缺点,Java实现自旋锁的代码示例,对比了自旋锁与非自旋锁的差异。还讨论了多种I/O模型,包括阻塞IO、非阻塞IO、IO复用模型、信号驱动IO和异步IO。此外,文章提到了缓存穿透和缓存雪崩问题及其解决方案,以及Redis的淘汰策略。在数据库方面,讲解了MySQL的锁机制、行锁与表锁的应用,以及B+树和事务恢复的undo/redo日志。最后,介绍了基本数据结构,如LRU、循环链表和跳表,以及它们在实际场景中的应用。
摘要由CSDN通过智能技术生成

1 操作系统相关

自旋锁和一般锁的区别是什么?为什么要使用自旋锁?
当一个线程在获取锁的时候,如果这个锁已经被其他线程获取,那么这个线程不会破门而入,而是循环等待,但是嗷嗷待哺,需要不断地嗷嗷叫判断锁是否被成功获取,直到获取到锁才会退出循环。

自旋锁通常会出现哪些问题?
如果某个线程拿着锁死不放手,其他线程没法拿到这把锁,只好等待获取锁的线程进入循环等待的状态,等待不是睡觉,还是会消耗CPU,等待久了就会导致CPU的使用率太高。

那么自旋锁和其他锁到底有啥不同?
从线程状态来看,自旋锁的状态是运行-运行-运行。而非自旋锁的状态是运行—阻塞—运行,所以自旋锁会更高效。

不管是什么锁,都是为了实现保护共享资源而提出的一种锁机制,都是为了对某项资源的互斥使用。对于互斥锁而言,如果资源已经被占用,那么资源的申请者只会进入睡眠的状态。而自旋锁不会引起调用者睡眠,而是一直循环在那里查看该自旋锁的保持着是否已经释放了锁。

那么在Java中如何去实现一个自旋锁
public class SpinLock {
private AtomicReference cas = new AtomicReference();
public void lock() {
Thread current = Thread.currentThread();
// 利用CAS
while (!cas.compareAndSet(null, current)) {
// DO
}
}
public void unlock() {
Thread current = Thread.currentThread();
cas.compareAndSet(current, null);
}
}
上段代码中,方法lock利用的CAS,当线程A获取锁的时候,成功获取不会进入while循环。如果此时线程A没有释放锁,当线程B来获取锁的时候,由于不满足CAS,就会进入whilei循环,不断判断是否满足CAS,直到线程A调用unlock释放。

自旋锁有哪些优点?
因为运行在用户态,没有上下文的线程状态切换,线程一直处于active,减少了不必要的上下文切换,从而执行速度较快
因为非自旋锁在没有获取锁的情况下会进入阻塞状态,从而进入内核态,此时就需要线程的上下文切换,因为阻塞后进入内核调度状态,会导致用户态和内核态之间的切换,影响锁的性能。
了解哪些I/O模型?select是阻塞IO吗?
首先将IO模型给安排一遍,然后把自己很熟悉的IO模型详细说一波并介绍出应用场景,这个装的X就算比较完美,具体的非常详细的在下一篇文章,这里简要说一波。这一部分在上一篇详细阐述过
阻塞IO

我们知道在调用某个函数的时候无非就是两种情况,要么马上返回,然后根据返回值进行接下来的业务处理。当在使用阻塞IO的时候,应用程序会被无情的挂起,等待内核完成操作,因为此时的内核可能将CPU时间切换到了其他需要的进程中,在我们的应用程序看来感觉被卡主(阻塞)了。
在这里插入图片描述

非阻塞IO

当使用非阻塞函数的时候,和阻塞IO类比,内核会立即返回,返回后获得足够的CPU时间继续做其他的事情。
在这里插入图片描述

IO复用模型

当使用fgets等待标准输入的时候,如果此时套接字有数据但不能读出。IO

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值