途虎养车-Java开发-一面 面经

1、请做个简单的自我介绍

您好,我是[姓名],[学校][专业]毕业,有[X]年Java开发经验。技术栈方面,我熟练掌握Spring全家桶、MyBatis、Redis、MySQL等主流技术,对分布式系统和微服务架构有比较深入的理解。项目经验上,我主要负责过电商平台的核心业务模块开发,包括商品管理、订单处理、支付对接等,日均处理订单量在50万左右。在这个过程中,我解决过不少生产环境的性能问题,比如通过引入Redis缓存和数据库索引优化,将接口响应时间从800ms降到了100ms以内。我比较注重代码质量和系统稳定性,平时也会研究一些开源框架的源码,持续提升自己的技术能力。

2、Redis的持久化方案有哪些,如果让你设计集群会选择哪种

Redis持久化主要有三种方案:

  1. RDB快照模式,它会在指定时间间隔内将内存数据集快照写入磁盘,通过fork子进程来执行,优点是恢复速度快、文件紧凑适合备份,缺点是可能丢失最后一次快照之后的数据
  2. AOF日志模式,它记录每个写操作命令,可以配置always、everysec、no三种同步策略,优点是数据完整性好最多丢失1秒数据,缺点是文件体积大恢复慢
  3. 混合持久化,Redis 4.0之后支持,AOF重写时将数据以RDB格式写入文件开头,增量数据以AOF格式追加,兼顾了恢复速度和数据完整性

如果让我设计Redis集群,我会选择RDB+AOF混合方案。具体来说:1)主节点开启AOF持久化保证数据不丢失,配置everysec同步策略平衡性能和安全性;2)从节点只开启RDB用于快速恢复和备份;3)同时开启混合持久化aof-use-rdb-preamble,这样既保证了数据安全,又不会因为持久化影响太多性能。另外还要配置合理的AOF重写阈值,避免文件过大。

3、手撕算法:矩阵中的最短路径(类似LeetCode 64变种)

这是一个动态规划问题,我的思路是这样的:

  1. 定义dp[i][j]表示从起点到达位置(i,j)的最短路径和
  2. 状态转移方程是:dp[i][j] = grid[i][j] + min(dp[i-1][j], dp[i][j-1])
  3. 边界条件:第一行只能从左边来,第一列只能从上边来
public int minPathSum(int[][] grid) {
    int m = grid.length, n = grid[0].length;
    int[][] dp = new int[m][n];
    
    dp[0][0] = grid[0][0];
    
    // 初始化第一行
    for (int j = 1; j < n; j++) {
        dp[0][j] = dp[0][j-1] + grid[0][j];
    }
    
    // 初始化第一列
    for (int i = 1; i < m; i++) {
        dp[i][0] = dp[i-1][0] + grid[i][0];
    }
    
    // 填充dp数组
    for (int i = 1; i < m; i++) {
        for (int j = 1; j < n; j++) {
            dp[i][j] = grid[i][j] + Math.min(dp[i-1][j], dp[i][j-1]);
        }
    }
    
    return dp[m-1][n-1];
}

时间复杂度O(m×n),空间复杂度可以优化到O(n)只用一维数组。

4、布隆过滤器的原理是什么

布隆过滤器是一种空间效率很高的概率型数据结构,用来判断一个元素是否在集合中。它的原理是:

  1. 使用一个bit数组和多个hash函数,添加元素时,通过k个hash函数计算出k个位置,将这些位置的bit设为1
  2. 查询元素时,同样计算k个位置,如果这些位置都是1,则元素可能存在;如果有任何一个位置是0,则元素一定不存在
  3. 特点是存在一定的误判率,可能会把不存在的元素判断为存在(假阳性),但不会把存在的元素判断为不存在(假阴性)
  4. 误判率与bit数组大小、hash函数个数、元素数量有关,可以通过增加bit数组大小和hash函数个数来降低误判率

实际应用场景包括:1)缓存穿透防护,在查询Redis之前先用布隆过滤器判断key是否存在;2)爬虫URL去重;3)垃圾邮件过滤;4)推荐系统中判断用户是否看过某个内容。优点是空间占用极小,1亿数据只需要几十MB,缺点是不支持删除操作,需要用计数布隆过滤器。

5、用过哪些锁,可重入锁是如何实现的

我在项目中用过的锁主要有这几种:

  1. synchronized关键字,这是JVM层面的锁,使用最简单,适合锁竞争不激烈的场景
  2. ReentrantLock可重入锁,它提供了更灵活的锁操作,支持公平锁、可中断、超时获取锁等特性
  3. ReadWriteLock读写锁,适合读多写少的场景,多个线程可以同时读,但写操作是互斥的
  4. 分布式锁,基于Redis的SETNX或Redisson实现,用于分布式环境下的资源互斥访问

可重

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

Java面试圣经 文章被收录于专栏

Java面试圣经,带你练透java圣经

全部评论
我想知道你是真人还是人机
点赞 回复 分享
发布于 03-16 11:05 河南
接好运
点赞 回复 分享
发布于 03-13 14:48 上海

相关推荐

03-20 10:04
湖南大学
一、Java基础1.&nbsp;HashMap底层原理数组+链表+红黑树,JDK1.8后引入红黑树。初始容量16,负载因子0.75,扩容为原来2倍。线程不安全,多线程推荐使用ConcurrentHashMap。2.&nbsp;ConcurrentHashMap&nbsp;1.7和1.8区别1.7:Segment分段锁+数组+链表,锁粒度较大。1.8:CAS+synchronized,数组+链表+红黑树,锁粒度更细,性能更高。3.&nbsp;ArrayList和LinkedList区别ArrayList:动态数组,查询快,增删慢。LinkedList:双向链表,查询慢,增删快。4.&nbsp;String、StringBuilder、StringBufferString不可变,线程安全。StringBuilder可变,非线程安全,效率最高。StringBuffer可变,线程安全,效率较低。二、并发编程5.&nbsp;synchronized底层实现修饰方法:ACC_SYNCHRONIZED标识。修饰代码块:monitorenter、monitorexit指令。锁升级流程:无锁→偏向锁→轻量级锁→重量级锁。6.&nbsp;ReentrantLock和synchronized区别ReentrantLock:手动加锁解锁,支持可中断、超时、公平锁。synchronized:自动加锁解锁,使用简单。7.&nbsp;线程生命周期新建、就绪、运行、阻塞、终止。8.&nbsp;死锁四个必要条件互斥、请求保持、不可剥夺、循环等待。破坏任一条件即可避免。三、JVM9.&nbsp;JVM内存模型堆、方法区、虚拟机栈、本地方法栈、程序计数器。10.&nbsp;垃圾回收机制对象存活判断:引用计数法、可达性分析法。回收算法:标记清除、标记复制、标记整理。11.&nbsp;常见垃圾收集器Serial、ParNew、Parallel&nbsp;Scavenge、CMS、G1。四、计算机基础12.&nbsp;TCP三次握手、四次挥手三次握手:建立可靠连接。四次挥手:断开连接,保证数据传输完成。13.&nbsp;HTTP和HTTPS区别HTTP明文传输,端口80。HTTPS加密传输,端口443,基于SSL/TLS。14.&nbsp;MySQL索引底层B+树,分为聚簇索引和非聚簇索引。遵循最左匹配原则,避免索引失效。15.&nbsp;MySQL事务ACID原子性、一致性、隔离性、持久性。五、项目与场景16.&nbsp;接口限流方案计数器、漏桶算法、令牌桶算法。17.&nbsp;分布式锁实现Redis分布式锁、Zookeeper分布式锁。18.&nbsp;Redis缓存问题缓存穿透:布隆过滤器。缓存击穿:互斥锁、热点数据永不过期。缓存雪崩:过期时间随机、集群部署、服务降级。
查看18道真题和解析
点赞 评论 收藏
分享
评论
1
9
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务