Apong's Blog

当你快坚持不住的时候,困难也快坚持不住了

0%

Java多线程、SortedSet

多线程

线程协调

有时候因为业务逻辑的关系,代码之间是相互制约的,如果随意加锁就会导致死锁or逻辑死锁。

因此就需要借助 wait 和 notify 来完成一些配合操作。

死锁

多个服务需要同时获取多把锁,如果不同服务获取的锁出现交叉问题,就会造成死锁。

如:

  1. 阻塞读 —— 写,自身交叉,没写就读不到,造成逻辑死锁
  2. 业务交叉,A 获取 A 锁,B 获取 B 锁,此时如果 A 需要获取 B 锁,B 又需要获取 A 锁,就会顺序交叉,同样造成物理死锁。

限流

通过 Semaphore 信号量限制 acquire 的线程数。

线程池

因为创建新的线程,需要额外的开销。

如果一个线程执行完后让其释放,而后执行另一个任务又另起线程,这一创建和释放就会白耗很多性能。

因此就需要借助线程池,对执行完的线程进行回收,需要用到时再从线程池内取,减少了创建新线程的开销。

CompletableFuture

对 Future 异步执行返回结果的操作进行优化,可以在 complete 和 exception 时传入回调操作自动执行。

同时还支持多线程下的串行执行(单个 then),并行执行(any -> 多个then),以及综合起来执行(any -> 多个then)。

点赞功能

用户对同一篇笔记点赞和取消点赞

实现:

  1. 先判断该用户是否已点赞

    从 Redis 的 SortedSet中调用score查询,如果没有分数,则表示该用户未点赞

  2. 未点赞

    1. MySQL 自增 liked 字段
    2. 加入 SortedSet 中,并将 score 设置为当前时间戳
  3. 已点赞

    1. MySQL 自减 liked 字段
    2. 从 SortedSet 中移除

存在问题:

  1. 并发,同时多个线程绕过点赞判断,出现一个用户对同一篇笔记多次点赞

显示点赞效果

实现:

  1. 给实体类添加 isLike 属性
  2. 从 redis 中查询 score

点赞显示的对象按时间先后排列

实现:

  1. 从 Redis 中按 ZRANGE 查询(升序:时间先后)
  2. 查询 MySQL 用户信息
  3. 限制 MySQL 返回结果排列 ORDER BY FIELD(“id”, id1, id2)
  4. 返回脱敏用户信息