這個(gè)Map你肯定不知道典勇,畢竟存在感確實(shí)太低了劫哼。

這是why哥的第 75 篇原創(chuàng)文章

image

從Dubbo的優(yōu)雅停機(jī)說(shuō)起

好吧,其實(shí)本文并不是講 Dubbo 的優(yōu)雅停機(jī)的割笙。

只是我在 Dubbo 停機(jī)方法 DubboShutdownHook 類(lèi)中权烧,看到了這樣的一段代碼:

image

很明顯眯亦,這個(gè)地方最關(guān)鍵的地方是紅框框起來(lái)的部分。

而這個(gè) addShutdownHook 其實(shí)是 JDK 的方法:

java.lang.Runtime#addShutdownHook

image

最終般码,把傳進(jìn)來(lái)的 hook 放到了 hooks 里面妻率。

你說(shuō) hooks 是這個(gè)什么玩意?

這個(gè) hooks 調(diào)用的是 put 方法板祝,里面放了一個(gè) key宫静,一個(gè) value。

盲猜也知道:這個(gè) hooks 肯定是一個(gè) Map券时。那么這么多 Map 具體是哪個(gè)呢孤里?

來(lái)看看答案:

image

說(shuō)真的,第一次看到這個(gè) IdentityHashMap 的時(shí)候橘洞,我都有點(diǎn)愣住了捌袜。

一時(shí)間居然想不起來(lái)這是個(gè)什么玩意了,只是覺(jué)得有點(diǎn)眼熟炸枣。

至于它是干啥的虏等,有啥特性,那就更是摸不清楚了适肠。

于是我去了解了一下霍衫,發(fā)現(xiàn)這玩意,有點(diǎn)意思迂猴。屬于學(xué)了基本沒(méi)啥卵用采盒,但如果你知道,偶爾會(huì)出奇制勝的東西闯传。

image

有啥不一樣

image

IdentityHashMap 也是 Map 家族中的一員亥鬓。只是他的存在感也太低了,很多人都不知道還有這么一個(gè)玩意息尺。

甚至感覺(jué)它是一個(gè)第三方包里面引進(jìn)的類(lèi)携兵,沒(méi)想到居然是一個(gè)親兒子。

說(shuō)到 Map 家族搂誉,大家最熟悉的也就是 HashMap 了徐紧。

那么這個(gè) IdentityHashMap 和 HashMap 有什么區(qū)別呢?

先上個(gè)代碼給大家看看:

image

先不說(shuō)后半部分輸出什么了炭懊。

前面的 hashMap 最終的輸出結(jié)果你肯定知道吧并级。

由于多次 new String("why") 出來(lái)的字符串對(duì)象的 hashCode 是一樣的。

所以侮腹,最終 hashMap 里面只會(huì)留下最后一個(gè)值嘲碧。

這個(gè)點(diǎn),之前的這《why哥悄悄的給你說(shuō)幾個(gè)HashCode的破事》篇文章中已經(jīng)講過(guò)了父阻。相信不需要我再次補(bǔ)充愈涩。

疑問(wèn)點(diǎn)是 identityHashMap 最終會(huì)輸出什么呢望抽?

來(lái),看看結(jié)果:

image

OMG履婉,什么鬼煤篙?identityHashMap 里面把三個(gè)值都存下來(lái)啦?這么神奇的嗎毁腿?怎么做到的辑奈?

先不去想它怎么實(shí)現(xiàn)的,我們就把它當(dāng)個(gè)黑盒使用狸棍。

那么它在給我們傳遞什么樣的信息身害?

我們可以存多個(gè)相同的 key 到 map 里面了。

比如這樣的:

image

我把前面的示例代碼的中的 String 換成 Person 對(duì)象草戈。

來(lái)塌鸯,你先告訴我,hashMap 里面放了幾個(gè)對(duì)象唐片?一個(gè)還是三個(gè)丙猬?

什么,一個(gè)费韭?

你出去茧球,你個(gè)假粉絲!你自己看看是幾個(gè):

image

之前的文章里面說(shuō)過(guò)了星持,hashMap 里面抢埋,如果我們要用對(duì)象當(dāng)做 key。我們應(yīng)該怎么辦督暂?

必揪垄!須!要逻翁! 重寫(xiě)對(duì)象的 hashCode 和 equals 方法饥努。

HashMap 才會(huì)是表現(xiàn)的和我們預(yù)期一樣。

所以八回,當(dāng)我們重寫(xiě)了對(duì)象的 hashCode 和 equals 方法后酷愧,運(yùn)行結(jié)果是這樣的:

image

這兩個(gè)容器的執(zhí)行結(jié)果,含義是不一樣的缠诅。

hashMap 只能看到 18 歲的 why溶浴。

identityHashMap 可以看到 16 到 18 歲的 why。

總之管引,你是否重寫(xiě)了對(duì)象的 hashCode 和 equals 方法士败,identityHashMap 都不關(guān)心。

那么 identityHashMap 是怎么實(shí)現(xiàn)這個(gè)效果的呢汉匙?

我們?nèi)ピ创a中尋找一下答案拱烁。

暢游源碼-PUT

在講源碼之前,我先把 identityHashMap 的存儲(chǔ)套路給你說(shuō)一下噩翠,你看源碼的時(shí)候就輕松多了戏自。

不管怎么它還是一個(gè) Map,那么必然就有對(duì)應(yīng)的 hash 方法伤锚。

對(duì)于 identityHashMap 而言擅笔,經(jīng)過(guò) hash 方法,計(jì)算出 key 的下標(biāo)為 2:

image

key 放好了屯援,然后 value 直接放到 i+1 的位置:

image

key 的下一個(gè)位置猛们,就是這個(gè) key 的 value 值。 這就是 identityHashMap 的存儲(chǔ)套路狞洋。它的數(shù)據(jù)結(jié)構(gòu)不是數(shù)組加鏈表弯淘,就完完全全是一個(gè)數(shù)組。?

記住這個(gè)套路吉懊,我們先從 put 方法的源碼入手:

java.util.IdentityHashMap#put

image

在標(biāo)號(hào)為 ① 的地方庐橙,就是 hash 方法,入?yún)⑹俏覀儌魅氲膶?duì)象和 table 的長(zhǎng)度借嗽。

table 是個(gè)什么玩意呢态鳖?

image

是一個(gè) Object 的數(shù)組。所以恶导,我們知道了 identityHashMap 的數(shù)據(jù)結(jié)構(gòu)它還是一個(gè)數(shù)組浆竭,而且看注釋?zhuān)哼@個(gè) table 的長(zhǎng)度必須是 2 的整數(shù)倍,也就是偶數(shù)惨寿。

那么數(shù)組的默認(rèn)長(zhǎng)度是多少呢:

image

是的邦泄,看起來(lái)是 32。

但是當(dāng)我對(duì)程序進(jìn)行調(diào)試的時(shí)候我發(fā)現(xiàn)缤沦,這個(gè) len 居然是 64:

image

可以看到這個(gè) table 數(shù)組里面什么東西都沒(méi)有虎韵,也就根本不存在觸發(fā)擴(kuò)容什么的。

為什么長(zhǎng)度是 64 呢缸废?說(shuō)好的 32 呢包蓝?

后來(lái)我在構(gòu)造方法中找到了答案:

image

臥槽,說(shuō)好的默認(rèn)容量 32企量,你初始化的時(shí)候直接翻倍了测萎?

這是什么行為?年輕人届巩,你這代碼硅瞧,不講武德啊恕汇!

image

但是你轉(zhuǎn)念一想腕唧。默認(rèn)容量 32 是指的 key 的?容量或辖。而一個(gè) key 對(duì)應(yīng)一個(gè) value。 key + value 總共不就是 64 的長(zhǎng)度嗎枣接?

好了颂暇,我們接著看 hash 方法的具體實(shí)現(xiàn):

image

hash 方法只有兩行。但是這兩行都非常的關(guān)鍵但惶。

先看第一個(gè) System.identityHashCode耳鸯,這個(gè)是什么東西?

看看 API 上的解釋?zhuān)?/p>

image

就是對(duì)于一個(gè)對(duì)象膀曾,不管你有沒(méi)有重寫(xiě) hashCode 方法县爬,該方法返回的值都是不會(huì)變化的。

看兩個(gè)示例代碼:

image

注意 Person 對(duì)象是沒(méi)有重寫(xiě) hashCode 方法的添谊。

程序的最終輸出結(jié)果是這樣的:

image

我們分成三個(gè)部分去看财喳,我們可以發(fā)現(xiàn)。

當(dāng)對(duì)象(Person)沒(méi)有重寫(xiě) hashCode 方法的時(shí)候斩狱,他們的 hashCode 和 identityHashCode 是一樣的纲缓。

即使對(duì)象(String)重寫(xiě)了 hashCode 方法,對(duì)于不同的對(duì)象喊废,hashCode 值是一樣的祝高,但是 identityHashCode 可能是不一樣的。

注意是“可能不一樣”污筷。因?yàn)?identityHashCode 的底層邏輯是基于一個(gè)偽隨機(jī)數(shù)生成的工闺。

這個(gè)特性特別有用,但是也別亂用瓣蛀。用錯(cuò)了陆蟆,就是一個(gè) bug。

比如在 identityHashMap 里面的使用就是一個(gè)正確的使用惋增。至于錯(cuò)誤的使用叠殷,我們稍后會(huì)講。

經(jīng)過(guò)前面的分析我們知道了:hash 方法中的第一行代碼诈皿,對(duì)于 new 出來(lái)的相同對(duì)象的不同實(shí)例林束,不管是否重寫(xiě) hashCode 方法,會(huì)產(chǎn)生不同的 identityHashCode稽亏。

可以說(shuō) System.identityHashCode 方法壶冒,是整個(gè) identityHashMap 的基石。

然后再看這一行代碼:

image

很多朋友第一眼看到位運(yùn)算截歉,心里就稍微有點(diǎn)抵觸胖腾。

別這樣,我?guī)惴治鲆幌拢芎?jiǎn)單的咸作。

首先锨阿,我前面畫(huà)圖示意了 identityHashMap 的存儲(chǔ)套路,說(shuō)了:key 的下一個(gè)位置就是這個(gè) key 的 value记罚。

那么 key 的位置一定要是一個(gè)偶數(shù)群井。

這一點(diǎn)能不能跟上?跟不上你就多想想再往下看毫胜。

image

而 hash 方法就是計(jì)算 key 的位置。

所以诬辈,該方法的返回值一定是一個(gè)偶數(shù)酵使。

這縝密的邏輯,是不是無(wú)懈可擊焙糟。

假設(shè) length 為 64 的話口渔,那么這一行代碼的目的是為了生成一個(gè) 0 到 63 之間的偶數(shù)。

0 到 63 之間的數(shù)穿撮,是 &(length-1) 保證的缺脉。這個(gè)沒(méi)啥說(shuō)的。

那么為什么一定會(huì)生成一個(gè)偶數(shù)呢悦穿?

h<<1 的最終結(jié)果肯定是一個(gè)偶數(shù)吧攻礼?

h<<8 的最終結(jié)果肯定也是一個(gè)偶數(shù)吧?

那么偶數(shù)減去偶數(shù)是一個(gè)什么數(shù)栗柒?

什么礁扮,你問(wèn)我會(huì)不會(huì)溢出?

你管它溢出不溢出瞬沦,就算它變成負(fù)數(shù)了太伊,變成 0 了,它也是一個(gè)偶數(shù)呀逛钻!

image

偶數(shù)的二進(jìn)制的最后一位是不是 0僚焦?

length-1 這個(gè)數(shù)的二進(jìn)制最后一位不是 0 就是 1,對(duì)不對(duì)曙痘?

0 & 上 0 或者 1芳悲,是不是還是 0?

那不就對(duì)了边坤。所以芭概,最終結(jié)果肯定是一個(gè)偶數(shù)的。

經(jīng)過(guò)前面的分析惩嘉,我們知道了標(biāo)號(hào)為 ① 的地方返回的 i 肯定是一個(gè) 0 到 len-1 之間的偶數(shù):

image

返回的這個(gè)偶數(shù) i罢洲,在標(biāo)號(hào)為 ② 和 ③ 的地方都有用到。

標(biāo)號(hào)為 ② 的地方是檢查傳進(jìn)來(lái)的這個(gè) key 是否在數(shù)組中已經(jīng)存在了,也就是我們說(shuō)的是否 hash 沖突惹苗。

如果沒(méi)沖突殿较,繼續(xù)往下執(zhí)行。

如果沖突了桩蓉,且 value 值存在淋纲,就替換 value 值,然后返回院究。

如果沖突了洽瞬,且 value 值不存在, i 值經(jīng)過(guò) nextKeyIndex 方法后也發(fā)生了變化业汰。

下標(biāo) i 是怎么變化的呢伙窃?

假設(shè)我們來(lái)了一個(gè) key=key2 的元素,經(jīng)過(guò) hash 計(jì)算后样漆,對(duì)應(yīng)數(shù)組下標(biāo)為 2为障,但是該位置上已經(jīng)有了一個(gè) key1 ,那么就是發(fā)生了 hash 沖突:

image

發(fā)生沖突放祟,i+2鳍怨,也就是找到下一個(gè)偶數(shù)下標(biāo)。

代碼中是這樣的體現(xiàn)的:

image

當(dāng) key2 的 identityHashCode 和 key1 一樣跪妥,發(fā)生 hash 沖突之后鞋喇,是這樣存儲(chǔ)的:

image

那勢(shì)必會(huì)出現(xiàn) i+2 的結(jié)果比 len 還長(zhǎng)的情況:

image

你發(fā)現(xiàn)源碼是怎么解決這個(gè)問(wèn)題的嗎?

這個(gè) nextkeyIndex 這個(gè)方法首尾相接眉撵,它是一個(gè)圓叭丰恪:

image

這種情況,這個(gè)圓执桌,畫(huà)圖是怎么體現(xiàn)的呢?

image

怎么樣鄙皇,是不是很騷。

執(zhí)行到編號(hào)為 ③ 的地方仰挣,就很清晰了:

key 是放在 tab[i] 的位置的伴逸。

value 是放在 tab[i+1] 的位置的。

image

和我們畫(huà)圖的邏輯一致膘壶。

暢游源碼-GET

接下來(lái)我們看看 get 方法:

image

標(biāo)號(hào)為 ① 的地方错蝴,直接取到了對(duì)應(yīng)的 key。

你注意這個(gè)地方颓芭,用的是 == 來(lái)判斷對(duì)象是否相等顷锰,hashMap 用的是 equals 。

標(biāo)號(hào)為 ② 的地方亡问,是沒(méi)有對(duì)應(yīng)的 key官紫,直接返回 null肛宋。

走到標(biāo)號(hào)為 ③ 的地方,代表這個(gè) key 發(fā)生過(guò) hash 沖突束世。那么接著找下一個(gè)偶數(shù)位下標(biāo)的 key酝陈。

比如我們這里的 key2:

image

整個(gè)過(guò)程還是非常清晰的。學(xué)習(xí)的時(shí)候可以和 hashMap 的 get 方法進(jìn)行對(duì)比學(xué)習(xí)毁涉。

你會(huì)發(fā)現(xiàn)沉帮,思想是一個(gè)思想,但是解決方案是完全不同的解決方案贫堰。

暢游源碼-REMOVE

接著再看最后一個(gè) remove 方法:

image

首先穆壕,標(biāo)號(hào)為 ① 的地方,你想到了什么東西其屏?

我看到這個(gè) modCount 可太親切了喇勋。圍繞著這個(gè)玩意,我前前后后大概寫(xiě)了有 3w 多字的文章吧:

image

是為了拋出 ConcurrentModificationException 服務(wù)的漫玄。

這里體現(xiàn)的是 fast-fail 的思想。

關(guān)于這個(gè)異常最經(jīng)典的一個(gè)面試題就是:ArrayList 如果一邊遍歷压彭,一邊刪除睦优,會(huì)出現(xiàn)什么情況?

什么壮不?你不會(huì)汗盘?我也不回答了。

假粉絲询一,請(qǐng)你回去等通知吧隐孽。

標(biāo)號(hào)為 ② 的地方,把 i 和 i+1 的位置都置為 null健蕊。也就是把 key 和對(duì)應(yīng)的 value 都置為 null菱阵。

執(zhí)行完標(biāo)號(hào)為 ② 的地方, remove 的操作也就完成了缩功。

那么按理來(lái)說(shuō)方法就應(yīng)該結(jié)束了晴及。對(duì)嗎?

image

你想一想我之前的這個(gè)圖片:

image

如果這個(gè)時(shí)候我要移除 key=key1 的鍵值對(duì)嫡锌,當(dāng)標(biāo)號(hào)為 ② 的地方執(zhí)行完成后虑稼,是這個(gè)樣子的:

image

發(fā)現(xiàn)問(wèn)題了嗎?

如果這個(gè)時(shí)候我來(lái)查詢(xún) key2,而 key2 經(jīng)過(guò) hash 方法后計(jì)算出來(lái)的 i 還是 2势木,而對(duì)應(yīng)位置上的值是 null:

image

這個(gè)時(shí)候你告訴我 key2 查不到蛛倦,返回一個(gè) null 給我?

key2啦桌,啪溯壶,沒(méi)了!

image

所以,標(biāo)號(hào)為 ③ 的地方就是為了解決這個(gè)問(wèn)題的茸塞。

java.util.IdentityHashMap#closeDeletion

image

你看這個(gè)方法標(biāo)號(hào)為 ① 的地方躲庄,自己都說(shuō)了:

朋友,因?yàn)槲覀冞@個(gè)結(jié)構(gòu)是一個(gè)圓钾虐,這個(gè)方法比較混亂噪窘。做好心理準(zhǔn)備。

然后就是一個(gè)異常復(fù)雜的 if 判斷效扫。

這個(gè)我是看懂了倔监,但是屬于只可意會(huì)不可言傳的那種,所以就不給大家分析了菌仁。大家有興趣的自己去看看浩习。

只要你抓準(zhǔn)了它的存儲(chǔ)機(jī)制和方法功能,理解起來(lái)應(yīng)該不算很費(fèi)勁济丘。

image

再看標(biāo)號(hào)為 ② 的地方谱秽,理解起來(lái)就很容易了,把之前由于 hash 沖突導(dǎo)致的位置偏移的數(shù)據(jù)摹迷,一個(gè)個(gè)的往前挪:

image

意思就是上面圖片的意思疟赊。

先把 key1 從 i=2 的位置移走。然后把 i=4 的 key2 往前移動(dòng) 2 位峡碉。

這樣近哟,下次來(lái)查詢(xún) key2 的時(shí)候,就能得到正確的返回了鲫寄。

這里留下一個(gè)疑問(wèn)吉执,假設(shè)下面這個(gè)場(chǎng)景:

image

key1 和 key2 是有 hash 沖突的,但是 key3 是正常的?地来。

那么移除掉 key1 之后的圖應(yīng)該是這樣的:

image

代碼是怎么控制或者說(shuō)怎么知道 key2 和 key1 是有沖突的戳玫,所以移走 key1 之后,需要把 key2 往前移動(dòng)未斑。而 key3 和 key2 是沒(méi)有關(guān)系的量九,所以 key3 放著不動(dòng)。

答案其實(shí)就藏在 closeDeletion 方法的源碼里面颂碧,就看你有沒(méi)有徹底理解這個(gè)方法了荠列。?

好了,到這里關(guān)于 identityHashMap 增刪改查我們就分享完畢了载城。

老規(guī)矩肌似,源碼導(dǎo)讀,點(diǎn)到為止诉瓦。

就像傳統(tǒng)功夫川队,都是點(diǎn)到為止力细。年輕人,不講武德固额,耗子尾汁...

image

馬老師可真是我最近一段時(shí)間的快樂(lè)源泉啊眠蚂。

咦,偏了偏了斗躏,說(shuō)編程呢逝慧,怎么說(shuō)到馬老師那邊去了。

難道我不經(jīng)意間發(fā)現(xiàn)了:萬(wàn)物皆可馬保國(guó)定律啄糙?

identityHashCode的錯(cuò)誤使用

前面說(shuō)了笛臣,IdentityHashMap 的核心點(diǎn)在于 System.identityHashCode 方法。

說(shuō)到這個(gè) identityHashCode 我又想到了曾經(jīng)在 Dubbo 中的看到的一段源碼隧饼。

位于一致性哈希負(fù)載均衡算法中:

org.apache.dubbo.rpc.cluster.loadbalance.ConsistentHashLoadBalance#doSelect

image

上面的源碼是 2.7.8 版本沈堡。

假設(shè)有五個(gè)可用的服務(wù)提供者,這里的 invokers 集合里面裝的就是一個(gè)個(gè)服務(wù)提供者燕雁。

然后調(diào)用了 invokers 诞丽,也就是 list 的 hashCode 方法。

因?yàn)橐恢滦怨5呢?fù)載均衡的思想就是當(dāng)服務(wù)發(fā)生了上下線之后拐格,我們需要對(duì)哈希環(huán)進(jìn)行調(diào)整僧免。

如果服務(wù)沒(méi)有發(fā)生上下線,那么是不需要進(jìn)行哈希環(huán)調(diào)整的禁荒。

具體到這個(gè) list 來(lái)說(shuō)就是:

當(dāng) list 里面的元素發(fā)生了變化猬膨,那么說(shuō)明有服務(wù)上下線的情況發(fā)生角撞。

至于你裝元素的 list 是否和原來(lái)的不一樣呛伴,那我是不關(guān)心的。

所以作者在這里還寫(xiě)了一個(gè)備注:我們應(yīng)該只注意 list 里面的元素就可以了谒所。

言外之意就是我剛剛說(shuō)的:裝元素的 list 是否發(fā)生了變化热康,我是不關(guān)心的。

按照開(kāi)源框架的尿性劣领,這地方專(zhuān)門(mén)寫(xiě)了一行注釋?zhuān)f(shuō)明這個(gè)地方曾經(jīng)是有問(wèn)題的姐军。

那我們看看這個(gè)地方的提交記錄:

image

果然,在 2019 年 12 月 11 日尖淘,有人提交了代碼奕锌。

提交的代碼如下:

image

你看,原來(lái)的代碼是 System.identityHashCode 方法村生。

后來(lái)修改為調(diào)用 list 的 hashCode 方法惊暴。

單單看著一行代碼,我們就知道趁桃,之前的代碼是關(guān)注 list 這個(gè)容器了辽话,導(dǎo)致了某些 bug 的出現(xiàn)肄鸽。

具體什么原因,我們可以看看這次提交對(duì)應(yīng)的 pr:

也就是編號(hào)為 5429 的 issue:

https://github.com/apache/dubbo/issues/5429

image

哎呀油啤,我去典徘,這誰(shuí)啊益咬?看著眼熟按濉?這不就是 why 哥嗎础废?這不是巧了嗎汛骂,這不是?

是的评腺,這個(gè) bug 就是我發(fā)現(xiàn)并提出的對(duì)應(yīng)的 issue帘瞭。

image

而且這個(gè) bug 其實(shí)是非常好發(fā)現(xiàn)的,只要你把環(huán)境一搭蒿讥,代碼一跑蝶念,場(chǎng)景一模擬。是個(gè)必現(xiàn)的問(wèn)題芋绸。

而產(chǎn)生這個(gè) bug 的原因媒殉,可謂是蝴蝶效應(yīng)。在離這段源碼很遠(yuǎn)的摔敛,毫不相干的一次需求中廷蓉,不知不覺(jué)的就影響到了這段代碼。

而且連開(kāi)發(fā)者自己都不知道马昙,自己的修改會(huì)影響到一致性哈希負(fù)載均衡算法桃犬。所以,根本也就談不上什么測(cè)試用例了行楞。

如果你想更進(jìn)一步了解這個(gè) bug 的來(lái)龍去脈攒暇。可以看看這篇文章:

《夠強(qiáng)子房!一行代碼就修復(fù)了我提的Dubbo的Bug》

如果你想更進(jìn)一步的了解 Dubbo 的負(fù)載均衡策略形用,那可以看看這篇文章:

《吐血輸出:2萬(wàn)字長(zhǎng)文帶你細(xì)細(xì)盤(pán)點(diǎn)五種負(fù)載均衡策略≈ず迹》

好了田度,那么這次的文章就到這里啦。給大家分享了一個(gè)冷門(mén)的解愤、"學(xué)了沒(méi)多大卵用" 的 IdentityHashMap镇饺。

你要是不喜歡下面的荒腔走板環(huán)節(jié)的話,也請(qǐng)記得拉到文章的最后琢歇。留言兰怠、點(diǎn)贊梦鉴、在看、轉(zhuǎn)發(fā)揭保、贊賞肥橙,隨便來(lái)一個(gè)就行。你要是都安排上秸侣,我也不介意存筏。

荒腔走板

最近項(xiàng)目組接到了一個(gè)工期特別緊張的項(xiàng)目。

所以剛剛過(guò)去的周末我加了兩天的班味榛。周六晚上把流程走通之后椭坚,已經(jīng)快是 22 點(diǎn)了。

之前預(yù)約了安裝家電的師傅搏色,剛好也是周六善茎。

所以只有女朋友一個(gè)人去家那邊,邊打掃衛(wèi)生频轿,邊等著安裝師傅垂涯。

安裝師傅全部弄好之后也是 19 點(diǎn)之后了。

因?yàn)槲覐墓镜郊姨貏e的近航邢。女朋友覺(jué)得我也差不多該下班了耕赘,于是決定就在家里等我,然后一起從家里回到租住的小區(qū)膳殷。

結(jié)果一等就是 2 個(gè)多小時(shí)操骡。

我下班之后,馬上打車(chē)到小區(qū)册招。

下午沒(méi)有吃飯河质,工作也比較勞累,坐在車(chē)上乐尊,一陣疲倦的感覺(jué)襲來(lái)扔嵌。

但是在小區(qū)門(mén)口刷門(mén)禁卡的時(shí)候胁勺,我一抬頭嵌洼,門(mén)口寫(xiě)著:歡迎回家麻养。

那一刻春贸,我突然覺(jué)得好暖啊,甚至還有一絲絲的感動(dòng)类垫。

走在小區(qū)的路上,感覺(jué)一切都是這么的可愛(ài)陪捷。

因?yàn)檫@個(gè)家,真的是屬于自己的家,用自己一手一腳掙出來(lái)的錢(qián)堆出來(lái)的。

此時(shí)此刻穴豫,家里還有一個(gè)人,開(kāi)著燈逼友,在等著我回家精肃。

之前我從來(lái)沒(méi)有這樣的感覺(jué)過(guò),這是一種非常神奇的感覺(jué)帜乞。

到家之后司抱,由于家具還沒(méi)有準(zhǔn)備好,我看到女朋友在地上鋪著一個(gè)泡沫墊子黎烈,坐在上面习柠,靠在墻上,通過(guò)手機(jī)看著綜藝照棋。

她起來(lái)抱了抱我资溃,說(shuō):你終于回來(lái)啦。今天的事可真是多烈炭。

我們一起站在空蕩蕩的客廳中間溶锭。

那一刻,家的含義符隙,家的感覺(jué)趴捅,從來(lái)沒(méi)有這么具體過(guò)。

最后說(shuō)一句(求關(guān)注)

才疏學(xué)淺膏执,難免會(huì)有紕漏驻售,如果你發(fā)現(xiàn)了錯(cuò)誤的地方露久,可以在留言區(qū)提出來(lái)更米,我對(duì)其加以修改。 感謝您的閱讀毫痕,我堅(jiān)持原創(chuàng)征峦,十分歡迎并感謝您的關(guān)注迟几。

我是 why,一個(gè)被代碼耽誤的文學(xué)創(chuàng)作者栏笆,不是大佬类腮,但是喜歡分享,是一個(gè)又暖又有料的四川好男人蛉加。

歡迎關(guān)注我呀蚜枢。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市针饥,隨后出現(xiàn)的幾起案子厂抽,更是在濱河造成了極大的恐慌,老刑警劉巖丁眼,帶你破解...
    沈念sama閱讀 211,348評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件筷凤,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡苞七,警方通過(guò)查閱死者的電腦和手機(jī)藐守,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蹂风,“玉大人卢厂,你說(shuō)我怎么就攤上這事』葑模” “怎么了足淆?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,936評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)礁阁。 經(jīng)常有香客問(wèn)我巧号,道長(zhǎng),這世上最難降的妖魔是什么姥闭? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,427評(píng)論 1 283
  • 正文 為了忘掉前任丹鸿,我火速辦了婚禮,結(jié)果婚禮上棚品,老公的妹妹穿的比我還像新娘靠欢。我一直安慰自己,他們只是感情好铜跑,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,467評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布门怪。 她就那樣靜靜地躺著,像睡著了一般锅纺。 火紅的嫁衣襯著肌膚如雪掷空。 梳的紋絲不亂的頭發(fā)上莱坎,一...
    開(kāi)封第一講書(shū)人閱讀 49,785評(píng)論 1 290
  • 那天杠纵,我揣著相機(jī)與錄音,去河邊找鬼。 笑死荧飞,一個(gè)胖子當(dāng)著我的面吹牛挫掏,可吹牛的內(nèi)容都是我干的弛秋。 我是一名探鬼主播踪区,決...
    沈念sama閱讀 38,931評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼赤炒!你這毒婦竟也來(lái)了氯析?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,696評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤莺褒,失蹤者是張志新(化名)和其女友劉穎魄鸦,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體癣朗,經(jīng)...
    沈念sama閱讀 44,141評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡拾因,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,483評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了旷余。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绢记。...
    茶點(diǎn)故事閱讀 38,625評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖正卧,靈堂內(nèi)的尸體忽然破棺而出蠢熄,到底是詐尸還是另有隱情,我是刑警寧澤炉旷,帶...
    沈念sama閱讀 34,291評(píng)論 4 329
  • 正文 年R本政府宣布签孔,位于F島的核電站,受9級(jí)特大地震影響窘行,放射性物質(zhì)發(fā)生泄漏饥追。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,892評(píng)論 3 312
  • 文/蒙蒙 一罐盔、第九天 我趴在偏房一處隱蔽的房頂上張望但绕。 院中可真熱鬧,春花似錦惶看、人聲如沸捏顺。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)幅骄。三九已至,卻和暖如春本今,著一層夾襖步出監(jiān)牢的瞬間拆座,已是汗流浹背主巍。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留懂拾,地道東北人煤禽。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓铐达,卻偏偏與公主長(zhǎng)得像岖赋,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子瓮孙,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,492評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容