美团一面

1、ArrayList 和 LinkList 区别

(1)ArrayList 基于数组,需要连续内存;LinkList 基于双向链表,不需要连续内存。

(2)ArrayList 随机访问快(可以根据下标访问);LinkedList 随机访问慢(需要迭代遍历)。

(3)ArrayList 插入和删除性能慢;LinkedList 插入和删除性能快。

2、ArraryList 扩容过程

分为两个步骤:

ArrarList默认大小是10,当集合个数大于容量的时候,就会以1.5倍容量去进行扩容,如果还不够大就在扩容后的1.5倍再扩容。扩容后要对原来的集合进行copy到新的集合中。

(在add()方法中调用确保内部容量方法,传入参数当前元素个数加一,当它大于实际数组大小的时候就调用grow()方法进行扩容。扩容是右移一位,进行扩容1.5倍,不够再进行扩容,通过copyof()方法进行数组的复制。)

3、hashmap 冲突怎么解决?

(1)开放地址法:也称线性探测法,就是从发生冲突的那个位置,按照一定次序从Hash表中找到一个空闲的位置, 把发生冲突的元素存入到这个位置。而在java种ThreadLocal就用到了线性探测法,来解决Hash冲突。

(2)链式寻址法:通过单向链表的方式来解决哈希冲突,Hashmap就是用了这个方法。(但会存在链表过长增加遍历时间)

(3)再哈希法:key通过某个哈希函数计算得到冲突的时候,再次使用哈希函数的方法对key哈希一直运算直到不产生冲突为止 (耗时间,性能会有影响)

(4)建立公共溢出区:就是把Hash表分为基本表和溢出表两个部分,凡是存在冲突的元素,一律放到溢出表中。

补充:在JDK1.8中HashMap通过链式寻址法以其红黑树来解决哈希冲突的,其中红黑树是为了优化哈希表的链表过长导致遍历时间复杂度增加的问题。当链表长度大于8并且哈希表的容量大于64,再向链表中添加元素,会转化为红黑树。

4、ConcurrentHashMap 如何实现线程安全?

JDK 1.7 给 Segment 添加 ReentrantLock 锁来实现线程安全。

JDK 1.8 通过 CAS synchronized 来实现线程安全。

5、sychronized 关键字如何实现线程安全?

synchronized 关键字可以实现线程安全,它的作用在于保证同一时间只有一个线程可以执行被 synchronized 关键字修饰的代码块或方法,从而避免了多个线程同时访问共享资源的情况。

具体来说,当一个线程进入一个对象或类的 synchronized 代码块或方法时,它将会获得一个锁。如果该锁已经被其他线程获得,则该线程将会阻塞,直到该锁被释放。只有当该线程执行完 synchronized 代码块或方法并释放锁时,其他线程才能获取该锁并执行相应的代码。

6、解释一下 minitor ?

synchronized底层使用monitor来控制锁的活动, wait(),notify(),notifyAll() 操作都与他有关,所以也必须在同步块能才能用。了解monitor中的各个属性值的含义,锁的竞争流程。

每个Java对象都可以关联一个Monitor对象,如果给这个Java对象使用了Synchronized加上了重量级锁,那么这个对象就会关联一个Monitor对象,在Mark Down中会有一个指针指向这个Monitor对象。

7、简述线程池工作原理?

线程池是一种用来管理线程的技术,它可以避免在程序执行时频繁地创建和销毁线程带来的性能消耗。线程池中的线程可以被重复利用,以完成多个任务。下面是线程池的工作原理:

(1)创建线程池:在程序启动时,创建一个线程池,将一定数量的线程放入线程池中,并等待任务的到来。

(2)提交任务:当有新的任务需要执行时,将其提交给线程池。

(3)任务处理:线程池中的某个线程会从等待队列中获取待执行的任务,并执行该任务。

(4)线程回收:当线程执行完任务后,该线程并不会立即被销毁,而是重新归入线程池,等待下一个任务的到来。

线程池按照线程数量分为两部分,分别是核心线程和非核心线程。当任务提交给线程池时,如果当前线程池中的线程数量小于核心线程数,则会立即创建一个新的线程来执行该任务。如果当前线程池中的线程数量已经达到核心线程数,但还有其他任务需要执行,则此时任务会被加入等待队列。如果等待队列已满,且当前线程池中的线程数量仍然小于最大线程数,则会创建非核心线程来执行任务。如果当前线程池中的线程数量已经达到最大线程数,此时再有新的任务提交,则会采取一定的拒绝策略。

通过线程池,我们可以有效地利用有限的计算资源,提高程序的执行效率和性能,降低系统的负载。

8、Redis 的数据类型?

Redis 支持五种数据类型,分别是string、hash、list、set和zset(sorted set)。

9、结合开发经验,用了那种Redis在实际业务?

缓存查询记录、缓存登录状态

10、Redis 分布式锁怎么实现?

Redis 分布式锁的实现,一般有以下两种方式:

  1. 基于 SETNX 命令实现使用 SETNX(key, value) 命令,若 key 不存在,则设置 key 的值为 value。若 key 已存在,则不进行任何操作。该命令具有原子性,即对于一个 key,只有一个客户端能够成功地对其设置值。因此,可以将 SETNX 命令用于分布式锁的实现中。具体实现步骤如下:

1)获取分布式锁时,利用 SETNX(key, value) 命令尝试将 key 设置为特定的值(例如 "locked");

2)如果返回值为 1,表示锁设置成功,客户端获取到了锁,可以开始执行任务了;

3)如果返回值为 0,表示锁已被其他客户端占用,客户端需要等待一段时间后重新尝试获取锁。在释放锁的时候,可以使用 Redis 的 DEL 命令将键值从 Redis 中删除来释放锁。

  1. 基于 Redission 框架实现Redisson 是一个基于 Java 实现的 Redis 客户端,它提供了丰富的分布式锁实现方案,包括可重入锁、公平锁、联锁、红锁、读写锁等。Redisson 支持使用单个 Redis 实例、多个 Redis 实例甚至是集群模式下的 Redis 进行分布式锁的实现。具体实现步骤如下:

1)添加 Redisson 的相关依赖;

2)创建 Redisson 对象,并使用其 getLock 方法获取锁对象;

3)调用锁对象的 lock() 方法尝试获取锁,如果获取成功就可以开始执行任务了;

4)任务执行完毕后,调用锁对象的 unlock() 方法释放锁。

以上是 Redis 分布式锁的两种常见实现方式。在实际场景中,我们需要根据不同的业务需求选择不同的实现方式。例如,基于 SETNX 命令实现方式简单易懂,但需要手动添加重试机制;基于 Redisson 框架实现方式复杂一些,但提供了更多的分布式锁实现方案和优秀的性能。

11、setnx 为什么是原子性?

SETNX 是 Redis 中的一个原子性操作指令,它可以用于实现分布式锁等功能。SETNX 的原子性指的是多个客户端并发执行 SETNX 操作时,只有其中一个客户端能够成功地将键值对设置到 Redis 中。

SETNX 命令的原子性是由 Redis 内部的单线程机制所保障的。在 Redis 中,所有命令都会交给一个单独的线程执行,这个线程会依次执行命令队列中的每个命令,并根据自己的特性维护自己的状态。对于 SETNX 命令,Redis 的单线程机制会保证在执行该命令时,任何其他命令都无法干扰其执行结果。具体来说,当 SETNX 命令被执行时,Redis 会检查要设置的 key 是否已经存在,如果不存在,则会执行 SETNX 命令将 key 设置为指定的 value,此时 Redis 会阻塞其他客户端的读写请求,直到 SETNX 命令执行完成并返回结果。

因此,无论是单个客户端还是多个并发的客户端,SETNX 命令执行时都不会出现并发问题,即 SETNX 命令具有原子性。同时,Redis 还提供了诸如 INCR 和 DECR 等其他单个命令具有原子性的操作,在分布式场景中也可以利用这些指令实现原子性操作。

12、如何实现 Redis 和 MySQL 一致性?

(1)先更新数据库,后更新缓存;

(2)先更新缓存,后更新数据库;

(3)先更新数据库,后删除缓存;

(4)先删除缓存,后更新数据库。

「先更新数据库,再删除缓存」的方案虽然保证了数据库与缓存的数据一致性,但是每次更新数据的时候,缓存的数据都会被删除,这样会对缓存的命中率带来影响。

如果我们的业务对缓存命中率有很高的要求,我们可以采用「先更新数据库,再更新缓存」的方案,因为更新缓存并不会出现缓存未命中的情况

  • 在更新缓存前先加个分布式锁,保证同一时间只运行一个请求更新缓存,就会不会产生并发问题了,当然引入了锁后,对于写入的性能就会带来影响。
  • 在更新完缓存时,给缓存加上较短的过期时间,这样即时出现缓存不一致的情况,缓存的数据也会很快过期,对业务还是能接受的。

延迟双删:先进行缓存清除,再执行update,最后(延迟N秒)再执行缓存清除。

13、Redis 缓存雪崩问题及解决方案?

缓存雪崩:大量的缓存同时过期 或 Redis 服务宕机,导致大量的请求到达数据库,导致数据库承受压力过大而宕机。

解决方案:

大量缓存同时过期:(1)设置均匀的过期时间,随机设置;(2)双 key,主 key 过期,副 key 不过期;(3)互斥锁,确保只有一个请求能到达数据库,并把数据更新至缓存

Redis 服务宕机:(1)搭建高可用 Redis 集群;(2)利用熔断机制,暂停业务应用对缓存服务的访问,直接返回错误,不用再继续访问数据库。(3)限流机制:只将少部分请求发送到数据库进行处理,再多的请求就在入口直接拒绝服务,等到 Redis 恢复正常并把缓存预热完后,再解除请求限流的机制。

14、什么是熔断?

当系统中某一个服务出现性能瓶颈时,对这个服务的调用进行快速失败,避免造成连锁反应,从而影响整个链路的调用。

服务熔断的作用类似于我们家用的保险丝,当某服务出现不可用或响应超时的情况时,为了防止整个系统出现雪崩,暂时停止对该服务的调用。

15、熔断和限流的区别?

限流是指上游服务对本服务请求 QPS 超过阈值时,通过一定的策略(如延迟处理、拒绝处理)对上游服务的请求量进行限制,以保证本服务不被压垮,从而持续提供稳定服务。常见的限流算法有滑动窗口、令牌桶、漏桶等。

16、Redis 更高效的原因?

(1)更高效的数据结构

(2)运行在内存上面

(3)IO 多路复用

17、项目

18、算法

19、反问

#软件开发2023笔面经#
全部评论
阿里刚开始春招,欢迎同学踊跃报名。查看这个帖子 查看部门介绍和扫码线上投递简历。 https://www.nowcoder.com/discuss/474899666987909120
2 回复 分享
发布于 2023-04-18 14:56 浙江
哪个部门呀
点赞 回复 分享
发布于 2023-04-28 07:35 陕西
八股很nice,基本都遇到过。补充一下熔断和限流的区别,熔断主要指在调用方,限流是指在服务提供方,保证高可用。
点赞 回复 分享
发布于 2023-04-18 18:35 陕西
这是什么岗位啊
点赞 回复 分享
发布于 2023-04-17 16:14 浙江

相关推荐

11-12 08:07
已编辑
门头沟学院 Java
第一次面试这种中大厂,我个人感觉有点压力面(也可能是鼠鼠太菜了),被狠狠拷打力1、开场直接自我介绍2、我看你项目利用threadlocal解决kryo序列化器的线程安全,你是怎么解决的?被指出我的描述错误,实际上是解决了kryo上下文使用的一个问题,并没有解决线程安全,我跟面试官说用threadlocal不就保证一个线程使用一个独立kryo序列化器了吗?他说这不还是没有解决kryo本身的线程安全问题么。我也不想说什么了3、api和spi的区别是什么?回答的有点乱,之前没有系统去理解他们的区别4、jdk动态代理里你是怎么知道要代理哪个服务呢?你说你用服务发现从etcd得到服务列表,那你有用到哪些负载均衡器?有没有用容错和熔断限流?具体是哪些?那你动态代理里需要配置什么吗?回答有点乱,有点没清楚面试官想问配置的是什么东西5、你说你用rabbitmq解决订单业务解耦,我没太懂是解耦什么?我说是解耦订单创建业务,结果被拷打。为什么你要解耦订单创建呢?我说为了提高用户响应速度,提高服务体验。结果说你知道哪些平台是异步创建订单的?鼠鼠也不知道啊,面试官告诉我,主流平台没有异步订单创建的,因为如果用户发现订单列表没有自己刚刚买的订单怎么办呢?被"夸"我这个是奇思妙想😭😭😭,我之前问ai大人也没告诉过我这个有问题啊6、你说使用Redis➕caffeine实现二级缓存,实现缓存降级处理,怎么实现的?你确定能实现缓存降级吗,那如果Redis宕机,你caffeine未命中的请求你是怎么处理的?打到数据库的话,那怎么可以解决缓存降级呢?鼠鼠麻了,ai大人之前还是没指出我的问题,这里我心态其实有点炸了。可能面试看我有点窘迫,就说问点八股吧。我以为八股总不能这么难堪了吧,还是太年轻了。7、你说说jvm的垃圾回收器吧,你配置过哪些?(鼠鼠完全没有配置jvm的经验)说了默认是使用g1,然后把常见的垃圾回收器回答了。他说:cms有点老了,你可能不太用过,那你说说cms为什么会被替代吧,相比于g1来说?我不知道呢,我就说cms初衷是为了并发回收减少STW的时间,但是总体时间更长,因此后面被替代了。但是可能我说的有点乱,面试官有点没太理解,然后跟我说了一下g1的好处,并且让我多去了解一下8、面试官可能看我很紧张回答很乱,终于问了个简单的了。那你说说缓存三大问题吧,都是怎么解决的呢?鼠鼠这种基础八股可熟啊,直接按流程分类说完了,这次面试官终于没有追问了,完全胜利✌🏻9、那你说说缓存一致性怎么保证吧?回答了最终一致性使用延迟双删,强一致用分布式锁➕事务。那如果事务的缓存重建出现了异常怎么办?我说可以先重试多次,如果任然不行就抛出异常让事务回滚。结果面试官问,如果数据库没写成功,缓存写成功怎么处理呢,你总不能让缓存回滚吧?鼠鼠又有点懵了,支支吾吾说了那就规定顺序,必须数据库写成功之后才能进行写缓存,不知道对不对。那删除缓存你是怎么做的?我说使用删除语句。面试官问还有吗?我没懂什么意思,结果面试官说让我去了解一下Binlog的作用。我还没了解过Binlog这玩意在这有什么作用啊。那你说说延迟双删是怎么做的呢?那为什么要先操作数据库在删缓存呢?这里面试官其实想问我旁路缓存,但是这个有点忘了啊😭😭,总之一顿乱答10、那你讲讲mvcc吧。我简单说了什么redo log、版本链、读视图,事务可见版本4个规则,说实话有点忘了。面试官可能也看我了解不多也没追问了。11、双亲委派机制了解吗?那怎么打破呢?这个常规八股我直接朗诵了。行,那打破之后这个可以加载多次吗?我又懵了,我不确定的回答:应该只有当这个类加载失败的时候jvm会进行重新加载吧,但是如果正常加载的话应该不能重复加载吧。面试官直接说:是可以重复加载,只要在loadclass进行重写就行。这个我真不知道啊12、手撕算法环节:给你一个二叉树,返回这个二叉树的反向层序遍历。我简单想了一分钟,说先将正序层序遍历结果保存到数组a,再保存每一层节点数到数组len,再反向遍历len,从a中读取正确答案。因为没有电脑所以前十多分钟就是再讲思路,后面用了朋友的电脑在牛客上写,写了几分钟还没写完,由于时间不太够了,面试官说就这样吧,大概能理解我的思路了,但是说细节不是很完善,可以用更简单的办法实现层序遍历。我力扣第一遍还没过完,对这题不是很有印象,但是感觉我的思路应该没有问题,编码时间不够细节也不可能一次完善吧反问环节:13、您对我本次面试的表现给点建议和意见吧。就是让我把简历上刚刚提出来的问题好好改一下,也没说别的。然后就是问了公司的业务和技术栈方面,没了。总结:这次真的指出了我很多问题,无论是八股还是项目,感觉面试官人挺好,至少帮我纠错,还告诉我正确解决思路,虽然感觉对我来说全程压力面,但是我还是学到和了解到很多,就是被刷我还是要很感谢面试官啊。这一周把这次问题去好好处理巩固一下吧,这次实习面试强度好大啊
查看25道真题和解析
点赞 评论 收藏
分享
评论
22
181
分享

创作者周榜

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