多线程
线程协调
有时候因为业务逻辑的关系,代码之间是相互制约的,如果随意加锁就会导致死锁or逻辑死锁。
因此就需要借助 wait 和 notify 来完成一些配合操作。
死锁
多个服务需要同时获取多把锁,如果不同服务获取的锁出现交叉问题,就会造成死锁。
如:
- 阻塞读 —— 写,自身交叉,没写就读不到,造成逻辑死锁
- 业务交叉,A 获取 A 锁,B 获取 B 锁,此时如果 A 需要获取 B 锁,B 又需要获取 A 锁,就会顺序交叉,同样造成物理死锁。
限流
通过 Semaphore 信号量限制 acquire 的线程数。
线程池
因为创建新的线程,需要额外的开销。
如果一个线程执行完后让其释放,而后执行另一个任务又另起线程,这一创建和释放就会白耗很多性能。
因此就需要借助线程池,对执行完的线程进行回收,需要用到时再从线程池内取,减少了创建新线程的开销。
CompletableFuture
对 Future 异步执行返回结果的操作进行优化,可以在 complete 和 exception 时传入回调操作自动执行。
同时还支持多线程下的串行执行(单个 then),并行执行(any -> 多个then),以及综合起来执行(any -> 多个then)。
点赞功能
用户对同一篇笔记点赞和取消点赞
实现:
先判断该用户是否已点赞
从 Redis 的 SortedSet中调用score查询,如果没有分数,则表示该用户未点赞
未点赞
- MySQL 自增 liked 字段
- 加入 SortedSet 中,并将 score 设置为当前时间戳
已点赞
- MySQL 自减 liked 字段
- 从 SortedSet 中移除
存在问题:
- 并发,同时多个线程绕过点赞判断,出现一个用户对同一篇笔记多次点赞
显示点赞效果
实现:
- 给实体类添加 isLike 属性
- 从 redis 中查询 score
点赞显示的对象按时间先后排列
实现:
- 从 Redis 中按 ZRANGE 查询(升序:时间先后)
- 查询 MySQL 用户信息
- 限制 MySQL 返回结果排列 ORDER BY FIELD(“id”, id1, id2)
- 返回脱敏用户信息