2024Java面试高频问题

2025 年 1 月 9 日 星期四
5

2024Java面试高频问题

收集总结2024年9月之后本人Java面试相关的问题,本人语言表达能力一直不太好,我发现涉及到底层原理或者源码相关的面试,看了很多视频或者博客的讲解,是明白了大概的原理,但面试时真的问到,语言组织总是不流畅,现场讲出来的很没有逻辑,真的需要写出来背一背。

线程池相关

非常高频!!!!!

常问:几个核心参数,流程,拒绝策略等

回答:

比较重要的几个:核心线程数,最大线程数,队列,拒绝策略,还有存活时间,时间单位,线程工厂。流程就是,会先用核心线程,核心线程用完了,会进队列,队列也满了,会用最大线程,如果也满了会执行拒绝策略。主要有几种,使用主线程,丢弃当前的任务,丢弃队列中最早的任务,直接抛异常,或者自定义拒绝策略。我这边是使用主线程来执行。 队列一般有数组和链表实现的两种,默认数组实现的是有界队列,链表实现的是无界队列,但可以指定长度。 线程池的种类有固定线程池,可缓存的线程池,支持定时的线程池,单线程的线程池。 创建线程池的方式:ThreadPoolExecutor可以指定线程池的参数,或者我们是使用spring封装过的ThreadPoolTaskExecutor

MySQL

索引,优化,B+树,MVCC,sql优化,线上死锁

回答:

b+树的数据都存在叶子节点,非叶子节点存的是索引或者说是目录项。每个节点对应的是一个页page,大小是16k,页由几部分构成,文件头,页头,用户记录区最大最小值,空闲空间,页目录,页尾。

页与页之间通过双向链表链接,这个双相链表其实就是通过文件头的两个字段,FIL_PAGE_PREV和FIL_PAGE_NEXT实现的。

页头里存了很多控制信息,比如当前页有多少条记录、最后插入位置在哪等。 用户记录区,我们的真实数据会按照指定的行格式存在用户记录区中,每条记录都有个记录头,里面存了这条记录是否被删除、在页中的位置、以及指向下一条记录的指针next_record,所以页内的记录其实是通过next_record串成了一个链表。

页目录中有个槽slot的数据结构,将真实数据和最大最小值一起分组管理,通过最大记录的偏移量字段,加速了二分查找。因为槽的数量远远小于记录的数量嘛,比如100条数据,应该会分布到10几个槽里。先对槽进行二分查找,找到在哪个槽里,再具体找到目标数据

因为真实数据的叶子节点通过记录头中的next_record指针形成了链表查询也是比较快的

mvcc就是多版本并发控制,mysql是通过undolog,readview和trxid事务id,还有rollpointer回滚指针,还有一个事务id列表,实现了记录不同版本的数据,形成版本链,然后可以读取不同版本的数据。

AQS

略高频,但我觉得遇到并发,锁相关的都能扯到这里

底层实现,原理等

回答:

AQS就是抽象队列同步器,是构建锁或者其他同步组件的一个框架,Java并发的很多类都是基于这个框架实现的。AQS底层是一个双端队列实现的,有head和tail两个Node节点,还有一个int类型的state变量表示同步状态。主要通过getstate,setstate,cas设置state来操作这个状态。Node节点的数据结构其实是链表,保存了当前线程,前后节点,和等待状态等信息。这个流程简单来说就是,当线程获取同步状态失败时,AQS会将当前线程信息和等待状态等信息构造成一个Node节点并加入同步队列,同时会阻塞当前线程,当同步状态释放时,会把head的第一个后继节点,也就是队列中的第一个节点的线程唤醒,然后尝试获取同步状态,此时这个节点就成为了head。

acquire方法主要有几个操作,尝试获取锁,节点构造并加入同步队列以及在队列中自旋等待。首先去尝试获取锁,根据state判断,成功就是正常获取到锁;失败的话就会把这个线程构造成Node节点放进阻塞队列等待,是通过CAS自旋的方式放到链表的尾部。同时会判断是否需要挂起或者说阻塞当前线程,正常挂起的情况就不说了,还有情况就是前面有线程取消了等待,就需要循环找到一个正常的前驱节点。

release方法也是先尝试释放,根据state的状态,如果-1之后是0就证明可以释放了,然后就会开始唤醒后继节点,这里也有可能有线程取消了等待,也会去循环找到一个最靠前的没取消的节点,把他唤醒,此时这个节点就是head节点了。

比如ReentrantLock底层就是AQS实现的,当我们使用ReentrantLock时,通常我们会new一个ReentrantLock,然后调用lock方法,再执行具体的业务代码,最后unlock释放锁。

ReentrantLock内部使用一个Sync的内部类管理锁,他继承了AQS,有两个实现类公平锁和非公平锁,就是FairSync和NonfairSync。

公平锁,当调用lock方法时,就是调用AQS的acquire方法。

Redis

数据结构,使用场景,缓存穿透

回答:

redis首先就是作为缓存,缓存一些热点数据,减少数据库的压力。除此之外,还可以用来作为分布式锁,计数器,简单的消息队列,或者存一些用户的权限结构,token数据,还可以做一些用户行为的限制功能。

我们项目中,用作缓存热点数据的场景不太多。一般就是,缓存用户的token和权限数据,用hash或者string的数据结构,分布式锁,有些定时任务执行的时间比较久的化,可以用string加setnx命令做分布式锁,还有一些限制功能,比如用户退货太多次,就可以在redis中记录一下,防止恶意下单。

RabbitMQ

和rocketmq对比

回答:

rabbitmq消息可靠,延迟低,支持其他消息协议,延迟队列 首先rabbitmq比较适合用于中小规模的项目,是基于AMQP协议实现的,比较适合一些任务队列和微服务之间的调用这些场景,在高并发高吞吐量的场景下性能不如rocketmq,比如电商,金融这类大型分布式项目。然后rabbitmq支持多种消息模式,比如点对点,发布订阅,rocketmq支持顺序消费事务消息。

rabbitmq的核心是通过交换机和队列实现的消息传递,简单来说就是生产者把消息发送到交换机,交换机根据规则把消息路由到队列,消费者再从队列里取消息,不同的交换机类型对应不同的消息模式。

Nacos

和eureka对比

回答:

首先作为注册中心主要都是有三个功能,服务注册,服务发现openfegin,服务监控。都是服务会先将自己的信息注册到注册中心,然后消费者openfegin从服务中心获取服务列表并根据负载均衡策略选一个调用,服务提供者会定时向注册中心发送心跳来报告健康状态,如果注册中心一定时间没收到心跳会将服务从注册中心移除。

eureka支持ap可用性和分区容错性,nacos支持ap和cp切换

eureka是依赖客户端心跳,nacos支持服务端主动检测状态以及服务列表变更的消息推送。

反射

项目中有个地方用到,所以偶尔会问到

回答:

原理就是在获取class对象时,类加载器会把这个类的字节码加载到jvm中,并在方法区生成类的元数据,字段,方法,构造方法等,反射就是通过访问这些元数据来动态的获取信息的。

优点就是可以在运行时动态的加载类,调用方法和访问字段,可以编写一些通用的方法,比如我这个功能其实就是代替了ifelse的判断代码。

缺点就是,破坏了类的一个封装性,然后因为涉及动态的解析和调用,比直接调用方法要慢,性能相对来说差一点,但我们的调用量也不大,所以这里影响也不是很大。

电商项目的流程

由于最近的项目都没什么亮点,好几次面试都问了之前电商项目的流程,但时间太久都回答的不怎么样

从整个流程来讲,首先是从国内的供应商工厂采购商品,将商品信息录入后台的商家系统,在app上架;商品从国内仓库出海到达海外仓库,这部分会有一些国际物流和清关的流程;用户通过浏览app选购商品下单,支付,生成订单和物流信息;这个物流信息就是国外的一些物流信息;从海外仓库通过海外的物流进行配送,也叫最后一公里配送。

我们app实现的功能,简单来说就是主要是包括商品上架,用户下单生成订单和物流信息,最后进行配送。就是我们采购运营人员的部分功能,还是没有实现,比如在国内采购,还有出海清关,这几块功能,还是靠他们人线下来搞的。

然后其中我主要参与的就是物流相关的功能,比如电商那边下单支付完会调我这边的接口创建物流单。物流会提供一个轨迹状态的消息队列,这个状态有变化时会通知电商系统。还有相关的物流信息的查询接口。以及比较重要的一部分是对接一些当地快递公司的api,包括快递建单,取消,轨迹等相关的接口。肯定是有多家快递公司的嘛,就是整合他们的一些接口和信息,我这边统一封装提供给电商调用。最后有对接一些海外的oms和wms系统,因为刚刚说一些功能我们还是没有实现的,当时仓库的功能是先对接了的当地的海外仓,大概就是一些商品入库出库的流程。

使用社交账号登录

  • Loading...
  • Loading...
  • Loading...
  • Loading...
  • Loading...