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

推荐订阅源

量子位
P
Privacy International News Feed
Security Latest
Security Latest
Spread Privacy
Spread Privacy
NISL@THU
NISL@THU
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
The Last Watchdog
The Last Watchdog
S
Schneier on Security
Engineering at Meta
Engineering at Meta
Google Online Security Blog
Google Online Security Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Know Your Adversary
Know Your Adversary
Cyberwarzone
Cyberwarzone
C
Cyber Attacks, Cyber Crime and Cyber Security
G
GRAHAM CLULEY
A
Arctic Wolf
博客园 - 聂微东
I
Intezer
腾讯CDC
罗磊的独立博客
T
Tailwind CSS Blog
WordPress大学
WordPress大学
宝玉的分享
宝玉的分享
L
Lohrmann on Cybersecurity
人人都是产品经理
人人都是产品经理
C
Cybersecurity and Infrastructure Security Agency CISA
博客园 - 【当耐特】
P
Palo Alto Networks Blog
Simon Willison's Weblog
Simon Willison's Weblog
W
WeLiveSecurity
N
News and Events Feed by Topic
SecWiki News
SecWiki News
S
Security Affairs
T
Threat Research - Cisco Blogs
The GitHub Blog
The GitHub Blog
F
Fortinet All Blogs
T
Troy Hunt's Blog
N
News and Events Feed by Topic
P
Proofpoint News Feed
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
酷 壳 – CoolShell
酷 壳 – CoolShell
M
MIT News - Artificial intelligence
I
InfoQ
Hacker News: Ask HN
Hacker News: Ask HN
T
The Blog of Author Tim Ferriss
Schneier on Security
Schneier on Security
Hacker News - Newest:
Hacker News - Newest: "LLM"
Vercel News
Vercel News
博客园 - 三生石上(FineUI控件)
D
Darknet – Hacking Tools, Hacker News & Cyber Security

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。。。

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