2021年面试问题记录

20 篇文章 0 订阅
20 篇文章 3 订阅
本文详细介绍了Java中的缓存穿透和雪崩问题及其解决方案,包括对空值的缓存处理和使用Bitmap进行过滤。同时,讲解了Nginx的正向代理和反向代理概念,以及其处理HTTP请求的反应器模式。此外,还探讨了如何使用JVM工具排查CPU100%的问题,包括定位问题进程和线程。最后,提到了MongoDB在大数据存储中的应用和JVM线程安全与并发问题。
摘要由CSDN通过智能技术生成

Redis

1.什么是缓存穿透?什么是缓存雪崩?如何避免?

答:

缓存穿透

       一般的缓存系统,都是按照key去缓存查询,如果不存在对应的value,就应该去后端系统查找(比如DB)。一些恶意的请求会故意查询不存在的key,请求量很大,就会对后端系统造成很大的压力。这就叫做缓存穿透。

避免方法:

         1.对查询结果为空的情况也进行缓存,缓存时间设置短一点,或者该key对应的数据insert了之后清理缓存。

         2.对一定不存在的key进行过滤。可以把所有的可能存在的key放到一个大的Bitmap中,查询时通过该bitmap过滤。

缓存雪崩

        当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,会给后端系统带来很大压力。导致系统崩溃。

如何避免?

         1.在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。

         2.做二级缓存,A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期

         3.不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。

Ngix

什么是正向代理?

一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。

  • 客户端才能使用正向代理。
  • 正向代理总结就一句话:代理端代理的是客户端。例如说:? 我们使用的代理软件等等。

什么是反向代理?

反向代理(Reverse Proxy)方式,是指以代理服务器来接受 Internet上的连接请求,然后将请求,发给内部网络上的服务器并将从服务器上得到的结果返回给 Internet 上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。

反向代理总结就一句话:代理端代理的是服务端。

请解释Nginx如何处理HTTP请求

  Nginx使用反应器模式。主事件循环等待操作系统发出准备事件的信号,这样数据就可以从套接字读取,在该实例中读取到缓冲区并进行处理。单个线程可以提供数万个并发连接。

MongDB

MongoDB能为我解决哪些问题?

       一般来讲,我会将MySQL中的部分表迁移到MongoDB中,主要是涉及到车辆历史轨迹以及温湿度数据等机器采集到的数据,而订单数据、客户数据等信息,仍然放到MySQL数据库中,主要是因为这两类数据实时采集,实时更新,会随着时间的推移,项目的扩大(PAAS服务),造成非常巨大的数据量,而一般MySQL在单表数据量超过500万后,性能就会下降的比较快,虽然可以通过分表的方式进行处理,但是随着时间的增长,仍然会给我带来比较大的麻烦(如查询等),这样,就不如将其放到MongoDB中存储,查询什么的都会比较方便,不过需要注意根据片键分片哦。

JVM

如何排查一次CPU100%的情况

    当我们把服务发布到服务器器,可能会因为一些问题造成我们的服务器CPU被打满甚至超过100%,那如果我们想知道到底上在做什么操作导致CPU持续过高呢?因为在线上,我们只能通过日志看问题,或者排查到哪个进程或者哪个线程持续占用CPU。然后才能找到具体问题在哪里才能进行解决。

所以这里我们模拟一个死循环导致CPU过高的情况,然后如何快速的找到问题在哪。

一、问题代码案例

我们这里只是写了一段死循环的代码,我们把它放到服务器上门直接用java命令跑起来。

public class DumpDemo {
    public static void main(String[] args) {
        do{
            System.out.println("-------------死循环e----------------");
        }while(true);
    }
}

不过在服务器上,如果只是一个死循环,其实上用不了多少CPU的,我们就假设这是一个有问题的代码。

二、排查问题

查找进程

当发现CPU过高之后,首先我们要找出哪个进程占用了CPU。我们可以使用top命令

top -c

    在显示模式下,然后我们可以通过切换到大写,不断的按大写P就能进行排序,找到最大的CPU看看上哪个进程。
在这里插入图片描述
可以看到进程PID 为 26045的消耗最高。

查找线程

    我们已经找到了哪个进程最消耗CPU了,接下来,我们当然要找到该进程下,哪个线程CPU消耗最高咯。这里的进程PID是26045,使用如下命令。

top -Hp PID 显示进程PID下所有的线程

 

在这里插入图片描述
到此我们已经定位到线程了,接下来我们就该用上jvm的命令工具了。

定位问题代码

    定位到线程26046消耗CPU最高,但是这里我们需要将26046这个线程转为16进制的。因为jvm的进程快照中线程显示是16进制的。
在这里插入图片描述
然后我们使用jstack命令,拉到26045进程快照信息,输出到文件中,方便我们查看。

jstack -l 26045 > ./26045.stack 

 

然后我们cat该文件,并且grep通过16进制找一下该线程。

cat 26045.stack | grep '65be' -C 20

 

在这里插入图片描述

至此我们就已经找到了问题代码在哪了。接下来的事情就是去分析代码为啥有问题咯,完美收公。

 


1.java hashmap 数据结构

HashMap也是我们使用非常多的Collection,它是基于哈希表的 Map 接口的实现,以key-value的形式存在。在HashMap中,key-value总是会当做一个整体来处理,系统会根据hash算法来来计算key-value的存储位置,我们总是可以通过key快速地存、取value。
定义:HashMap实现了Map接口,继承AbstractMap。其中Map接口定义了键映射到值的规则,而AbstractMap类提供 Map 接口的骨干实现,以最大限度地减少实现此接口所需的工作,其实AbstractMap类已经实现了Map,这里标注Map, 我觉得应该是更加清晰吧!

2.什么是线程不安全 和线程安全?(解释并发问题)


当我们在做压测或并发测试时,经常会遇到此问题

举例说明:假设售票系统有1000张票,A和B同时来买票,如果是线程不安全,那么可能售票系统可能出现
1000-1去同时执行的情况,最终结果是A和B都买完后剩下999张票,而不是998张。

1、线程安全:

指多个线程在执行同一段代码的时候采用加锁机制,使每次的执行结果和单线程执行的结果都是一样的,不
存在执行程序时出现意外结果。

2、线程不安全:

是指不提供加锁机制保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据。


3.mysql 索引结构

看这里吧


Mysql目前主要有以下几种索引类型:FULLTEXT,HASH,BTREE,RTREE。
BTREE索引就是一种将索引值按一定的算法,存入一个树形的数据结构中(多路平衡查找树),每次查询都
是从树的入口root开始,依次遍历node,获取leaf。这是MySQL里默认和最常用的索引类型。


4.streambuilder与加号字符串区别


字符串拼接在开发过程中是非常平凡的常用的有三种方式
1、加号拼接(str+“123”)
2、StringBuilder拼接
3、StringBuffer拼接
StringBuffer是保证线程安全的,效率是比较低的,更多的应用场景是不会涉及到线程安全,所以会选择StringBuilder效率会高一些

通过查看字节码(反编译分析)发现 m1的方法内每次循环都会传递一个StringBuilder对象,效率低于m2()方法
总结 “+”和StringBuilder两种拼接方式是一样的,所以效率是一样的,但是在for循环中,使用“+”号拼接,每循环一次都要重新创建一个StringBuilder对象用来存储新的字符串,所以在for循环中 StringBuilder效率更高

5.内存溢出 内存泄漏

看这里

6.Arraylist Linkedklist

看这里

7.mysql事务隔离级别

推荐这里

事务隔离级别脏读不可重复读幻读
读未提交(read-uncommitted)
不可重复读(read-committed)
可重复读(repeatable-read)
串行化(serializable)

8.bean注解

推荐看这里

9.说一下 HashMap 的实现原理?

HashMap概述: HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。 

HashMap的数据结构: 在java编程语言中,最基本的结构就是两种,一个是数组,另外一个是模拟指针(引用),所有的数据结构都可以用这两个基本结构来构造的,HashMap也不例外。HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。

当我们往Hashmap中put元素时,首先根据key的hashcode重新计算hash值,根绝hash值得到这个元素在数组中的位置(下标),如果该数组在该位置上已经存放了其他元素,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放入链尾.如果数组中该位置没有元素,就直接将该元素放到数组的该位置上。

需要注意Jdk 1.8中对HashMap的实现做了优化,当链表中的节点数据超过八个之后,该链表会转为红黑树来提高查询效率,从原来的O(n)到O(logn)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

liumce

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值