京东零售 社招 java一面面经

京东零售 社招 java一面面经
最新回答
帅癌晚期

2021-01-10 15:03:58

京东零售社招Java一面面经总结如下

一、面试流程与问题概述

面试岗位为京东-达达的Java后端开发,面试流程包含自我介绍、项目介绍及技术问题问答,整体氛围轻松,面试官态度友好。技术问题覆盖JVM、数据冲突解决、JDK特性、HashMap原理、索引优化、ES查询优化及线程池使用等核心Java后端知识点。

二、具体问题及解答思路1. 代码上线导致JVM重启,缓存中数据丢失时怎么处理?
  • 缓存预热:在JVM重启前,将核心数据持久化到数据库或分布式缓存(如Redis),重启后从持久化存储中加载数据到本地缓存。
  • 分布式缓存:使用Redis等分布式缓存替代本地缓存,避免单点JVM重启导致数据丢失。
  • 本地缓存持久化:通过RocksDB等本地持久化存储工具,将缓存数据写入磁盘,重启后恢复。
  • 双缓存机制:维护两份缓存(主缓存+备份缓存),重启时切换至备份缓存,同时异步恢复主缓存。
2. 数据版本号有冲突怎么解决?
  • 乐观锁机制:在数据表中增加版本号字段(如version),更新时检查版本号是否匹配,若不匹配则重试或抛出异常。UPDATE table SET value = new_value, version = version + 1 WHERE id = 1 AND version = old_version;
  • 时间戳冲突解决:使用最后修改时间戳替代氏和版本号,更新时比较时间戳是否一致。
  • 分布式锁:对冲突操作加锁(如Redis分布式锁),确保同一时间仅一个线程能修改数据。
3. JDK1.8对HashMap有什么优化?
  • 红黑树优化:当链表长度超过阈值(默认8)且桶数正慎量大于64时,链表转为举核敬红黑树,降低查询时间复杂度至O(log n)。
  • 扩容优化:扩容时通过resize()方法重新计算元素位置,JDK1.8使用e.hash & oldCap判断元素是否需要移动,减少哈希冲突。
  • 初始化容量优化:支持通过构造函数指定初始容量和负载因子,避免频繁扩容。
4. HashMap中put的原理
  • 计算哈希值:通过key.hashCode() ^ (key.hashCode() >>> 16)计算哈希值,减少高位信息丢失。
  • 定位桶位置:哈希值与数组长度减一(n-1)进行按位与操作,确定元素存储的桶索引。
  • 处理冲突

    若桶为空,直接插入新节点。

    若桶非空(链表或红黑树),遍历链表或树,根据equals()方法判断是否覆盖已有值,否则添加到链表尾部或树中。

  • 扩容检查:插入后检查是否需要扩容(元素数量超过容量*负载因子)。
5. HashMap源码什么时候会索引失效?
  • 扩容导致索引变化:HashMap扩容时,元素会重新计算哈希值并分配到新桶中,若此时遍历HashMap,可能因索引变化导致ConcurrentModificationException或数据不一致。
  • 多线程并发修改:非线程安全的HashMap在多线程环境下直接操作(如并发put),可能导致链表成环或索引失效。
6. 联合索引最左匹配原则
  • 定义:联合索引(如(A, B, C))的查询条件必须从最左列开始匹配,否则索引失效。
  • 示例

    查询WHERE A=1 AND B=2可命中索引。

    查询WHERE B=2无法命中索引,因缺少最左列A。

  • 优化建议:将高频查询条件放在联合索引左侧,避免索引失效。
7. ES中分页查询,页数过多如何处理?
  • 深度分页问题:ES默认分页通过from+size实现,但深度分页(如from=10000)性能差,因需扫描大量数据。
  • 解决方案

    游标分页(Scroll):适用于大数据量导出,保持游标上下文,但无法跳页。

    搜索后分页(Search After):基于上一页最后一条记录的排序字段值进行分页,支持实时数据。

    业务优化:限制最大页数或改用“上一页/下一页”导航,避免用户直接跳转至深页。

8. 搜索优化的措施
  • 索引优化

    合理设计字段类型(如keyword替代text用于精确匹配)。

    使用分词器(如IK)提高中文搜索准确性。

  • 查询优化

    避免wildcard查询,改用match或term查询。

    使用bool查询组合多个条件,减少嵌套查询。

  • 硬件优化:增加ES节点内存、使用SSD存储、调整线程池配置。
9. 用过线程池吗?
  • 线程池作用:复用线程资源,避免频繁创建/销毁线程的开销,控制并发数。
  • 核心参数

    corePoolSize:核心线程数。

    maximumPoolSize:最大线程数。

    keepAliveTime:空闲线程存活时间。

    workQueue:任务队列(如LinkedBlockingQueue)。

  • 使用示例:ExecutorService executor = new ThreadPoolExecutor( 5, 10, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100));executor.submit(() -> System.out.println("Task executed"));
三、面试体验与建议
  • 面试官评价:态度友好,问题由浅入深,注重考察基础知识和项目经验。
  • 准备建议

    复习JVM、集合类、并发编程等核心知识点。

    梳理项目中的技术难点及解决方案(如缓存策略、分布式锁)。

    熟悉ES、MySQL等中间件的优化技巧。

    练习手写代码(如HashMap的put逻辑、乐观锁实现)。