---
url: /notes/面试/真实面经/武汉音游科技有限公司/index.md
---
##

## mybatis默认反射设置属性慢

服务器无法处理请求，nginx代理其中一台服务器处理不了请求，直接访问也打不开页面

1.**日志查看出现GC**

```
jmap -dump 查看是否内存溢出
发现某个对象频繁创建！！！
```

2.查看进程占用高达1400%

```
top -Hp

printf %\n

jstack 线程 获取堆栈信息
发现某个方法一直在执行，分析可能是数据量大/数据库死锁
```

这个方法是统计报表用到，每个月底会执行，数据每天20w作业，统计实验室的温度，湿度；获取数据湖的数据

本地debug 直接卡死，GC

多线程并行分批处理，发现一天一天执行时间还是10分钟左右

排查sql问题，sql执行1-3s

方法里面打印执行时间，发现查询数据慢

可能是sql字段过多，映射实体较慢

修改xml指定具体字段，换指定jdbc类型和java类型转换

发现问题还是没有解决

可能是mybatis默认的反射（运行时动态解析）填充字段慢

修改为构造器（编译时，调用类的构造函数）方式映射

修改完执行时间减少到1-2分钟（每一天的数据）

## LinkedBlockingQueue阻塞队列实现事件调度，如果数据量过大，导致设置的队列长度满了，有没有方法解决

拒绝策略

使用当前线程处理

使用新线程处理

记录信息，发送消息提醒，手动重试

动态调整队列容量

使用带超时的offer方法，超时之后（丢弃当前事件、记录日志、 触发报警）

增加消费者线程数量

## 分布式锁除了通过key加锁（SETNX + Lua 脚本），还有没有其它的方式

**使用   SET   命令（带 NX/EX 参数）。**

Redis 的   SET   命令在 2.6.12 版本后支持   NX   和   EX   参数，可以直接在一条命令中完成加锁操作，避免了   SETNX   和   EXPIRE   分开执行带来的原子性问题。

实现原理：

使用   SET key value NX PX timeout   命令尝试加锁。

NX  ：只有当键不存在时才设置键。

PX  ：设置键的过期时间（毫秒）。

如果命令返回   OK  ，则表示加锁成功；如果返回   nil  ，则表示锁已被占用。

```java
import redis.clients.jedis.Jedis;

public class RedisLockExample {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("localhost", 6379);
        String lockKey = "lock_key";
        String requestId = UUID.randomUUID().toString();
        int timeout = 10000; // 锁超时时间，单位为毫秒

        String result = jedis.set(lockKey, requestId, "NX", "PX", timeout);
        if ("OK".equals(result)) {
            try {
                // 执行业务逻辑
            } finally {
                // 释放锁
                if (requestId.equals(jedis.get(lockKey))) {
                    jedis.del(lockKey);
                }
            }
        } else {
            // 获取锁失败，重试或返回
        }
    }
}
```

**使用 RedLock 算法，提高锁的高可用性和一致性。**

RedLock 是 Redis 的作者提出的分布式锁算法，通过多个独立的 Redis 实例来实现锁的高可用性和一致性。实现原理：

• 客户端尝试在多个独立的 Redis 实例上加锁。

• 只有在大多数实例（超过半数）上成功加锁，才认为获取锁成功。\\

• 锁的总耗时必须小于锁的有效时间。

```java
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

public class RedLockExample {
    public static void main(String[] args) {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://localhost:6379");
        RedissonClient redisson = Redisson.create(config);

        RLock lock = redisson.getLock("myLock");
        try {
            if (lock.tryLock(10, 10, TimeUnit.SECONDS)) {
                try {
                    // 执行业务逻辑
                } finally {
                    lock.unlock();
                }
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}
```

**使用 Lua 脚本，确保操作的原子性。**

Lua 脚本可以确保加锁和解锁操作的原子性，避免竞态条件。

实现原理：

• 使用 Lua 脚本将多个 Redis 命令封装在一起，确保操作的原子性。

• 例如，加锁时可以检查键是否存在，如果不存在则设置键并设置过期时间。

```java
import redis.clients.jedis.Jedis;

public class LuaLockExample {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("localhost", 6379);
        String lockKey = "lock_key";
        String requestId = UUID.randomUUID().toString();
        int timeout = 10000; // 锁超时时间，单位为毫秒

        // 加锁 Lua 脚本
        String lockScript = "if redis.call('exists', KEYS[1]) == 0 then " +
                            "redis.call('set', KEYS[1], ARGV[1]);" +
                            "redis.call('pexpire', KEYS[1], ARGV[2]);" +
                            "return 1;" +
                            "else return 0; end";

        // 释放锁 Lua 脚本
        String unlockScript = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
                              "return redis.call('del', KEYS[1]);" +
                              "else return 0; end";

        // 加锁
        Long result = jedis.eval(lockScript, Collections.singletonList(lockKey), Arrays.asList(requestId, String.valueOf(timeout)));
        if (result == 1L) {
            try {
                // 执行业务逻辑
            } finally {
                // 释放锁
                jedis.eval(unlockScript, Collections.singletonList(lockKey), Collections.singletonList(requestId));
            }
        } else {
            // 获取锁失败，重试或返回
        }
    }
}
```

**使用 Redis 的事务特性，实现简单的分布式锁。**

虽然 Redis 的事务本身不支持回滚，但可以通过事务的原子性来实现简单的分布式锁。

实现原理：

• 使用   `MULTI`   和   `EXEC`   命令将加锁和设置过期时间的操作封装在一个事务中。

• 如果事务执行成功，则表示加锁成功。

```java
import redis.clients.jedis.Jedis;

public class RedisTransactionLockExample {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("localhost", 6379);
        String lockKey = "lock_key";
        String requestId = UUID.randomUUID().toString();
        int timeout = 10000; // 锁超时时间，单位为毫秒

        jedis.watch(lockKey); // 监视锁键
        if (jedis.get(lockKey) == null) {
            jedis.multi();
            jedis.set(lockKey, requestId);
            jedis.expire(lockKey, timeout / 1000);
            List<Object> results = jedis.exec();
            if (results != null && results.size() == 2) {
                try {
                    // 执行业务逻辑
                } finally {
                    jedis.del(lockKey);
                }
            }
        } else {
            // 获取锁失败，重试或返回
        }
    }
}
```

## 防止多个用户操作同一数据造成数据不一致的问题

使用version，如果用户修改了数据还没提交，数据库挂了，有没有什么方法，保证修改了的数据不丢失

## 接口有重发机制，如果多次点击重发，怎么限制

**前端限制**

```
禁用按钮:在用户点击按钮后，立即禁用按钮，直到请求完成再重新启用
防抖（Debounce）:确保在用户停止操作一段时间后才执行请求，适用于需要延迟触发的场景。
节流（Throttle）:确保在指定时间内只执行一次操作，适用于需要限制操作频率的场景。
```

**后端限制**

```
使用 Redis 分布式锁:确保在指定时间内只处理一次请求
使用 Redis 的   INCR   命令:实现计数限制，适用于需要限制请求频率的场景
```

## 多线程countdownlatch并行查询，如果有线程报错或者执行失败，出现死锁，怎么解决

可设置超时机制，如果长时间执行，可以try catch手动让信号量减1

## 用到的设计模式

门面（提供统一接口，简化与多个子系统交互步骤），模板（定义业务骨架），建造者（构建和表示分离），策略（优化if else）

## 职业发展，5年经验需要会什么

https://note-1259190304.cos.ap-chengdu.myqcloud.com/noteimage-20241229205657540.png

## 遇到需求变更，或者leader和你的技术方案不同，你怎么解决

理解需求变更和技术分歧是项目开发过程中的一部分，保持开放的心态，愿意倾听和理解他人的观点。

在提出自己的观点之前，先花时间了解需求变更或技术分歧的背景和原因。

沟通是解决分歧的关键。主动与领导或相关团队成员进行沟通，表达自己的观点和担忧，同时也要倾听他们的意见。

在沟通的基础上，尝试找到双方都能接受的解决方案。

如果经过沟通和讨论后，最终决定采用领导的方案，要学会灵活调整自己的思路，积极配合项目的推进。即使自己的方案没有被采纳，也要理解这是项目决策的一部分，保持积极的工作态度。

无论最终结果如何，都要对这次经历进行记录和总结。

始终要从项目的整体目标出发，而不是单纯地坚持自己的技术方案。如果领导的方案更符合项目的短期目标或资源限制，即使技术上不是最优解，也可以接受。反之，如果自己的方案对项目的长期发展更有利，可以通过持续沟通和展示其潜在价值来说服领导。
