Java面试题

1.redis key删除策略
  定期删除:贪心策略
    1.从过期字典中随机 20 个 key;
    2.删除这 20 个 key 中已经过期的 key;
    3.如果过期的 key 比率超过 1/4,那就重复步骤 1;
  惰性删除:
    在客户端访问这个key的时候,redis对key的过期时间进行检查,如果过期了就立即删除,不会给你返回任何东西。

  定期删除是集中处理,惰性删除是零散处理。

3.es 为什么这么快,分词的原理,分页优化

4.配置加载顺序优先级
  bootstrap.yml在项目启动时,就会加载
  application.yml在springContext加载后进行加载
5.springboot常用注解
  @SpringBootApplication 包含 @SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan
  @ImportResource @Scope @Primary @Lazy @Profile
6.数据库数据发生变化,如何同步给Redis
  方案1:直接删除Redis缓存;
  方案2: 基于MQ异步同步更新
  方案3: 基于canal订阅binlog同步
7.项目高并发解决方案
  非垂直拆分,水平拆分
  垂直拆分的话就是,增加服务器节点,消耗成本,升级CPU
  水平拆分的话包括
    前端页面静态化
  缓存:浏览器缓存 -> CDN加速 -> Nginx动静分离,Nginx缓存 -> Redis缓存 -> DB
  应用拆分,分布式开发,业务拆分
  数据库拆分:垂直拆分和水平拆分
  数据库连接池、Redis连接池、线程池、消息队列
  采用数据搜索引擎
  JVM参数优化
8.秒杀项目会有的问题
  1.商品超卖
  2.高并发
    页面优化,线程池、mq、信号量限制
  3.重复下单
  4.秒杀地址暴露
  5.分布式事务

9.数据库系统的负载均衡
  多主、一主一从、一主多从、多级主从
10.项目并发量,多线程的应用场景
  高并发系统的本质就是充分利用硬件资源,提升cpu
11.mysql 分库分表利弊
  多主、一主一从、一主多从、多级主从
  缺点:
    分布式事务、
  关联查询 join、排序、函数 问题、
  分布式ID问题、
  数据迁移、扩容问题

12.你们项⽬如何排查JVM问题
  对于还在正常运⾏的系统:
  1.可以使⽤jmap来查看JVM中各个区域的使⽤情况
  2.可以通过jstack来查看线程的运⾏情况,⽐如哪些线程阻塞、 是否出现了死锁
  3.可以通过jstat命令来查看垃圾回收的情况,特别是fullgc,如果发现fullgc⽐较频繁,那么就得进⾏调优了
  4.通过各个命令的结果,或者jvisualvm等⼯具来进⾏分析
  5.⾸先,初步猜测频繁发送fullgc的原因,如果频繁发⽣fullgc但是⼜⼀直没有出现内存溢出,那么表示fullgc实际上是回收了很多对象了,所以这些对象最好能在younggc过程中就直接回收掉,避免这些对 象进⼊到⽼年代,对于这种情况,就要考虑这些存活时间不⻓的对象是不是⽐较⼤,导致年轻代放不 下,直接进⼊到了⽼年代,尝试加⼤年轻代的⼤⼩,如果改完之后,fullgc减少,则证明修改有效
  6.同时,还可以找到占⽤CPU最多的线程,定位到具体的⽅法,优化这个⽅法的执⾏,看是否能避免某些 对象的创建,从⽽节省内存

13.对于已经发⽣了OOM的系统:
  1.⼀般⽣产系统中都会设置当系统发⽣了OOM时,⽣成当时的dump⽂件(- XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/base)
  2.我们可以利⽤jsisualvm等⼯具来分析dump⽂件
  3.根据dump⽂件找到异常的实例对象,和异常的线程(占⽤CPU⾼),定位到具体的代码
  4.然后再进⾏详细的分析和调试

  总之,调优不是⼀蹴⽽就的,需要分析、 推理、 实践、 总结、 再分析,最终定位到具体的问题

14.Java死锁如何避免?
  造成死锁的⼏个原因:
  1.⼀个资源每次只能被⼀个线程使⽤
  2.⼀个线程在等待时,不释放已占有资源
  3.⼀个线程已经获得的资源,在未使⽤完之前,不能被强⾏剥夺
  4.若⼲线程形成头尾相接的循环等待资源关系

  这是造成死锁必须要达到的4个条件,如果要避免死锁,只需要不满⾜其中某⼀个条件即可。 ⽽其中前3个条件是作为锁要符合的条件,所以要避免死锁就需要打破第4个条件,不出现循环等待锁的关系。

  在开发过程中:
    1.要注意加锁顺序,保证每个线程按同样的顺序进⾏加锁
    2.要注意加锁时限,可以针对所设置⼀个超时时间
    3.要注意死锁检查,这是⼀种预防机制,确保在第⼀时间发现死锁并进⾏解决

15.消息队列如何保证消息可靠传输
  消息可靠传输代表了两层意思,既不能多也不能少。
  1.为了保证消息不能多,也就是消息不能重复
    a.⾸先要确保消息不多发,这个不常出现,也⽐较难控制,因为如果出现了多发,很⼤的原因是⽣产 者⾃⼰的原因,如果要避免出现问题,就需要在消费端做控制
    b.要避免不重复消费,最保险的机制就是消费者实现幂等性,保证就算重复消费,也不会有问题,通 过幂等性,也能解决⽣产者重复发送消息的问题
  2.消息不能少,意思就是消息不能丢失
    a.⽣产者发送消息时,要确认消息投递成功,⽐如RabbitMQ的transaction机制和confirm机制,Kafka的ack机制都可以保证⽣产者能正确的将消息发送给broker
    b.broker:确认broker确实收到并持久化了这条消息,将队列的持久化标识durable设置为true
    c.消费端手动ack机制,消费者接收到⼀条消息后,如果确认没问题了,就可以给broker发送⼀个ack,broker接收到ack后才会删除消息

16.消息堆积的解决方案
  1、消息发送的速率远远大于消息消费的速率。
    通过关闭某些不重要的业务,减少发送的数据量
  2、消费者出现了问题,导致无法消费。
    a.先修改consumer的问题,确保其恢复消费速度
    b.临时启用多个消费者,通过扩容消费端的实例数来提升总体的消费能力。
    c.消费者参数优化,在初始化的时候提高并发消费者的个数

17.合适的线程数量是多少?CPU 核心数和线程数的关系?
  线程数 = CPU 核心数 *(1+平均等待时间/平均工作时间)

18. 如何让你来设计消息队列中间件,如何设计?
  1、MQ得支持可伸缩性
  2、就是需要的时候增加吞吐量和容量?
  3、考虑MQ的数据持久化
  4、考虑MQ的可用性。
19. 如何保证消息的顺序性
  a. 使用单线程消费来保证消息的顺序性,保证生产者 - MQServer - 消费者是一对一对一的关系
  b. 对消息进行编号,消费者处理时根据编号来判断顺序

20. 什么是沾包拆包
  TCP以流方式传输,是没有界限的一串数据,并没有消息边界。
    - TCP传输数据时,会根据底层的TCP缓存区实际情况进行数据包划分:
    - 1.业务上定义的完整数据(比方说一个完整的json串),可能会被TCP拆分成多个数据包进行发送(拆包)。
    - 2.业务上特殊含义的独立数据,也有可能因为大小或者缓冲区原因,被TCP封装成一个大数据包发送(粘包)。
21. 怎么解决沾包拆包问题
  1.在发送端每个数据包首部添加数据包长度字段,在接收端接收到消息后,通过读取首部的长度字段,便可知道数据包的实际长度了
  2.发送端的每个数据包封装为固定长度(不够的部分补0填充),这样接收端就自然而然的把每个数据包拆分开
  3.设置数据包之间的边界,如设置特殊符号

22. 一般不建议使用System.gc,为什么还要有这个方法
  一般不建议使用system.gc()去显示地要求进行垃圾回收,一般每一次显示的调用system.gc()都会进行一次full gc,而full gc会导致应用的暂停,如果频繁地full gc会导致应用长时间暂停,也就无法正常运行了。

23. mysql数据库删除重复的数据保留一条
  解答一:
    delete from Person where Id not in (
      select t.min_id from ( select min(Id) as min_id from Person group by Email) as t );

  解答二:
    delete p1 from Person as p1,Person as p2 where p1.Email=p2.Email and p1.Id > p2.Id;

 

posted on 2022-03-23 14:04  a阳光倾城  阅读(28)  评论(0编辑  收藏  举报