Java高频面试题分享

1. 策略模式怎么控制策略的选取

答:
if else

1.1 追问:如果有100种策略呢?

答:
使用Map来做字段和策略的映射

1.2 追问:什么情况下初始化Map

答:

  1. 在项目运行的时候去初始化Map,相当于提前加载
  2. 如果策略很多,在用户使用的时候再去加载,相当于懒加载,之后需要再次使用的时候去读取初始化的策略就可以了

2. 什么是索引?什么时候用索引?

答:
索引在MySQL中也叫做“键”,它是一个特殊的文件,它保存着数据表里所有记录的位置信息,更通俗的来说,数据库索引好比是一本书前面的目录,能加快数据库的查询速度。
当数据库中数据量很大时,查找数据会变得很慢,我们就可以通过索引来提高数据库的查询效率

2.1 追问:怎么判断系统什么时候用量比较少

答:
看日志、看负载、看CPU、看接口调用量

2.2 追问:如何实时的查看日志

答:
tail -f

3. 怎么实现发送短信功能

答:
第三方运营商服务,引入对应的包,填写对应的参数(一般都有ak,sk),更具示例代码编写自己的逻辑就可以

3.1 追问:怎么防止短信被刷

答:
验证码+限制短信发送频率

3.2 追问:怎么实现限制短信发送频率

答:redis

4. 什么是AOP?怎么在项目中运用AOP

4.1 追问:Spring AOP是怎么实现的
4.2 追问:Spring AOP是基于哪一种动态代理

详情见文章:Spring AOP(概念、实战、原理)

5. MySQL读写分离怎么实现

答:
定义主服务器和从服务器,主服务器负责写数据,从服务器只负责读数据

5.1 追问:主从节点是如何同步的

答:
在这里插入图片描述

5.2 追问:有几种同步模式,分别介绍一下

有两种同步模式
异步同步模式
异步同步模式是MySQL默认的同步策略模式,客户端向服务端发送请求后,master处理完之后,直接返回客户端结果,接着在将对应的log信息发送给slave节点
半同步模式

  1. master处理完自身操作,将对应的binary log 发送从服务器,从服务器通过io thread线程写入到relay log中,然后将结果返回给master,master在收到salve的响应之后返回给客户端
  2. 半同步模式是基于异步复制的基础上进行的,无非是半同步模式需要安装异步插件完成

6. 介绍一下缓存雪崩

原因:同一时间段key大量过期
解决:
4. 设置不同过期时间(一个固定值,一个随机值)
5. 多级缓存
6. 降级处理(最简单的抛出异常,也可以返回一些简化的内容或者静态页面)

7. redis缓存和数据库不一致的问题

采用redisson实现的读写锁,在读的时候添加共享锁,可以保证读读不互斥,读写互斥。当我们更新数据的时候,添加排他锁,它是读读,读写都互斥,这样就能保证在写数据的同时是不会让其他线程读数据的,避免了脏数据。这里面需要注意的是读方法和写方法上需要使用同一锁才行。
注意:这种情况只有必须保证强一致性的时候才会使用

开发中大部分是允许短暂的不一致的,这个时候采用异步的方案
● 使用MQ中间件,更新数据之后,通知缓存删除
● 利用canal中间件,不需要修改业务代码,伪装为MySQL的一个从节点,canal通过读取binlog数据更新缓存

7.1 追问:为什么不适用延迟双删

延迟双删,如果是写操作,我们先把缓存中的数据删除,然后更新数据库,最后再延时删除缓存中的数据,其中这个延时多久不太好确定,在演示的过程中可能会出现脏数据,并不能保证强一致性,所以没有采用

8. RabbitMQ重复消费问题

  1. 给每一个消息携带一个全局唯一id
    ● 消费者监听到消息后获取id,先去查询这个id是否存在
    ● 如果不存在,则正常消费消息,并将消息的id存入数据库或者redis中
    ● 如果存在则丢弃此消息
  2. 分布式锁
    ● 以唯一的消息id为键加锁,消费过后就上锁,下次消息再过来就判断
8.1 追问:如何保证消息不丢失

第一个是开启生产者确认机制,确保生产者的消息能到达队列,如果报错可 以先记录到日志中,再去修复数据
详细的:
RabbitMQ提供了publisher confirm机制来避免消息发送到MQ过程中丢失。消息发送到MQ以后,会返回一个结果给发送者,表示消息是否处理成功
如果到达消费者,则会返回publish-confirm ack,如果到交换机失败,则返回publish-confirm nack,如果到队列失败了,则返回publish-return ack

第二个是开启持久化功能,确保消息未消费前在队列中不会丢失,其中的交换机、队列、和消息都要做持久化
详细的:

第三个是开启消费者确认机制
1. auto
自动ACK。Spring AMQP提供了一种自动的消息确认机制。它利用AOP(面向切面编程)对消息处理逻辑做了环绕增强。当业务正常执行时,Spring AMQP会自动返回ACK。当业务出现异常时,根据异常判断返回不同结果:业务异常,自动返回NACK;消息处理或校验异常,自动返回REJECT。

2. manual
手动ACK。消费者接收到消息后需要手动发送确认给发送者,发送者才会继续发送下一条消息。在这种模式下,如果消费者处理消息失败,可以手动发送NACK给发送者,告诉发送者这条消息处理失败,以便发送者重新发送消息。这种模式可以保证消息的可靠性,但需要消费者手动处理确认和NACK。
Channel.basicAck()方法

channel.basicAck(deliveryTag,true);

肯定确认,消费成功,可以删除
Channel.basicreject()方法

channel.basicReject(deliveryTag, true);

拒绝deliveryTag对应的消息,第二个参数是否requeue,true则重新入队列,否则丢弃或者进入死信队列。
该方法reject后,该消费者还是会消费到该条被reject的消息。
Channel.basicnack()方法

channel.basicNack(deliveryTag, false, true);

为不确认deliveryTag对应的消息,第二个参数是否应用于多消息,第三个参数是否requeue
与basic.reject区别就是同时支持多个消息,可以nack该消费者先前接收未ack的所有消息。nack后的消息也会被自己消费到。
Channel.basicrecover()方法

channel.basicRecover(true);

是否恢复消息到队列,参数是是否requeue,true则重新入队列,并且尽可能的将之前recover的消息投递给其他消费者消费,而不是自己再次消费。false则消息会重新被投递给自己。

8.2 追问:多个消费者消费同一个消息如何实现

发布订阅模式

8.3 追问:RabbitMQ有哪几种工作模型

一、简单模式
简单模式是最基本的消息队列模式,适用于一个生产者和一个消费者的场景。生产者发送消息到队列,消费者从队列中获取消息进行处理。这种模式的优点是简单易用,但缺点是消息只能被一个消费者消费,且没有消息的确认机制,可能会出现消息丢失的情况。
二、工作队列模式
工作队列模式适用于多个消费者共同处理一个任务的情况。生产者将任务发布到队列中,多个消费者监听同一个队列,通过竞争获取任务进行处理。这种模式的优点是能够充分利用多个处理器的计算能力,提高系统的吞吐量。但缺点是可能会导致多个消费者同时处理同一个任务,造成资源的浪费。
三、发布订阅模式
发布订阅模式是一种广播模式,适用于一对多消息传递的场景。生产者将消息发布到交换机,交换机将消息转发给所有绑定到该交换机的队列,消费者从队列中获取消息进行处理。这种模式的优点是能够实现一对多的消息传递,提高系统的扩展性。但缺点是可能会导致消息的重复传递和消费者的重复消费。
四、路由模式
路由模式是一种更灵活的消息传递方式,适用于多个业务系统的集成。生产者将消息发送到交换机,交换机根据routing key将消息路由到一个或多个队列中,消费者从队列中获取消息进行处理。这种模式的优点是能够根据业务需求灵活地路由消息,提高系统的可扩展性和灵活性。但缺点是需要合理地设计routing key以避免消息的丢失或重复传递。
五、通配符模式
通配符模式是一种匹配规则的消息传递方式,适用于多级菜单的场景。生产者将消息发送到交换机,交换机根据通配符匹配规则将消息路由到对应的队列中,消费者从队列中获取消息进行处理。这种模式的优点是能够根据规则匹配到多个队列,实现多级菜单的消息传递。但缺点是需要合理地设计通配符规则以避免消息的错漏或重复传递。
六、主题模式
主题模式是一种基于关键字订阅的消息传递方式,适用于多级分类的场景。生产者将消息发布到主题交换机,交换机将消息转发给所有绑定到该主题交换机的队列,消费者从队列中获取消息进行处理。这种模式的优点是能够根据关键字订阅消息,实现多级分类的消息传递。但缺点是需要合理地设计主题和关键字以避免消息的错漏或重复传递。

8.4 追问:多个消费者,如何保证只有一个消费者去消费一个消息(生产者消息来了是直接给所有的消费者的)

默认情况下,RabbitMq收到消息后,就向消费者全部推送。但是如果rabbitmq队列里消息过多,且消息的数量超过了消费者处理能力, 就会导致客户端超负荷崩溃。此时我们可以通过 prefetchCount 限制每个消费者在收到下一个确认回执前一次可以最大接受多少条消息。即如果设置prefetchCount =1,RabbitMQ向这个消费者发送一个消息后,再这个消息的消费者对这个消息进行ack之前,RabbitMQ不会向这个消费者发送新的消息

 // 每个客户端每次最后获取N个消息
channel.basicQos(1);
  • 10
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

栖迟于一丘

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

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

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

打赏作者

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

抵扣说明:

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

余额充值