问题一:你CompletableFuture怎么用的?
问题二:为什么用自定义线程池?
问题三:你部署了吗?知道哪些部署方式
问题四:Redisson可重入锁怎么实现的
问题五:你用过什么mybatis插件
问题一:你CompletableFuture怎么用的?
我在项目里用 CompletableFuture 做多任务异步并行处理,主要分这几块说:
- 创建异步任务 用 supplyAsync 执行有返回值的任务、runAsync 执行无返回值任务,还能指定自定义线程池,避免用默认 ForkJoinPool。
- 任务编排组合
- thenApply/thenAccept:单个任务完成后串行执行后续逻辑;
- thenCombine:两个独立异步任务全部完成,再合并两者结果;
- anyOf:只要任意一个任务完成就往下走,allOf 需要所有任务全部结束;
- 异常处理 用 exceptionally 捕获异步任务抛出的异常,给兜底返回值,或者 handle 同时处理正常结果和异常,防止单个任务异常阻塞整体流程;
- 实际业务场景 比如我做后台数据统计时,并行查订单、用户、商品三张表的数据,用多个 CompletableFuture 同时发起查询,最后等全部完成再组装返回,相比单线程串行查询大幅缩短接口响应时间,最后用 get () 阻塞拿到最终结果。问题二:为什么用自定义线程池?
问题二:为什么用自定义线程池?
我简单说下为什么要用自定义线程池:
- 避免使用 Executors 默认线程池的隐患,比如无界队列会堆积大量请求,容易 OOM;
- 可以根据业务调整核心线程、最大线程、队列、拒绝策略,贴合项目并发量,资源可控;
- 统一管理线程,给线程命名方便日志排查线上问题;
- 配合 CompletableFuture 这类异步工具,复用线程,减少频繁创建销毁线程的开销;
- 不同业务隔离线程池,比如 IO 查询、文件处理分开,一个业务阻塞不会拖垮其他异步任务。
问题三:你部署了吗?知道哪些部署方式
我自己项目做过部署,常见几种部署方式我都了解:
- 传统服务器部署:把 Maven 打包好的 jar 包上传 Linux,用 java -jar 命令运行,搭配 nohup 或者 systemd 设置开机自启,适合小型项目。
- Docker 容器部署:编写 Dockerfile 构建镜像,用 docker run 启动容器,环境统一,不会出现本地和线上环境不一致的问题。
- Docker Compose:多服务项目,比如同时启动 Redis、MySQL、后端服务,用 compose 文件一键编排启动,本地测试或者单机部署很方便。
- K8s 部署:企业线上常用,通过 yaml 文件管理 Pod、服务、扩容策略,支持自动扩缩容、滚动更新,适合集群高并发项目。
- 云平台一键部署:比如阿里云、腾讯云应用平台,上传 jar 或者镜像就能自动部署,不用手动操作服务器,还自带监控告警。
我自己毕业设计项目是用 Docker 部署到阿里云服务器上的。
问题四:Redisson可重入锁怎么实现的
Redisson 可重入锁是基于 Redis 哈希结构实现的:
- 锁 key 是业务锁名,value 是一个 hash,key 存当前线程标识,value 记录该线程加锁次数;
- 第一次加锁:不存在这个 key 就创建 hash,线程计数设为 1;
- 同一线程再次加锁:匹配到相同线程标识,直接计数 + 1,不用等待;
- 解锁:先把计数减 1,计数大于 0 只重置过期时间,计数为 0 才删除整个锁 key;
- 底层用 Lua 脚本保证加锁、解锁、计数修改的原子性,防止并发数据错乱。
问题五:你用过什么mybatis插件
我项目里最常用的是 MyBatis-Plus 自带的分页插件,还有自定义的乐观锁插件,另外也了解过分页、性能监控类插件:
- 分页插件 PaginationInnerInterceptor 不用自己写分页 SQL,直接调用 Page 对象就能自动拼接 limit 语句,简化分页查询开发,适配 MySQL 等多种数据库。
- 乐观锁插件 OptimisticLockerInnerInterceptor 给表加 version 版本字段,更新时自动携带版本号条件,更新成功 version 自增,并发更新冲突时直接更新行数为 0,实现乐观锁防超卖,不用手动写判断逻辑。
- 额外用过第三方 / 自定义插件: 一是 SQL 性能监控插件,拦截 SQL 打印执行耗时,慢 SQL 会输出日志方便优化; 二是自定义字段填充插件,自动给创建时间、更新时间、操作人赋值,省去每次手动 set。