2020Java高级开发工程师面试题汇总

2020面试总结

工作三年多,面试目标为高级开发工程师

前言

9.5–11.13,经过了长达70天的面试,终于有了结果。期间崩溃过无数次,很多次面试都被虐到怀疑人生,也有三面被刷掉无奈,一次次整装重新出发,一次次从头再来。今天有时间整理最近面试过程中涉及到的问题和经验,希望可以帮助到正在面试中或即将面试的同行们。


一、面试过的公司

  • 阿里巴巴
  • 京东
  • 美团
  • 百度
  • 度小满金融
  • 爱奇艺
  • 当当网
  • 58同城
  • 贝壳找房
  • 快手
  • 小米
  • 滴滴
  • 微博
  • 陌陌
  • 中信银行
  • 尚德机构
  • 轻松筹
  • 货拉拉
  • 一起教育
  • 易车
  • 好未来

二、面试主要涉及到的技术点

概述:以Java编程基础、JVM原理、Spring\Spring Boot、Redis、Zookeeper、消息队列(Kafka、Rocket MQ)、MySQL等为主;也包括Dubbo、Tomcat性能优化、容器化技术(Docker、Kubernetes)、微服务中监控、Linux常用命令等问题;最为重要的当然是算法和数据结构。

1.Java基础问题

  • Java中多态的实现原理?

  • Java中线程池的工作原理?

  • ThreadLocal的使用场景和原理?

  • 使用syncronized和Lock实现生产者消费者模式?

  • 线程池如何正常关闭?

  • synchronized锁的升级过程?

  • synchronized重入锁和非公平锁的实现原理?

  • synchronized和Lock的区别?

  • synchronized为什么称之为重量级锁?

  • JUC(并发编程工具包)包下使用过哪些类?

  • 阻塞队列的实现原理?

  • 阻塞队列中的消息服务重启时,如何持久化?

  • AQS队列原理?

  • Lock的几种实现方式?

  • volatile关键字的使用场景和作用 (解决可见性和有序性

    1.解决可见性问题
    2.禁止指令重排序

  • JMM关于synchronized的两条规定:(解决可见性和原子性

    1.线程解锁前,必须把共享变量的最新值刷新到主内存中;
    2.线程加锁时,将清空工作内存中共享变量的值,从而使用共享变量时需要从主内存中重新获取最新的值;(注意:加锁与解锁需要是同一把锁)
    通过以上两点,可以看到synchronized能够实现可见性。同时,由于synchronized具有同步锁,所以它也具有原子性

  • volatile能当锁使用么?

  • 简述JMM(Java内存模型)

  • ConcurrentHashMap的原理?

  • PriorityQueue(堆)?

  • BIO、NIO、AIO的区别?NIO中selector、poll、epoll模型的区别?

    1.select,poll实现需要自己不断轮询所有fd集合,直到设备就绪,期间可能要睡眠和唤醒多次交替。而epoll其实也需要调用epoll_wait不断轮询就绪链表,期间也可能多次睡眠和唤醒交替,但是它是设备就绪时,调用回调函数,把就绪fd放入就绪链表中,并唤醒在epoll_wait中进入睡眠的进程。虽然都要睡眠和交替,但是select和poll在“醒着”的时候要遍历整个fd集合,而epoll在“醒着”的时候只要判断一下就绪链表是否为空就行了,这节省了大量的CPU时间。这就是回调机制带来的性能提升。
    2. select,poll每次调用都要把fd集合从用户态往内核态拷贝一次,并且要把current往设备等待队列中挂一次,而epoll只要一次拷贝,而且把current往等待队列上挂也只挂一次(在epoll_wait的开始,注意这里的等待队列并不是设备等待队列,只是一个epoll内部定义的等待队列)。这也能节省不少的开销。

  • TCP协议、HTTP协议、https协议的原理?

  • TCP协议的滑动窗口?

  • 常用的序列化协议及区别?

  • StringBuffer和SpringBuilder的区别,线程是否安全的原理?

  • ArrayList和LinkedList的区别?

  • 重写equals方法的时候为什么要重写hasCode方法?

  • HashSet是如何实现去重功能的?HashMap怎么保证key不重复的?

  • HashMap的线程不安全体现在哪些地方?

    1.数据丢失
    2.数据覆盖
    3.死循环

  • HashMap底层数据结构,为什么选择红黑树?

  • Java中为什么是单继承?

  • 接口和抽象类的区别?

  • Java中多态的原理?

  • Java中类加载机制?

    • 装载
    • 链接
      • 验证
      • 准备
      • 解析
    • 初始化
  • Java中static关键字的作用?

    • 修饰成员变量
    • 修饰方法
    • 修饰代码块
  • HashMap的扩容过程?

  • 红黑树解决了什么问题

  • 线程池如果关闭了两次会有什么问题?

2.JVM

  • 虚拟机运行时数据区

    • 方法区
    • 虚拟机栈
    • 本地方法栈
    • 程序计数器
  • 类加载机制

    • 装载
    1. 通过一个类的全限定名获取定义此类的二进制字节流;
    2. 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构 ;
    3. 在Java堆中生成一个代表这个类的java.lang.Class对象,作为对方法区中这些数据的访问入口。
    • 链接
      • 验证
      1. 文件格式验证
      2. 元数据验证
      3. 字节码验证
      4. 符号引用验证
      • 准备
        • 为类的静态变量分配内存,并将其初始化为默认值
      • 解析
        • 把类中的符号引用转换为直接引用
    • 初始化
      • 对类的静态变量,静态代码块执行初始化操作
  • 类装载器

  • 双亲委派机制的优点

    • 防止重复加载
    • 防止核心类不被篡改,保证数据安全
  • 判断Java对象时候存活的算法

    • 引用计数法
    • 可达性分析算法
  • 垃圾回收算法

  • 垃圾收集器种类

    • 吞吐量优先

    • 停顿时间优先

  • CMS垃圾收集器的工作过程

  • CMS和G1的区别?

    • CMS

      • 优点:并发收集、低停顿
      • 缺点:产生大量空间碎 片、并发阶段会降低吞吐量
      • 使用“标记-清除”算法
    • G1

      • 并行与并发

      • 分代收集(仍然保留了分代的概念)

      • 空间整合(整体上属于“标记-整理”算法,不会导致空间碎片)

      • 可预测的停顿(比CMS更先进的地方在于能让使用者明确指定一个长度为M毫秒的时间片段内,消耗在垃圾收集

        上的时间不得超过N毫秒)

  • Java中的对象一定都存储在堆中么(逃逸分析)

  • Java对象创建的过程?

  • 生产上遇到OOM如何排查?

    • JVM启动参数-XX:+HeapDumpOnOutOfMemoryError,当OutOfMemoryError发生时自动生成 Heap Dump 文件;
    • 或者通过jmap -heap 结合pid手动生成Heap Dump文件;
    • 分析Dump文件,使用JDK自带的jvisualVm或者Eclipse memory analyzer等工具进行日志分析
    • 可以查看哪些对象被频繁创建,哪些对象占用内存空间较大;
  • CPU占用100%如何分析原因?

    • 查找pid
    • top 查看CPU占用率,找到消耗CPU最多的线程号 top -H -p pid
    • 使用jsatck生成 Thread Dump文件
    • 将线程号转化为16进制后查询日志
  • Java应用生产环境线程发生死锁的情况如何解决?

    • jstack
    • jconsole
  • JVM优化?

    • 适当的增大堆内存大小
    • 选择合适的垃圾收集器
    • G1合理设置停顿时间
    • 合理设置并发线程数
    • 调整启动并发GC时堆内存占用百分比
    • 内存泄漏和内存溢出的区别,分别产生的原因,及解决方案
  • 内存泄漏的原因:

    • 代码缺陷,使用完对象后没有及时释放,导致某些不会再被使用的对象不能被垃圾回收器正常回收
  • 内存泄漏解决方案:

    • 使用完对象后将其置为NULL;
    • 使用数据库连接,IO操作,网络连接后要关闭连接;
    • 使用集合类后需要将其remove或置为NULL;
    • 正确使用单例模式,如果单例对象持有外部的引用,那么这个对象将不能被JVM正常回收;
  • 内存溢出的原因

    • 内存泄漏到一定程度会导致内存溢出
    • 创建大对象时,无法分配足够大的空间会导致内存溢出
    • 应用程序并发较高时,
    • 内存中加载的数据过多
    • 在循环中不断创建实例对象
    • 启动参数内存值设置过小·
  • 内存溢出解决方案

    • 代码检查
    • 检查数据库查询语句,是否有一次获取全部数据的查询
    • 根据应用程序QPS峰值,合理部署集群节点数,合理进行负载均衡
    • 合理设置内存值大小,可根据峰值的请求量以及估算实例对象的大小,设置JVM启动参数内存值大小
  • 频繁发生Full GC的原因,及解决方案?(老年代进行空间分配担保)

    • System.gc()方法的调用,强烈影响系建议能不使用此方法就别使用,让虚拟机自己去管理它的内存,可通过通过-XX:+ DisableExplicitGC来禁止RMI(Java远程方法调用)调用System.gc。
    • 适当调整新生代的空间大小,让对象在新生代多存活一段时间,
    • 适当增加方法区的大小
    • 启用空间分配担保机制
  • 执行Minor GC的时候,JVM会检查老年代中最大连续可用空间是否大于了当前新生代所有对象的总大小。

如果大于,则直接执行Minor GC(这个时候执行是没有风险的)。

如果小于了,JVM会检查是否开启了空间分配担保机制,如果没有开启则直接改为执行Full GC。

如果开启了,则JVM会检查老年代中最大连续可用空间是否大于了历次晋升到老年代中的平均大小,如果小于则执行改为执行Full GC。

如果大于则会执行Minor GC,如果Minor GC执行失败则会执行Full GC。

  • 工具

    • jconsole
    • jvisualvm
    • MAT 分析Heap Dump文件
    • perfma 在线
    • GC Viewer 分析GC日志
    • gceasy 在线
  • JVM命令

    • jps
    • jinfo
    • jstat
    • jstack
    • jmap
  • CMS垃圾收集器的优化步骤

    • CMS收集器一般在内存使用空间占比达到某一比例的时候CMS 收集器就会被激活。现在默认比例一般90%以上
    • 通过参数设置,整理空间碎片
  • G1垃圾收集器的优化步骤

    • 适当调整内存大小
    • 调整最大停顿时间
    • 调整启动并发GC时堆内存占用百分比

3.Spring/Spring Boot

  • 设计模式和设计原则
  • 六大设计原则
  • 常用设计模式
    • 策略模式
    • 模板方法模式
    • 代理模式和委派模式的区别?
    • 动态代理和静态代理的区别 ?
      • 所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。
      • 缺点:
        • 如果要代理的类型很多,势必要为每一种类型的方法都进行代理
        • 如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。显而易见,增加了代码维护的复杂度。
      • 动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成
      • 代理模式的优点:程序解耦,功能增强
    • 责任链模式
    • 单例模式
    • 工厂模式
    • 装饰器模式–代码实现流程小米
      • 抽象构件(Component)角色:定义一个抽象接口以规范准备接收附加责任的对象。
      • 具体构件(ConcreteComponent)角色:实现抽象构件,通过装饰角色为其添加一些职责。
      • 抽象装饰(Decorator)角色:继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
      • 具体装饰(ConcreteDecorator)角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。
      • 通过构造器传入包装类实例,接口成员变量接收
      • 优点:
        • 装饰器是继承的有力补充,比继承灵活,在不改变原有对象的情况下,动态的给一个对象扩展功能,即插即用
        • 通过使用不用装饰类及这些装饰类的排列组合,可以实现不同效果
        • 装饰器模式完全遵守开闭原则
      • 缺点:
        • 装饰模式会增加许多子类,过度使用会增加程序得复杂性。
  • 在项目中常用的设计模式有哪些(总结)
  • Spring中Bean的生命周期
  • Spring Bean 的作用域及适用于哪些场景?
  • Spring中IoC容器的初始化过程
  • Spring中的AOP的实现原理
  • JDK提供的代理实现方式和Cglib实现的区别,使用于哪些情况下?
  • JDK的动态代理为什么基于接口实现?
    • public final class $Proxy0 extends Proxy implements Interface
    • 受限制于Java仅支持单继承
  • Spring中的事务
  • 事务传播机制
  • 事务实现的原理(代理模式、反射机制)
  • Spring中如何解决循环依赖问题?
  • Spring中@Bean注解如何解析?
  • Spring阅读源码入口?
  • Spring整合Mybatis是,实现原理?
  • Spring中的定时任务原理?
  • @Autowried注入的是同一个对象么?
  • spring中的单例如何解决线程安全问题的? Bean默认是单例
  • 使用ThreadLocal为线程提供共享变量的副本
  • ThreadLocal的原理
  • Spring和SpringBoot 的区别?
  • ImportSelector 和 ImportBeanDefinitionRegistrar的区别
    • ImportSelector是将类的全路径名直接注册给Spring的IOC,而ImportBeanDefinitionRegistrar就是通过BeanDefinition注册给spring。
    • MyBatis的底层就是通过实现了ImportBeanDefinitionRegistrar来实现的,在构建真正需要注册进入到IOC的实现类之前,MyBatis动态实现了我们指定的数据访问层的接口,然后将其构建BeanDefinition并注入到了IOC中
  • SpringBoot 在启动时如何热加载数据?
    • Spring Boot 在启动后,会找到全部 CommandLineRunner 接口的实例并运行它们的 run 方法。
    • 可以通过 @Order 注解或者实现 Order 接口来指定 CommandLineRunner 的执行顺序。
  • Spring Boot 约定优于配置的体现?
    • 项目目录结构
    • 加载指定后缀,指定格式的配置文件

4.Redis

  • Redis为什么是单线程的,单线程的Redis为什么这么快?

  • 分布式锁

    • https://www.cnblogs.com/keeya/p/14332131.html
  • 基于内存操作

  • NIO epoll模型(Linux)

  • Redis中的数据结构,在项目中用到过哪些数据结构?

  • 缓存雪崩问题

    • 大量热点数据同时过期,增加数据库的压力
  • 缓存击穿问题

    • 缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库
  • 缓存穿透问题

    • 缓存穿透是指缓存和数据库中都没有的数据 布隆过滤器
  • Redis的哨兵模式

  • raft选举

  • 选举过程中不能对外提供服务

  • Redis集群模式

  • 思想:分片存储数据

  • 为什么是16384个数据槽,与心跳包的大小有关

  • Redis集群模式和哨兵模式的区别,优缺点?

  • Redis的持久化机制(默认是RDB)

    • RDB
    • AOF
    • 两种区别
  • Redis过期策略和淘汰策略

  • 过期策略

    • 定期删除
    • 惰性删除
  • 淘汰策略

    1. noeviction:当内存使用超过配置的时候会返回错误,不会驱逐任何键
    2. allkeys-lru:加入键的时候,如果过限,首先通过LRU算法驱逐最久没有使用的键
    3. volatile-lru:加入键的时候如果过限,首先从设置了过期时间的键集合中驱逐最久没有使用的键
    4. allkeys-random:加入键的时候如果过限,从所有key随机删除
    5. volatile-random:加入键的时候如果过限,从过期键的集合中随机驱逐
    6. volatile-ttl:从配置了过期时间的键中驱逐马上就要过期的键
    7. volatile-lfu:从所有配置了过期时间的键中驱逐使用频率最少的键
    8. allkeys-lfu:从所有键中驱逐使用频率最少的键
  • LRU(最近最少使用)

  • LFU(最少使用频率)

  • 默认是哪种,如何实现的?

  • Redis中的lua脚本如何保证操作的原子性?

  • Redis实现分布式锁的原理?

  • Redis集群模式中,数据同步方式?

  • Redis基本数据结构

  • 同样是存储字符串,Hash 与 String 的主要区别?

    1、把所有相关的值聚集到一个 key 中,节省内存空间

    2、只使用一个 key,减少 key 冲突

    3、当需要批量获取值的时候,只需要使用一个命令,减少内存/IO/CPU 的消耗

  • 一致性Hash算法原理

  • Redis中采用数据槽分配数据,为什么不适用一致性Hash?

    • 便于数据迁移,平滑的扩容或缩容
  • Redis中哨兵模式的选举方式?

    • 哨兵中通过Raft算法选举出Leader节点,进行故障转移
  • 客户端如何同时向Redis发送多个指令?

    • pipeline
    • lua脚本
  • 为什么RedisCluster会设计成16384个槽呢?

  • 作者原版回答如下: The reason is:

    • Normal heartbeat packets carry the full configuration of a node, that can be replaced in an idempotent way with the old in order to update an old config. This means they contain the slots configuration for a node, in raw form, that uses 2k of space with16k slots, but would use a prohibitive 8k of space using 65k slots.
    • At the same time it is unlikely that Redis Cluster would scale to more than 1000 mater nodes because of other design tradeoffs.

    So 16k was in the right range to ensure enough slots per master with a max of 1000 maters, but a small enough number to propagate the slot configuration as a raw bitmap easily. Note that in small clusters the bitmap would be hard to compress because when N is small the bitmap would have slots/N bits set that is a large percentage of bits set.

    1.如果槽位为65536,发送心跳信息的消息头达8k,发送的心跳包过于庞大。

    如上所述,在消息头中,最占空间的是 myslots[CLUSTER_SLOTS/8]。 当槽位为65536时,这块的大小是: 65536÷8÷1024=8kb因为每秒钟,redis节点需要发送一定数量的ping消息作为心跳包,如果槽位为65536,这个ping消息的消息头太大了,浪费带宽。

    2.redis的集群主节点数量基本不可能超过1000个。

    如上所述,集群节点越多,心跳包的消息体内携带的数据越多。如果节点过1000个,也会导致网络拥堵。因此redis作者,不建议redis cluster节点数量超过1000个。 那么,对于节点数在1000以内的redis cluster集群,16384个槽位够用了。没有必要拓展到65536个。

    3.槽位越小,节点少的情况下,压缩率高

    Redis主节点的配置信息中,它所负责的哈希槽是通过一张bitmap的形式来保存的,在传输过程中,会对bitmap进行压缩,但是如果bitmap的填充率slots / N很高的话(N表示节点数),bitmap的压缩率就很低。 如果节点数很少,而哈希槽数量很多的话,bitmap的压缩率就很低。

  • Redis中的缓存和数据库数据一致性问题的解决方案?

    • 先更新数据库,再删除缓存–缓存删除失败之后重试机制
    • 先删除缓存,再更新数据库–延时双删
  • Redis中zset中如何实现有序?

    • ziplist
    • skiplist
    • 通过score进行排序
  • Redis集群中数据节点不可用时,应急方案?

5.Zookeeper

  • ZAB协议
    • 原子广播
    • 崩溃恢复
  • zxid组成
  • 拜占庭将军问题
  • 顺序一致性问题
  • leader节点处理事务型请求
  • leader、follower节点数据同步
  • 临时节点和持久化节点的区别
  • 分布式全局ID
  • 分布式锁
  • kafka集群中的zookeeper作用
  • 输出选举功能
  • zookeeper集群搭建的过程

6.消息队列

Rocket MQ

  • 主从模式 多主多从
  • 数据同步
  • Topic 多个消息队列 默认一个topic在一个broker上有4个消息队列
  • Tag 过滤消息使用
  • 消费模式
    • 集群消费 集群中只有一个broker节点能成功消费消息,消费失败之后有重试机制(Exception和连接 超时),衰减重试16次后,进入死信队列。
    • 广播消费 能够保证消息至少被消费一次,消费失败之后没有重试机制
  • 如何保证消息一定会被消费成功,消费者链路中?
  • 消息重发机制
  • 零拷贝原理 磁盘中的消息在内核态中直接发送,不用拷贝到用户空间后在发送,减少拷贝次数
  • 消息存储
  • 日志文件
  • 索引文件
  • 事务消息原理

Kafka

  • 集群模式
  • 数据同步机制
  • 数据分区
  • 数据副本
  • 消息存储
  • 日志文件
  • 索引文件
  • 消息消费机制
  • 分区分配策略
    • range
    • 随机
    • 粘滞策略
  • rebalance原理
  • 程序连接kafka的参数设置
  • 生产者连接
  • 消费者连接

7.MySQL

  • 事务隔离级别

    • 脏读
    • 不可重复读
    • 幻读–如何解决
  • 索引结构

  • 聚簇索引

  • 回表

  • 主从数据同步

  • 集群模式如何数据不丢失

  • SQL优化的具体步骤

    • Explain 查看执行计划

    • type类型最好为ref或者range,index和all需要优化

    • 查看查询是否走索引

    • filtered:这个字段表示存储引擎返回的数据在 server 层过滤后,剩下多少满足查询的记录数

      量的比例,它是一个百分比。

    • Extra

    • using index 使用到了覆盖索引

    • using where 使用了 where 过滤,表示存储引擎返回的记录并不是所有的都满足查询条件,需要

      在 server 层进行过滤(跟是否使用索引没有关系)。

    • using index condition 索引条件下推 索引下推在非主键索引上的优化,可以有效减少回表的次数,大大提升了查询的效率。

    • using temporary 用到了临时表

  • 关联查询的注意事项

    • 小表驱动大表
    • 左连接以左表为准
    • 右连接以右表为准
  • 哪些情况会使索引失效?

    • 如果条件中有or,即使其中有部分条件带索引也不会使用(这也是为什么尽量少用or的原因),要想使用or,又想让索引生效,只能将or条件中的每个列都加上索引;
    • 前导模糊查询不能利用索引(like ‘%xx’ 或者 like ‘%xx%’)
    • 违反组合索引最左匹配原则
    • 需要隐形类型装换(如数字转换成字符)
    • where 子句里对索引列上有数学运算,用不上索引
    • where 子句里对有索引列使用函数,用不上索引
    • 如果mysql估计使用全表扫描要比使用索引快,则不使用索引
  • 什么时候没有必要用索引?

    • 唯一性差;
    • 频繁更新的字段不用(更新索引消耗);
    • where中不用的字段;
    • 索引使用<>时,效果一般;
  • 存储引擎InnoDB和MyISAM的区别

    • InnoDB支持事务,支持表级别锁和行级别锁,数据和索引绑定在一起
    • MyISAM不支持事务,只支持表级别锁,数据文件和索引文件分开存储
  • Mysql中页分裂的原理?

  • 数据页结构

  • https://blog.csdn.net/qq_35045184/article/details/104346594

  • B+树和B树的区别?B+树的搜索原理?

  • B+树和B树的区别

    B+树的非叶子结点只包含导航信息,不包含实际的值,所有的叶子结点和相连的节点使用链表相连,便于区间查找和遍历。
    B+ 树的优点在于:

    • IO次数更少:由于B+树在内部节点上不包含数据信息,因此在内存页中能够存放更多的key。 数据存放的更加紧密,具有更好的空间局部性。因此访问叶子节点上关联的数据也具有更好的缓存命中率。
    • 遍历更加方便:B+树的叶子结点都是相链的,因此对整棵树的遍历只需要一次线性遍历叶子结点即可。而且由于数据顺序排列并且相连,所以便于区间查找和搜索。而B树则需要进行每一层的递归遍历。相邻的元素可能在内存中不相邻,所以缓存命中性没有B+树好。

    但是B树也有优点,其优点在于,由于B树的每一个节点都包含key和value,因此经常访问的元素可能离根节点更近,因此访问也更迅速。

  • 为什么MySQL选择B+树做索引

    1、 B+树的磁盘读写代价更低:B+树的内部节点并没有指向关键字具体信息的指针,因此其内部节点相对B树更小,如果把所有同一内部节点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多,一次性读入内存的需要查找的关键字也就越多,相对IO读写次数就降低了。

    2、B+树的查询效率更加稳定:由于非终结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引。所以任何关键字的查找必须走一条从根结点到叶子结点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相当。

    3、B+树更便于遍历:由于B+树的数据都存储在叶子结点中,分支结点均为索引,方便扫库,只需要扫一遍叶子结点即可,但是B树因为其分支结点同样存储着数据,我们要找到具体的数据,需要进行一次中序遍历按序来扫,所以B+树更加适合在区间查询的情况,所以通常B+树用于数据库索引。

    4、B+树更适合基于范围的查询:B树在提高了IO性能的同时并没有解决元素遍历的我效率低下的问题,正是为了解决这个问题,B+树应用而生。B+树只需要去遍历叶子节点就可以实现整棵树的遍历。而且在数据库中基于范围的查询是非常频繁的,而B树不支持这样的操作或者说效率太低。

  • 数据结构中的各种树

    • https://www.cnblogs.com/maybe2030/p/4732377.html
  • Mysql中哪些情况下不会使用到索引?

    • 如果条件中有or,即使其中有部分条件带索引也不会使用(这也是为什么尽量少用or的原因)
    • 对于多列索引,不是使用的第一部分,则不会使用索引
    • like查询是以%开头
    • .存在索引列的数据类型隐形转换,则用不上索引,比如列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不使用索引
    • where 子句里对索引列上有数学运算,用不上索引
    • where 子句里对有索引列使用函数,用不上索引
    • 如果mysql估计使用全表扫描要比使用索引快,则不使用索引
  • limit和order的使用

    1、如果你只需要结果集中的某几行,那么建议使用limit。这样这样的话可以避免抓取全部结果集,然后再丢弃那些你不要的行。

    2、对于order by查询,带或者不带limit可能返回行的顺序是不一样的。

    3、如果limit *row_count* 与 order by 一起使用,那么在找到第一个***row_count***就停止排序,直接返回。

    4、如果order by列有相同的值,那么MySQL可以自由地以任何顺序返回这些行。换言之,只要order by列的值不重复,就可以保证返回的顺序。

    5、可以在order by子句中包含附加列,以使顺序具有确定性。

  • 数据量过大时,对limit语句进行优化

  • MVCC的原理

  • MySQL中锁的种类及作用

  • binlog日志的存储格式有几种?

8.项目经验和问题

  • 项目中如何保证消息一定被消费成功?(例如:服务重启过程中,消息处理失败后,如何进行重发机制?)
  • 如何保证项目平稳运行?
  • 生产中项目有没有监控平台?‘
  • 监控平台数据埋点的原理?
  • 数据上报的方式?
  • 设计接口的幂等性如何实现?
  • 项目过程中,解决过遇到过哪些难题,如何解决的?
    根据实际参加的项目情况回答,提前准备好场景分析问题,或者你擅长的问题

9.微服务下的监控

  • 日志监控
    • ELK push
  • 链路监控
    • CAT 数据埋点
  • 基于时间序列数据库的开源监控方案
    • Prometheus 采用拉的模式(Pull)从应用中拉取数据
    • InfluxDB
    • 都自带面板展示,可与Grafana集成
  • JDK自带的监控
  • JMX
  • 生产上合理使用JDK自带的jconsole,jvisualvm或者阿里的arthas等实时查看JVM状态
  • 链路监控中,链路ID如何向下传递????

10.算法

  • 快速排序

  • 堆排序(时间复杂度和空间复杂度)

  • 获取数组中第K大的数(使用快速排序或者堆)

  • 将两个有序数组或链表合并成一个有序的数组或链表(归并排序)

  • 判断链表中是否有环

  • 链表反转

  • 数的前中后遍历

  • 二分查找

  • 手写实现Lock

  • 实现两个线程循环打印AB

  • 实现多线程中生产者和消费者模式

  • 如何实现两个有上一亿条数据的文件中,找出相同的数据

  • 线程:假设有一个存储大于500条字符串数据列表List,输入一个要查找的字符串,查找List中包括该字符串的数据并输出。

  • 多个线程同时遍历处理一个list集合

  • list集合拆分后由多个线程处理

  • 假设有一个整数型数组,存在先正序后逆序两部分数据,去除数组中存在重复的数字并输出新的数组。如:
    {1,3,5,6,8,8,15,10,9,7,6,5,3},则输出:{1,3,5,6,8,15,10,9,7}

  • 获取无序数组中查找最大的K个数

  • 输入一个整形数组,数组里有正数也有负数。数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。求所有子数组的和的最大值。要求时间复杂度为 O(n)。

  • 输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,则输出任意一对即可。

  • 二维数组问题
    算法问题可以到访问https://leetcode-cn.com/练习

总结

本文总结了面试高级Java开发工程师的常见问题,涉及的问题仅为自己在面试过程中遇到问题的总结,只是列举出了问题,答案大家可以自己去网上搜索,并自己多加总结。在面试过程中一般都会有开放性的问题,例如:在工作中遇到的困难,如何解决,自己最擅长哪方面的技术等等问题,大家一定要提前准备好要回答的内容。
程序人生,逆水行舟,不进则退,祝大家都能找到合适自己的工作。
文章中如有错误,欢迎在评论区指正,以便及时修改。

你可能感兴趣的:(面试问题总结,Java高级面试题,java,面试,分布式,数据库,redis)