惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
Docker
爱范儿
爱范儿
人人都是产品经理
人人都是产品经理
博客园 - 司徒正美
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
量子位
罗磊的独立博客
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
小众软件
小众软件
C
Cybersecurity and Infrastructure Security Agency CISA
Cyberwarzone
Cyberwarzone
大猫的无限游戏
大猫的无限游戏
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
雷峰网
雷峰网
Simon Willison's Weblog
Simon Willison's Weblog
The Cloudflare Blog
博客园 - 三生石上(FineUI控件)
D
Darknet – Hacking Tools, Hacker News & Cyber Security
C
Cyber Attacks, Cyber Crime and Cyber Security
博客园_首页
博客园 - 叶小钗
V
Vulnerabilities – Threatpost
T
The Exploit Database - CXSecurity.com
T
Tailwind CSS Blog
IT之家
IT之家
博客园 - 聂微东
Spread Privacy
Spread Privacy
V2EX - 技术
V2EX - 技术
S
Security Affairs
宝玉的分享
宝玉的分享
V
V2EX
C
Cisco Blogs
博客园 - Franky
美团技术团队
酷 壳 – CoolShell
酷 壳 – CoolShell
月光博客
月光博客
S
Securelist
J
Java Code Geeks
Webroot Blog
Webroot Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
P
Proofpoint News Feed
Last Week in AI
Last Week in AI
L
LINUX DO - 热门话题
NISL@THU
NISL@THU
WordPress大学
WordPress大学
W
WeLiveSecurity
T
Threatpost
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
腾讯CDC
阮一峰的网络日志
阮一峰的网络日志

GoodBoyboy 's Blog|惬意小屋-点滴记忆

新设计了一个Astro主题 Cap,一个基于PoW的自托管验证码系统 公益服务迁移通知 一种基于argon2id算法与shamir算法的内存PoW(工作量证明)解密游戏 记忆里的屋子(一) Ubuntu 26.04 Btrfs+LUKS2安装 主域名服务不稳定通知 腾讯元宝客户端实习二面凉经 腾讯元宝客户端实习一面面经 对越来越多AI博文的看法 GoodBoyboy Blog、Talk联动成功 只有失去了才会懂得珍惜,但幸好我还没有失去 滴滴Android客户端一面凉经 GoodBoyboy 's Talk上线! Easy Drop——一个基于Gin开发的高性能、轻量级说说平台 Perfect Pic —— 一个基于 Gin 开发的高性能、轻量级图床 尘封了八年的祝福 欢迎OPPO Pad 4 Pro加入设备大家庭 官方Android11 Box系统的OrangePi 3B新增红外模块教程 家里也换成光纤了qwq 姜还是老的辣 布洛芬效果真不错 再见2025,你好2026 Canokey导入S/MIME邮箱证书并使用Thunderbird发送邮件 1.90$申请 WISeID S/MIME 邮箱证书 新购Intel AX210网卡 OpenPGP邮件加密——关于测试邮件握手的思考 疯狂动物城2太好看了(无具体剧透) 进程调度——时间片轮转 效果是真的好,劲也是真的大 不买立省100% 十月小记 新增外设漫步者G1500bar 欢迎招行万事达加入卡包大家庭 博客十周年啦🎉 ESP32 S3开发小结 ESP32 S3外设小记 Arduino+VSCode开发ESP32-S3 EPS32-S3刷入MicroPython EPS32 S3刷入Picokeys Debian13安装Nvidia驱动 现在小孩都这么早熟么。。。 《动物迷城》二周目通关! Bing索引终于恢复了 家里蹲大学开始招生! 家里蹲大学即将建校,欢迎各位莘莘学子来本校深造(doge 骑车去兜风~ OAuth2授权码、客户端凭证、PKCE、设备码授权流程详解 基于OIDC实现Authentik与阿里云RAM角色的联合身份认证 GitHub release以及Git Commit常用模板 实验室生活 阿里云角色SSO对接authentik进行单点登录 白嫖一年Gemini Pro 突然发现自己可能乳糖不耐受? Android第三方Passkey管理器探索 [公告]现评论区已支持使用emoji表情符号😊 Debian GRUB踩坑记——out of memory 为Debian KDE更换显示字体为思源黑体 Debian补全办公常用字体 Debian12 KDE Edge输入法问题 Debian KDE Plasma 5调整外接显示器亮度 Debian开玩Minecraft Debian KDE使用指纹传感器验证身份
多线程我太爱你了,你个“大可爱”
GoodBoyboy · 2025-06-26 · via GoodBoyboy 's Blog|惬意小屋-点滴记忆

又是大早上被多线程折磨的一天

先简单讲一下功能框架吧

flowchart TD
    A(用户发起查询操作) --> B{查询cache}
    B -- 有 --> C[返回cache内容给用户]
    B -- 没有 --> D[请求remote]
    D --> E[remote返回内容]
    E --> F[内容返回给用户]
    E --> G[remote内容写入cache]

简单来说就是从两个数据源获取信息,先查cache,cache没有再查remote,remote得到数据后返回给用户并写入cache

然后就出问题了,具体问题表现为出现重复插入情况

经过排查,发现remote请求返回的数据正常,但是到写入Room数据库的时候出现插入数量正确,但是部分item重复插入,部分item丢失的情况

问了一下ChatGPT,在给出的几个可能性中锁定到多线程并发写入导致的竞态和异常。

不过虽然该保存数据的函数确实是suspend的异步函数,但是我在函数入口明明打了断点,断点只触发一次,不存在多线程的问题

把代码贴上来问了问ChatGPT,结果给我整绷不住了:

问题

不是,也没人给我说呀,怎么kotlin的foreach和for还有这大坑等着我的。。。

然而把foreach改成for后还是一样的问题,继续追问

在众多的可能性中,锁定协程作用域问题

指出确保你的suspend fun saveServiceList()不是在多个协程并发调用!否则即使方法内部串行,外部还是会并发插入,导致竞态。

但是之前说过,我打的断点明明只触发一次,怎么会出现外部多次调用呢?

没办法,按照ChatGPT说的老老实实打Log看输出,在dao的insert方法前后插Log,发现确实是出现竟态问题。

然后ChatGPT再次指出确保整个suspend方法不在多个协程并发调用,提出用Mutex锁包裹整个suspend方法

结果发现居然没问题了???

所以还真是被多个协程调用了???我怎么不知道???

虽然用锁临时解决了该问题,但这个操作本质是不应该被多个协程调用的,说明代码本身有问题

本着不想写屎山的心态,继续问

然后ChatGPT指出:

原因

原因

所以断点在并发协程中并不适用来判断调用次数

我:多线程你太可爱了

给suspend方法第一行插个Log,发现确实日志打印了两遍

然后就是顺藤摸瓜,给所有调用点全部插Log,最后发现在ViewModel中的起始loadService函数被调用了两次

定位到View中发现在UI里有两处调用,一看代码就发现问题了。

一个来自ViewModel中的loadServiceState在View中监听,当State由Idle变为Loading后触发loadService,加载数据

然后一个手动刷新按钮,首先清除数据,然后更改loadServiceState的State为Loading,最后手动调用loadService

因此当手动刷新时,就会出现loadServiceState改变而触发的loadService以及按钮自身调用的loadService。。。

代码一多自己都忘记原来写的逻辑了,又是被多线程折腾的一天