每天一套面试题Day3-美图高频(1)

1.如何创建线程池?线程池常见参数有哪些?

核心线程数 最大线程数 最大空闲时间,拒绝策略

ThreadPoolExecutor构造函数或Executors工具类 最大空闲时间->非核心线程空闲时长,

2.HashMap底层原理和扩容机制

数组+链表 数组+链表/红黑树(JDK8以及之后,在 ?时会变成红黑树 当元素数目大于因子(0.75)×?的时候,会发生扩容,扩容为原来的两倍,在jdk7之前要重新计算来确定位置,由于要么位置在原位置,要么在原位置+原数组长度,所以用哈希值与上原数组长度大小的二倍,如果为真,那么就在原位置+原数组长度,不然的话就不动。确定好在哈希桶的位置后,再尾插进对应的位置。

默认初始容量16,负载因子0.75,当元素数量超过(容量×负载因子)发生扩容。链表长度超过8且数组长度≥64时会转为红黑树,提升查询效率。

3.ArrayList和LinkedList区别

主要是因为底层实现不同而导致的优劣势不同。ArrayList底层是数组,所以根据序号访问比较快,可以直接根据索引计算位置定位。但是涉及到改变位置的增删就比较慢。LinkedList底层是双向链表,所以首尾删除都很快,但是要访问的话,我们就不得不遍历,因此相对慢,由于每个节点要保留指针,所以内存占比相对大一些。

ArrayList基于动态数组。 ArrayList内存连续但可能预留空间,LinkedList每个节点含前后指针更占内存。线程均不安全,适用场景取决于读写操作比例。

4.JVM内存模型

分为线程共享和不共享的。线程共享的有:堆,存放对象实例;方法区,存放类型信息,比如说类的修饰符,全限定名,字段信息,方法信息,即时编译的??还有final修饰的,字符串常量在JDK7以及之前也放在方法区中,后面考虑到内存管理的方便,所以放在了堆中。线程不共享的区域,也就是随线程生而生,随线程灭而灭的有程序计数器,存放指向当前命令的指针?虚拟机栈,存放方法的局部变量和形参,本地方法栈,和虚拟机栈类似,但是对应的是native方法

程序计数器存放的是当前线程正在执行的指令的地址(或偏移量),而不是指向当前命令的指针。 方法区有即时编译器(Just-In-Time Compiler)编译后的代码缓存(将热点代码编译成本地机器码),方法信息(方法的字节码),运行时常量池(编译期生成的各种字面量,声明为 final 的常量值)

5.垃圾回收算法

引用垃圾收集

标记-复制(适合新生代),标记-清除算法,标记-整理算法

引用计数式垃圾收集(直接收集)

追踪式垃圾收集(间接垃圾收集) 可达性分析算法

标记-清除算法(在某些收集器 老年代)

会产生内存碎片

标记-复制算法(适合新生代)

标记-整理算法(为老年代设计)

6.Redis的数据类型

经典五种,String,Hash,适合对象的存储,Set,适合存放不重复的集合,比如共同关注,Zset,带有数字分数的集合,可以自动排序,适合存储班级排名等,List,适合存放有序的,有先后顺序的, BitMap,位图,存储二值,适合比如签到打卡 Stream,用于消息队列 GEO,找周围位置

+HyperLogLog,提供不精确的去重计数。在输入元素的数量或者体积非常非常大时,计算基数所需的内存空间总是固定的、并且是很小的。传统统计UV的问题:需要记录每个用户的ID,用户量巨大时内存消耗大。UV(Unique Visitor)即独立访客数,是指一段时间内访问网站的不同用户的数量 String,分布式锁,计数器 List,消息队列 GEO,读[ˈdʒiːəʊ]

7.Redis的持久化策略

RDB, AOF, RDB和AOF混合

RDB通过定时生成数据快照生成,适合快速恢复但是可能丢失部分数据(还没来得及下次快照生成的时候,发生了断电,这时候就丢失了)。 AOF记录所有写操作命令,数据完整性更高但文件较大。 Redis支持混合持久化模式(AOF+RDB),结合两者优势。

8.缓存穿透,击穿,雪崩的区别

他们都是大量请求达到了数据库 缓存雪崩是大量键值对同时失效, 缓存穿透是访问原本不存在的 缓存击穿是热key失效

9.Redis如何与数据库保持双写一致性

不知道什么是双写一致性,猜一下 先删除缓存,再写入数据库❌

双写一致性 指的是,当我们同时使用了数据库(持久化存储)和 Redis(缓存)时,如何保证对一个数据进行更新后,两者存储的数据是相同的。 双写一致性可能会面临并发问题(读写,写写等), Redis和数据库是两个独立系统,可能一个成功一个失败。

1.并发问题

  • 更新缓存和数据库,如果并发两个写,会因为并发导致数据库和缓存数据不一致。

  • 这里可以用旁路缓存策略,也就是说先更新数据库中的数据,再删除缓存中的数据。这个顺序为什么是这样的呢,因为存在一个读写并发,如果先删除缓存,这时候另一个线程来读的话,发现缓存没有,它去数据库读到旧数据,这时候就把旧数据缓存到缓存中,这时候去更新数据库。最终就会发现redis中的数据还是旧的数据,但是数据库更新了,不一致了。 那我们怎么改善这种问题,可以用延迟双删,我们等另一个线程读完旧的数据库的数据,并且写完缓存再删除一次不就解决了吗

  • 延迟双删,顾名思义,先更新数据库中的数据,再删除缓存中的数据,然后延迟(睡眠一会),再删除一次。

  • 当然其实先更新数据库中的数据,再删除缓存中的数据。也存在读写并发,如果我们在缓存中没有读到,就去数据库获取一个旧数据,这时候另一个线程来写数据库,然后删除缓存,我们再把原来从数据库获取到的旧数据缓存在redis中,但是这样有一个问题,就是必须等另一个线程来写数据库,然后删除缓存,都做完之后,再去写缓存,本来写redis就比写sql要快很多,所以这种概率并不高。

  • 但是删了缓存的话,命中率变低,如果要求很高,那我们可以更新缓存+数据库,但是要解决数据库和缓存数据不一致,我们可以采取

  • 分布式锁,避免并发问题,写操作时加锁,确保同一数据串行更新。也就是请求执行"更新数据库 → 更新缓存"的完整操作序列。

  • 给缓存加上较短的过期时间,接受出现短暂的缓存不一致,但是缓存的数据反正会很快过期。

2.Redis和数据库是两个独立系统,可能一个成功一个失败。 更新数据库中的数据,再删除缓存中的数据,但是删除缓存中的数据失败了,其他请求打过来不还是不一致吗。

  • 消息队列重试机制。要删除的缓存中的数据加入消息队列,消费者来擦欧总,如果失败,会从消息队列重新读取。
  • 订阅 MySQL binlog,再操作缓存。更新数据库成功会产生一条日志,记录在 binlog 里。订阅这个日志,并且通过ACK机制确认处理这条更新log(也是通过消息队列,但是代码侵入性没有那么强)

10.乐观锁和悲观锁

乐观锁是乐观的,先认为它不会被其他线程写,可以设定一个值,如果发现这个值被改动了,才认为被修改。 悲观锁则不给其他的写入的机会,比如sychnoiszed

synchronized /ˈsɪŋkrəˌnaɪz/ 乐观锁假设操作冲突少,只在提交时检查数据是否被修改(如版本号机制),适用于读多写少场景。悲观锁预先加锁(如行锁、表锁),确保独占操作,适合写多场景,但影响并发性能。前者减少锁竞争,后者保证强一致性。

#面试真题#
全部评论

相关推荐

美团开奖了,谁说测开比后端薪资低?谁说前端比后端薪资低?好了你又要说后端可以争取sp、ssp,但是能拿到美团白菜offer的就已经算是人中龙凤了,拿到sp、ssp更是凤毛麟角!依旧劝退后端!你后端学历内卷炼狱!实习经历卷的爆!甚至无法入行!入行了也只是和测开、前端的一般!1.学历,最痛的一击!后端工程师的第一步,走得不是技术,而是学历!想要进入大厂?好好看清楚自己的身份证:没有名校背景,别想着进美团、字节、腾讯! 面试官看你的第一眼就会想:“呵,去,给你点面试机会,看看你的技术!”什么?你说自己有技术?不好意思,来点GitHub链接,Project经历,能让面试官笑着赶你走。你没个985、211,双一流,根本就无法站稳在这场技术竞赛的起点。你想进大厂,没学历,没技术!永远只有一个词—— “被无情拒绝”。2. 薪资:你不过是和前端、测开的一匹马“后端工程师薪资高?能进SSP就是牛逼!”SSP? 听起来像是你梦想的银河,但实际上能拿到这个级别的人 凤毛麟角,除非你在面试官面前像神话人物一样打了个响指,否则你连SSP的尾巴都摸不着。至于你说的“前端薪资不高”?别逗了,前端都在笑你呢, 他们搞个页面,工资比你写个亿级请求接口还多。你说你辛辛苦苦优化API、调度缓存,别人搞个UI设计就能多拿几千块。前端已经不止是个展示层了,他们赚得比你还轻松,而你不过是服务器上疯狂跑“CRUD操作”的那只笨重的工蚁。3. 后端的真正意义:修 Bug,解决问题,下一份工作还是修 Bug有多少人觉得后端是系统架构、数据库优化的高端战场?醒醒吧! 后端的真正使命:维护旧项目,修复别人留下的烂摊子。你觉得自己能构建一个完美的系统?不!你只会一边修复技术债务,一边打着 “重构” 的旗号,换来的是 “重构再重构” 的无尽循环。而且,别告诉我你能专心写代码。你又要写代码,又要看服务器日志,没事还得帮别人 修崩的数据库,给前端数据源做“格式化”。你就是那块永远处于消耗型工作的 “万金油”。4. 晋升?哈哈哈,你是在做梦!你以为后端开发是一条顺风顺水的快速晋升路线?错! 你永远只能在一个“程序员”的岗位上打转,或者你为自己设立目标:“我要成为架构师”,那真的是在妄想。架构师?高级开发?靠近那条道路,你的心脏会先被晋升难度给捏住,你前方只有一座座高不可攀的技术山。别看那些SSP,架构师,架构啥呀?公司里的架构都是前端架构师,你就坐在后端的角落里,照顾着你那些满是错误的API和服务器。5. 加班?还是加班!你以为后端开发能像文艺片那样“偶尔加个班”?哈哈,傻了吧! 后端开发的生活是无休止的加班和修bug,你不仅要写接口,还得守夜调度、监控系统性能。就连你写的那个“完美的数据库查询”,也可能在 第二天 被前端因为“页面卡顿”给打回原形。“没有加班,你还能吃什么饭?”你说你是程序员,结果你的生活全是 熬夜加班、调试、重启。前端跑个页面,喝个咖啡就能过关,而你呢,熬夜跟数据库调试,最后还是那个穷忙的死循环。6. 技术天花板:架构?技术深度?笑死了!后端开发的天花板?那不过是个永远也摸不着的架构师“梦想”,你能掌握几款框架、几种数据库、两三套微服务架构,最后也不过是个 管理端的“搬运工”。你没办法“打破天花板”,更没有机会跳出“自己写个爬虫”或者“API接口”的死循环。技术深度?你也不过是 “技术债务”的修复者,一天到晚都在修补“老旧系统”的缺陷,偶尔听前端同学聊聊他们React、Vue的最新版本,你根本无法理解他们说的是什么。
开心小狗🐶:感觉后端有点像考研的0812,报名的时候都想冲0812,看不上0854。但是真入学了,不都是众生平等
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务