普通视图

发现新文章,点击刷新页面。
昨天以前暮光博客

写在博客十周年这一天

作者 大袋鼠
2023年8月1日 00:12

十年之约,这一天如期而至。

2013 年那个夏天,我坐在电影院的后排,跟着电影《致青春》的叙事试着共鸣别人的青春回忆故事。但我只记得当时看得无聊,剧情不对我的路子。当然,令我共鸣失败的主要原因是:那年我 18 岁,我的高考刚刚结束,我正在真真切切地拥有着青春和对青春的感受。

不止电影,无关乎表达形式,怀念青春对那时的我来讲是一种陈词滥调。站在十年后的今天,我惊觉时间过得好快,回望过去开始变得频繁并且难以抑制,「陈词滥调」渐渐成了我的常态。

我时常会回忆起 13 年新年伊始的那段日子。彼时还没放寒假,我在学校的信息教室里做着文综模考,答完卷子也不检查,望着窗外的漫天大雪出神。那时的我沉浸在意识空间里,觉得人一辈子都能保持着憧憬,觉得未来应当是一片坦途。

这种自信好奇怪,也不知道哪来的底气。

9904f48d.jpeg

十年后,那些憧憬都消失不见。

博客十年并不特殊,「10」仅仅是数字的累加,但它在人类的心理活动面前,被重新赋予意义,我觉得我需要趁此机会写下一点点感受。

主动纠偏

生活很多时候都是一个被动选择的命题,人的解题方式通常就是不作声响地顺着它走下去。于是,太多的渴望被抑制了,太多的无趣也都被容忍了。

这难免有时让我在生活中感到失控和自我怀疑。

而摆脱失控和纠正自我怀疑的能力,我称作主动纠偏。主动纠偏使我面对生活时拥有了更多的韧性和话语权,拥有了拒绝某种特定生活的底气。如果让我选取过去十年中两次关键的自我纠偏,那么一次是我在大学时决心抛弃修读的专业,投身到自己喜欢的行业中;另一次就是现在,我暂时离开了工作,正在为人生重新设定轨道。

seaside.jpg

行动力来源

我正处于身体和精神状态的巅峰状态 —— 对未来而言,是的。

人的一生大几十年,说起来很漫长,但其中的大半光阴皆无可能处于青春时的旺盛状态,而是处于稳定的衰老和持续变得更衰老中。这让我逐渐认识到,当下每一天我都处于身体与精神状态的双重巅峰,这种宝贵的状态我不能浪费,我要趁着年轻去探求更多的人生可能性。

我不想理所当然地就这样衰老下去、重复下去、自怨自艾地感叹「我已不再年轻了」,这种拒绝就是我的行动力来源。如果一定要对未来期许些什么,我希望是:少一点雷同与重复,多一点探索和惊喜。

以上是我面对生活给出的部分答案。

写得匆忙,行文逻辑会有些乱。

下个十年,我们再会。

十周年特别鸣谢:

  • 某位旧同事。他抢注了我在十多年前使用的博客域名 daishu.me,并将其转赠给我
  • 长期以来订阅暮光博客的独立博客博主和其他网友

Typecho v1.2.1-rc 的 XSS 漏洞

作者 大袋鼠
2023年5月8日 16:33

3 月份 Typecho 被曝出评论区网址字段存在存储型 XSS 漏洞,详见 issue#1545,为此,官方释出了 v1.2.1-rc 解决该漏洞。

然而,v1.2.1-rc 版本未能完全修复该问题,评论区的邮箱字段同样存在存储型 XSS 漏洞。对此我 4 月份提交了 issue#1560pull#1561 以解决该漏洞,但此 PR 还未进行合并。

💬[2023-05-17] Typecho 在 v1.2.1-rc.2 版本将我的 PR 合并,该问题已得到解决。

影响范围

Typecho 版本:v1.2.0 ~ v1.2.1-rc

PS:版本低于 v1.2.0 的用户不受影响。

漏洞原因

漏洞原因我已在 issue#1560 进行说明,可以进去看看。大致原因是 v1.2.0 之后 Typecho 官方更新了评论网址和邮箱的字段验证器,但新的验证器使用了 PHP 的 filter_var() 方法,该方法作为验证器并不够严格,包含了恶意代码的值可以顺利通过校验。管理员在 Typecho 后台查看该评论时,恶意代码就会被执行,并进一步完成提权等恶意操作。

POC

POC 同样参见 issue#1560

解决方案

在官方发布版本彻底修复该漏洞前,请按照以下思路进行修复:

使用 v1.2.0 的用户,请先升级到 v1.2.1-rc,然后按照 pull#1561 进行修复。
使用 v1.2.1-rc 的用户,直接按照 pull#1561 进行修复。

在问题修复前,建议临时关闭评论功能,以避免可能的攻击。

一次惊喜的 Apple 售后

作者 大袋鼠
2023年3月14日 11:46

很抱歉啊大家伙儿,我的博客成功变成了年更,对不起订阅我的朋友们。 icon_razz.gif


上周六,我打电话给 Apple 客服,请求更改我修电脑的预约时间。我原本预约了周六去检修 MacBook,但不幸的是,我中标了甲型流感,头疼脑热四肢酸痛,难受得我床都下不去,更遑论出门了。

幸亏了这通电话,让我知道了还有「特例维修」这回事。

为什么要修电脑

我的电脑在年初时 Touch Bar 右侧功能栏开始疯狂闪烁,重置 NVRAM 和 SMC 后并无改善。瞧这状态,我已笃定是硬件故障,互联网上也有资料指出这可能是电池鼓包问题导致的 Touch Bar 电路短路。

ezgif-5-b80df2b77b.gif

MacBook 整机保修 1 年,主要部件保修 2 年,这台电脑购于 21 年 3 月初,已过保数日。另外,Apple 有推出键盘保障计划,针对一些 2019 款之前的型号,4 年内可以免费更换键盘,但我的电脑型号不在保障计划范围内。

有朋友会问:为什么不赶在 3 月过保之前修?答案是:之前我不知道主要部件保修 2 年这回事。

可以说,我已经做好了自费维修的心理准备。

致电 Apple

先前我预约了 Apple 杭州万象城店的天才吧,预约的到店时间是上个礼拜六。但我因为甲流身体实在感到不适,只能改期。而当天 Apple 的在线工单有故障,改期操作一直失败,无奈我只能打电话给 Apple 客服让他们帮忙操作。

我打电话的本意只是为了变更预约时间,电话那头的客服却开始为我的案例提供全面跟进,热心客服给我交代的大致细节如下:

  1. Touch Bar 属于键盘,键盘是 MacBook 主要部件,享 2 年质保。
  2. 我的电脑已过保,但过保时间不长,请我不要担心,她有权限为我的质保期限做「适当延长」。
  3. 叮嘱我注意身体,若病情加重,记得就医。

同时她为我办理了改期,预约时间改到了礼拜天,并且告知我随时可以联系她,她会全程跟进这个案例,并与当地天才吧说明情况。

到店检修

礼拜天,身体状况大幅好转,我便赶往天才吧,而她也如约来了电话。她让我把电话递给工程师,交代了她的身份和「特例维修」的情况。而后经过工程师的检测,Touch Bar 确实存在硬件故障。

2023-03-14_19-29-10.png

Apple 的维修方案是更换整个 Top Case,包含键盘 + 触控板,这也是 Touch Bar 故障的官方通行维修方案,维修报价 3907 元。得益于这位客服的努力,我享受到了质保内的免费维修。

今天,天才吧那边发来邮件,通知我配件已到货,周末到店更换即可。

谢谢这位热心专业的 Apple 客服,她帮我办了事、省了钱,还叮嘱我保重身体。

哭了。


[Append] 2023-03-20
今天维修完毕,取货后发现电池循环次数为 0,也就是说电池也被更换为全新的了,我有一种白嫖了一台新电脑的感觉。

本周小记 - 20220515

作者 大袋鼠
2022年5月15日 19:59

友情链接里少了一个博主,多了一个黄网

今天检查了一下友情链接里每个博客的存活状态,发觉又有若干博客默默结束了它们的生命周期。

面对这些关停的博客,我通常还会保留很久,因为我拿不准他们是临时故障还是永久失联,毕竟「诈尸」的情况发生过好几次。这一年是暮光博客存在的第九个年头了,眼见着一些老博客陆续倒下,一些新博客建立又倒下。还有一些眼熟的博客进入封笔状态,而我也在接近这个状态。

说回检查友链这事,如果单单有几位博主朋友失联,倒不是件新奇事情。偏偏惊悚的是,有一位朋友的博客被色情网站夺舍了。本来面色平静的我,愣是心脏乱蹦了几拍,娘希匹的,还好四周没人。欣赏了几段无趣的视频后,我决定把这件事写进小记里。

再见,旧朋友;你好,黄网哥。

卖掉茅台

家里的茅台,本想屯到逢年过节,行情好了再卖的。但最近茅台酒市场价格有些不稳定,而且放家里也占地方,索性趁早卖掉。

20220515202338 (1).jpg

于是今天就卖掉了。

永远的长度

作者 大袋鼠
2021年12月25日 23:22

在我最迷茫的时期,许巍的歌给了我特别多的温暖和鼓舞,那时我觉得许巍应当是我永远喜欢的歌手。后来我的生活拨开云雾步入正轨,他的歌我便少听了。19 年他在杭州巡演,我独自买了张内场票坐在场内默默听完所有的曲目。

也就是演唱会那天,我对曾经那段迷茫的日子做了告别,此后我耳机里几乎不再放许巍的歌。

过去我觉得人会永远喜欢某首歌某本书,或是永远记得某件事某个人。可我翻看我十年前的日记,有一页写道:"我永远忘不了这一天",我想了足足半天,也没有想起那天到底发生了什么,可见永远其实一点也不远,永远的长度取决于你会爱它多久,需要它多久,记住它多久,认可它多久。

之前固件带后门?于是我自行编译了 N1 OpenWrt 固件

作者 大袋鼠
2021年11月28日 19:38

2019 年初折腾的斐讯 N1,三年来一直作为我的家庭旁路由,承担科学上网工作。去年国庆期间,由于之前固件中科学上网不支持 trojan 协议,就在恩山找了一个网友自编译固件更新到 N1 中,新固件内置了许多第三方插件,包含支持多种协议的科学上网、AdGuard Home、音乐解锁等,然而除了科学上网,其他功能我并用不上。

今年夏天,一次偶然地在主路由翻看日志时,发现经常会有不同的华为设备连接到我的家庭网络。起初,我以为是家庭 WiFi 密码遭到泄露,于是更换了密码,并停止了 SSID 广播。然而,还是会有华为设备不断连进来,包括各种型号的华为手机和平板。

WX20211128-190042.png
(主路由日志,各种华为设备连接记录)

后来我依然猜想是 WiFi 被蹭网,或者是主路由的 DHCP 有 BUG,这半年来没太当回事。
直到前几天下班回家,惊讶发现我的小爱音箱居然在自己播放电影音频。经过一番研究,发现电影是通过局域网 DLNA 点播到我音箱上的。这引起了我极大的不适,这都拉屎拉到我头上了。

于是写脚本监控设备连入,有未知设备连入时就通知我。后续有华为设备连入时,我第一时间去查看了华为设备的网络通信记录,发现华为设备和全国各地的 IP 都有通信。我的家宽极有可能被后门程序开放到公网,放进代理 IP 池了。在家里来来回回拔了几次网线,最终锁定这些华为设备都是从 N1 连入的,因为只要我拔掉 N1 的网线,我就 ping 不通华为设备了。

好家伙,给人当了一年肉鸡。

这里要提一下,这些所谓的「华为设备」可能并非是真实的华为设备,而是后门程序自行虚构的 Hostname 和 MAC 地址。

老固件是哪一个?

其实我本来不想公布老固件型号,因为该作者在恩山发布固件,有诸多用户,未见过其他用户反馈类似问题。后门程序可能不存在于固件本身,而是集成的各种第三方插件,作者可能也处于不知情状态。但思索很久还是发出来吧,如果有其他网友有类似问题,也可以给个参考。

老固件型号是「OpenWrt R20.10.1 国庆中秋双节特别版 by gd772」,在恩山的发布帖子是[N1盒子] 【2021-08-14 】 N1盒子 Openwrt 固件,支持 在线升级!

在此声明,我极大怀疑是内置的某个插件存在后门,具体哪个插件我无法排查,我并非质疑作者有意在编译的固件中投放后门。

自行编译新固件

自此,我觉得还是自己编译固件比较放心,最起码不用内置多余的插件,增加不必要的风险。我用 Parallel 开了一台 Ubuntu 虚拟机,拉取了 Lede 的代码,为了安全和纯净,我只将科学上网插件编译了进去。整个编译过程耗时 4 个多小时,编译完毕后,使用恩山知名用户 flippy 的 Armbian 内核和镜像制作工具,将编译好的 OpenWrt 制成镜像,写入 U 盘。将 U 盘插到斐讯 N1,重启后 U 盘启动,连入 OpenWrt SSH,使用 flippy 的 EMMC 一键写入脚本,将 OpenWrt 写入到 N1 存储中。从编译固件到最终写入 N1,整个过程耗时很久,把我搞得很疲惫。中间也来来回回二次编译了几次,因为第一次编译的固件写入 EMMC 时失败,主要原因是一些写入 EMMC 的依赖工具没有编译进去,比如 fdisk、bikid 等分区工具、文件系统等。

61E91BED-A79E-4B15-B795-BE4EAC602776.png
(LEDE 编译和镜像制作过程)

自行编译的固件很干净,不出意外的话,它作为旁路网关仍将服务我很长时间。

WX20211128-184106.png
(自行编译的新固件界面)

最后不得不说,到 2021 年底,N1 的各种玩法已经很成熟。2019 年初刚玩时,OpenWrt 固件写入 EMMC 还是一个很费事的工作,如今得益于一些大佬的努力,这项工作已经非常简单。

最后,我把固件上传到了云盘。
百度云:https://pan.baidu.com/s/1_rmBpJ5RmEW8EP6UOA-Wag?pwd=atm7
天翼云:https://cloud.189.cn/web/share?code=vIJbimjeMrQ3(访问码:cmp9)

下载完先解压为 .img 文件再制作镜像盘。
默认IP:192.168.123.2
默认账号密码:root / password

一次奇妙的流量暴涨

作者 大袋鼠
2021年8月30日 14:24

上周四,接到阿里云通知服务器流量暴涨。我第一反应是被人攻击了,我博客几年来流量都相当平稳,流量暴涨极有可能是被攻击。遂打开网站统计,惊讶地发现几乎所有访客都是从两个短链跳进来的。

因为来源都是短链,也就没办法获悉真正的入口是哪里。当时我想了一个馊主意,打开问卷星网站,编辑了一份问卷,问卷大致内容是:亲爱的访客,您是从哪个地方来的,如果方便的话最好提供下截图。问卷编辑完之后,我将它挂在博客首页的醒目位置,还特意标了红。二十分钟后竟收集上来 40 多份答卷,而更让我惊讶的是这些访客真正的流量入口,几乎都来自于 QQ 或者 QQ 群。


1630302294369.jpg

WechatIMG1774.png

WX20210830-135503.png

等等,灵儿色图?事情好像越来越不对劲了啊!这种感觉,就像你的手机号码被写在黑网吧男厕所的同性交友广告上。

而从访客那里收集上来的截图也是相当离谱,挑几张给大家欣赏下。


WX20210830-135835.png

WX20210830-135910.png

WX20210830-135946.png

WX20210830-140016.png

我意识到,有两条色情引流的短链,不知为何,最终指向了我的博客,从而导致流量暴涨。

很难想象,手机屏幕前一个个血脉偾张的热血少年,裤子都脱了,然后「暮光博客」四个大字和一篇篇杂文映入眼帘,没有大胸也没有美腿,他们是作何感受。通过网站分析,我发现有那么几个迷失少年,几乎快把我的文章翻完了,不知道他们有没有被我的文字打动,迷途知返。

而事情总要解决的,流量继续这么增长下去我博客的小水管要撑不住了。两条短链还包装了第二层跳转,正是这第二层最终指向了我的博客。我打开第二层的短链网站,联系到网站客服,跟客服描述了这一魔幻经历,客服表示可能是他们的客户填错了。


WX20210830-140950.png

WX20210830-141016.png

那么,究竟是哪个导流从业大哥,把链接错填成我的博客了呢?想必这一定是真爱了。

客服帮忙解决后,短链全部改为指向 QQ 群的加群链接。我顺手加到群里,群内成员增加速度相当迅速。当成员到达一定数量后,群主机器人开始推送卖货广告或外卖优惠券广告。至此,一条生意链条被我发现,大致是:色情广告引流 => 短链接跳转加群 => 群内广告卖货。

至于那短链为什么突然指向我的博客,可能不只是错填那么简单,真正的原因目前还不得而知。未来,应该也不会知道了。

上周小记 - 20210823

作者 大袋鼠
2021年8月23日 22:09

说起来博客已有 10 个多月没更新,这是今年的第一篇日志。停更原因是从去年开始脑子有些混乱,思维很难连贯,这可能是身体方面的原因,也可能是纯粹地懒。
2021 年已进入 8 月份,本博就是在 2013 年 8 月份建立,迄今已经走过 8 个年头,就这么停更了怪可惜的,所以我还是决定重新拾起来。

回顾下上周值得写的事情吧。

更换电脑 SSD

我有一台 2019 年配的台式主机,当初图性价比,配了一块 250G 的「东芝 TR200」做系统盘。网上普遍说这块 TR200 叫「特弱 200」,说实话的确是这样。当初刚装完系统的准空盘状态,SATA3 + 4K 对齐,读写速度勉强维持在 400~500Mb/s 左右,对我来说已经达到预期了,也没觉得对整机性能上有什么影响。

ajnnr-6dmh3.png

后来陆续装了几个游戏譬如《War Thunder》、《GTA5》,存储容量逐渐上涨。在今年年初,系统盘已接近满载,TR200 开始出现了惊人的令人发指的掉速。

20210110190047.png
(今年年初跑分图)

连续写入速度达到惊人的 18Mb/s,我手里的台电 U 盘都比它快!网上都说 TR200 这块 SSD 就是一个大号 U 盘,果然名不虚传。这恶心的掉速原因我将其归结为 SLC Cache 用尽,但掉速程度实在过于夸张,我怀疑它可能一开始就是个翻车盘。

所以上上周我采购了一块 500G 的「铠侠 RC10」M.2 NVMe 固态,准备替换掉那块该死的「特弱 200」。你们以为我换了个牌子吗?错了,「铠侠」正是改名后的「东芝」。但好在「铠侠 RC10」网上口碑不错,在性能上比「西数 SN550」还要好一丢丢。


WechatIMG1771.jpeg

20210823214450.png

「铠侠 RC10」到货后,贴上散热片、上机、装系统、跑分,跑分结果和实际体验都让我感到满意,终于体会到什么是丝滑的感觉了。之前那块「特弱 200」被我用来当做副盘,迁出游戏后腾出了一些空间,读写速度又恢复到 400+Mb/s,一点也不意外,这块破盘,呸。

周末骑行

周末跟几个同事从滨江区一路骑行到萧山戴村镇,来回共计 62 公里,一路上欣赏风景走走停停,花了 7 个小时。我没有自行车,所以提前租了一辆捷安特普通山地车。小车目测车架是 17 寸,轮胎 26 寸,我查了下,这种尺寸的山地车建议身高是 165cm~175cm,对我这个一米九壮汉来说未免有些不友好。车座需要调高,不然腿蹬不直,会伤膝盖;而车把又太低,导致我整个身体前倾很严重。骑到 20 公里左右时,我的腰部、屁股、手腕出现了不同程度的疼痛。因为车架太小,我的体态全程是「蜷着的」,骑到 40 公里左右时,身体已经有些疼痛难忍,这也太委屈自己了,把骑行玩成了上刑。

那天下午 5 点我就陷入了昏睡,醒来时已是第二天早上 5 点。


082430fa9bd31d41456ffcc82bd52e.jpg
d4124b66d8eaa3e22deb091107f183.jpg

第二天查了很多山地车的资料,一度冲动想买一辆适合自己尺寸的「称手爱车」。但我还在外租房,上下班又是开车通勤,感觉没有添置一辆山地车的必要。但骑行带来的感觉特别棒,我将来一定会入手一辆,等一个恰当的时机,but 不是现在。

租房这么多年,我沉淀下来的经验就是「如非必要,勿增实体」,这与编程中的哲学是相同的。无用的东西添置多了,就会变成累赘。

20年来,他们的过往故事都藏在这里

作者 大袋鼠
2020年10月10日 22:51

当你在百度上搜索「中国第一家博客网站是哪一个」,你会得到的答案是:博客中国(blogchina.com)。维基百科上描述博客中国成立于 2004 年,那一年,刘翔奥运夺冠、美国占领伊拉克、陈水扁遭到枪击、「震荡波」蠕虫病毒席卷全球。

然而今天文章的主角不是它。一定程度上讲,上了年纪的网民很难认同它是中国第一个出现的博客托管网站。博客,Blog 的中文音译,Web Log 的缩写,中文又译为「网络日记」。可以说,在中文互联网的蛮荒年代,提供网络日记功能的网站,都可称作博客网。在如今互联网容易被人忽略的犄角旮旯地带,还有一众「上古」的博客网在默默耕耘着。

漫游在互联网的边缘,你就有可能在犄角旮旯地带发现「追梦人日记网」这一日记网站。当你打开首页,一股「网页三剑客」设计的复古味道铺面而来。

20201010215418.png

追梦人日记网的特别之处在于:它建立于千禧之年,中国接入国际互联网后的第 6 年。同年,李彦宏在中关村创办百度公司,马化腾为了腾讯的生死存亡而焦头烂额,雷军刚拒绝掉马云的融资请求,张一鸣正在读高中。

从世纪伊始到如今,岁月的车轮已经滚动了 20 年,中文互联网一路从蛮荒走向鼎盛。这个名不见经传的日记网,未曾被商业和资本染指,仅凭着站长的初心和网络志愿者维护,还在持续地提供服务。没人知道它的版面重新设计过几次,更没人知道站长 20 年来换过几次服务器机房。事实证明,相比私人运营,商业运作并未高明到哪里去:多少商业化运作的站点,眼见高楼起,眼见宴宾客,眼见楼塌了。20 年来,多少站点被人遗忘与丢弃,多少站点走向正常或非正常死亡。
甚至因为日趋严格的网络审查,中文互联网出现了一定的数据断层,几大著名社区譬如贴吧、天涯、虎扑、博客大巴,都出现过大面积历史帖子消失的情况。流行多年的中文视频网站土豆网,曾融汇了无数的精华视频与音频创作,在被阿里巴巴收购后,数据也逐渐丢失殆尽。追梦人日记网却默默地保留了建站以来的所有数据,并且,如今你依旧可以正常地注册用户或发表日记。

网站最新一条日记发布于昨天(2020 年 10 月 9 日),昭示着日记网并非名存实亡。甚至它还记得每个会员的生日,将当天过生日的用户名刊登在「今日寿星榜」上。榜单按照当前的审美来瞧,table 布局制作相当「粗劣」,然在当年已是有心的体现。

20201010231749.png

你可以点开还在保持高频更新的几名用户主页,他们大都坚持了 10 年以上。随意翻开他们的历史日记,有曾经琐碎的生活牢骚,有世界政事的时局点评,有未曾发表的青年文学,还有青春期悸动少女的文艺情诗。20 年过去,青春期少女成为了两个孩子的母亲,热爱足球的大学生变成了市局领导,花甲之年的退休老头步入耄耋。用户们各自走出了不同的人生轨迹,但这些人的共同点在于:他们的过往故事都藏在这里。

在诸多保持更新的用户中,这里要单独提一位用户 ID 叫「老陆」。从个人资料上看,这名用户于 2001 年注册,坚持写日记已有 19 年余。

20201010235741.png

更引人注目的是,该用户生于 1936 年,即民国 24 年,这一年,鲁迅去世、张学良发动「西安事变」要求蒋介石联共抗日。注册日记网时,他 65 岁,网络日记写了近 20 年,现年已 84 岁。要知道,二十年来互联网变化沧海桑田,能够二十年如一日时刻惦记着这块自留地,犹如打理菜园一般坚持写作记录生活,属实不易。如果你想翻阅老爷子的日记本,可以点击上方的个人主页。(日记本界面需要注册账号并登录)

如此看来,日记网与用户是相互成就的:用户的坚持写作给了网站持续运营的动力,而网站的存续也慢慢地留下了这批最忠实的用户。

谨以此文章表达我对「追梦人日记网」和坚持写作的用户的敬意。

多线程中的「lost wake up 问题」

作者 大袋鼠
2020年3月27日 01:06

问:Java 多线程中 wait() 方法为什么要放在同步块中?
答:为了避免「lost wake up 问题」,即「无法唤醒问题」。

什么是「lost wake up 问题」

我对「lost wake up 问题」的通俗理解:线程 A 调用 wait() 方法进入阻塞状态,接下来没有其他线程去唤醒线程 A,或者其他线程唤醒时机不对(早于线程 A 的 wait() ),导致线程 A 永远阻塞下去。

有中文资料对这个问题作出过解释:Java中wait()方法为什么要放在同步块中?(lost wake-up 问题),文中举了生产者和消费者的例子,但我觉得此文的结论并未触达核心,需要对文中的例子和结论多做一下补充,理解起来会方便一点。

现在有一个生产者线程和消费者线程:
先定义一个 obj 对象,并将其 count 属性的初始值设置为 0:

Object obj = new Object();
obj.count = 0;

生产者伪代码:

obj.count++;
obj.notify();

消费者伪代码:

while(obj.count<=0)
    obj.wait();
obj.count--;

两个线程启动,消费者检查 obj.count 的值,发现 obj.count <= 0 条件成立,但这时由于 CPU 的调度,发生上下文切换,生产者开始工作,执行了 count+1obj.notify(),也就是发出通知,准备唤醒一个阻塞的线程。然后 CPU 调度到消费者,此时消费者开始执行 obj.wait(),线程进入阻塞。但生产者已经早在消费者阻塞前执行了唤醒动作,也就导致消费者永远无法醒来了。

1644918-20190619224558253-730645351.png

随便加个锁能解决「lost wake up 问题」吗

不能,举个例子。

定义一把锁:

Lock lock1 = new Lock();

生产者伪代码:

lock1.lock();
obj.count++;
obj.notify();
lock1.unlock();

消费者伪代码:

lock1.lock();
while(count<=0)
    obj.wait();
obj.count--;
lock1.unlock();

两个线程启动,obj.count 初始值为 0。假设消费者先竞争到锁,while 中的 obj.count<=0 条件满足,执行 obj.wait() 使线程进入阻塞状态,lock1 锁没有被释放,所以生产者拿不到锁,也就无法 obj.notify() 通知消费者醒来,消费者将永远阻塞下去。

Java 中什么锁才能解决「lost wake up 问题」

只有上述例子中的 obj 对象锁才能避免这个问题,也就是将 obj.wait()obj.notify() 放进 obj 对象锁的同步块中。如果锁的不是例子中的 obj 对象,Java 就会抛出 IllegalMonitorStateException 异常。

生产者伪代码:

synchronized (obj) {
    obj.count++;
    obj.notify();
}

消费者伪代码:

synchronized (obj) {
    while(count<=0)
       obj.wait();
    obj.count--;
}

Java 中对 wait() 方法的注释中提到:线程在调用 obj.wait() 前必须要拿到当前 obj 对象的监视器 monitor 对象,即 obj 的锁。只有这样,当执行到 obj.wait() 时,该线程才可以暂时让出 obj 的同步锁并停止对锁的竞争,让其他正在等待此锁的线程可以得到同步锁并运行。

在上述例子中,消费者执行到 obj.wait() 时,让出了 obj 锁,停止了对锁的竞争,进入阻塞状态,紧接着生产者竞争到 obj 锁,执行了 obj.notify() 方法,唤醒了消费者,使消费者线程从阻塞状态重新回到就绪状态。

这里要注意的是,obj.notify() 并不是让生产者马上释放锁,也不是让消费者马上得到锁,而是通知消费者线程可以重新去参与锁的竞争了。

❌
❌