徹底搞懂synchronized(從偏向鎖到重量級(jí)鎖)

接觸過(guò)線(xiàn)程安全的同學(xué)想必都使用過(guò)synchronized這個(gè)關(guān)鍵字于游,在java同步代碼快中耿焊,synchronized的使用方式無(wú)非有兩個(gè):

  1. 通過(guò)對(duì)一個(gè)對(duì)象進(jìn)行加鎖來(lái)實(shí)現(xiàn)同步,如下面代碼。
synchronized(lockObject){    //代碼 }
  1. 對(duì)一個(gè)方法進(jìn)行synchronized聲明储笑,進(jìn)而對(duì)一個(gè)方法進(jìn)行加鎖來(lái)實(shí)現(xiàn)同步。如下面代碼
public synchornized void test(){    //代碼}

但這里需要指出的是圆恤,無(wú)論是對(duì)一個(gè)對(duì)象進(jìn)行加鎖還是對(duì)一個(gè)方法進(jìn)行加鎖突倍,實(shí)際上,都是對(duì)對(duì)象進(jìn)行加鎖盆昙。

也就是說(shuō)羽历,對(duì)于方式2,實(shí)際上虛擬機(jī)會(huì)根據(jù)synchronized修飾的是實(shí)例方法還是類(lèi)方法淡喜,去取對(duì)應(yīng)的實(shí)例對(duì)象或者Class對(duì)象來(lái)進(jìn)行加鎖秕磷。

對(duì)于synchronized這個(gè)關(guān)鍵字,可能之前大家有聽(tīng)過(guò)炼团,他是一個(gè)重量級(jí)鎖澎嚣,開(kāi)銷(xiāo)很大,建議大家少用點(diǎn)瘟芝。但大家可能也聽(tīng)說(shuō)過(guò)易桃,但到了jdk1.6之后,該關(guān)鍵字被進(jìn)行了很多的優(yōu)化锌俱,已經(jīng)不像以前那樣不給力了晤郑,建議大家多使用。

那么它是進(jìn)行了什么樣的優(yōu)化,才使得synchronized又深得人心呢造寝?為何重量級(jí)鎖開(kāi)銷(xiāo)就大呢磕洪?

想必大家也都聽(tīng)說(shuō)過(guò)輕量級(jí)鎖,重量級(jí)鎖匹舞,自旋鎖褐鸥,自適應(yīng)自旋鎖,偏向鎖等等赐稽,他們都有哪些區(qū)別呢叫榕?
剛才和大家說(shuō),鎖是加在對(duì)象上的姊舵,那么一個(gè)線(xiàn)程是如何知道這個(gè)對(duì)象被加了鎖呢晰绎?又是如何知道它加的是什么類(lèi)型的鎖呢?

基于這些問(wèn)題括丁,下面我講一步一步講解synchronized是如何被優(yōu)化的荞下,是如何從偏向鎖到重量級(jí)鎖的。

鎖對(duì)象

剛才我們說(shuō)史飞,鎖實(shí)際上是加在對(duì)象上的尖昏,那么被加了鎖的對(duì)象我們稱(chēng)之為鎖對(duì)象,在java中构资,任何一個(gè)對(duì)象都能成為鎖對(duì)象抽诉。
為了讓大家更好著理解虛擬機(jī)是如何知道這個(gè)對(duì)象就是一個(gè)鎖對(duì)象的,我們下面簡(jiǎn)單介紹一下java中一個(gè)對(duì)象的結(jié)構(gòu)吐绵。
java對(duì)象在內(nèi)存中的存儲(chǔ)結(jié)構(gòu)主要有一下三個(gè)部分:

  1. 對(duì)象頭
  2. 實(shí)例數(shù)據(jù)
  3. 填充數(shù)據(jù)
    這里強(qiáng)調(diào)一下迹淌,對(duì)象頭里的數(shù)據(jù)主要是一些運(yùn)行時(shí)的數(shù)據(jù)。
    其簡(jiǎn)單的結(jié)構(gòu)如下
長(zhǎng)度 內(nèi)容 說(shuō)明
32/64bit Mark Work hashCode,GC分代年齡己单,鎖信息
32/64bit Class Metadata Address 指向?qū)ο箢?lèi)型數(shù)據(jù)的指針
32/64bit Array Length 數(shù)組的長(zhǎng)度(當(dāng)對(duì)象為數(shù)組時(shí))

從該表格中我們可以看到唉窃,對(duì)象中關(guān)于鎖的信息是存在Markword里的。
我們來(lái)看一段代碼

LockObject lockObject = new LockObject();//隨便創(chuàng)建一個(gè)對(duì)象synchronized(lockObject){    //代碼}

當(dāng)我們創(chuàng)建一個(gè)對(duì)象LockObject時(shí)纹笼,該對(duì)象的部分Markword關(guān)鍵數(shù)據(jù)如下纹份。

bit fields 是否偏向鎖 鎖標(biāo)志位
hash 0 01

從圖中可以看出,偏向鎖的標(biāo)志位是“01”廷痘,狀態(tài)是“0”矮嫉,表示該對(duì)象還沒(méi)有被加上偏向鎖。(“1”是表示被加上偏向鎖)牍疏。該對(duì)象被創(chuàng)建出來(lái)的那一刻蠢笋,就有了偏向鎖的標(biāo)志位,這也說(shuō)明了所有對(duì)象都是可偏向的鳞陨,但所有對(duì)象的狀態(tài)都為“0”昨寞,也同時(shí)說(shuō)明所有被創(chuàng)建的對(duì)象的偏向鎖并沒(méi)有生效瞻惋。

偏向鎖

不過(guò),當(dāng)線(xiàn)程執(zhí)行到臨界區(qū)(critical section)時(shí)援岩,此時(shí)會(huì)利用CAS(Compare and Swap)操作歼狼,將線(xiàn)程ID插入到Markword中,同時(shí)修改偏向鎖的標(biāo)志位享怀。

所謂臨界區(qū)羽峰,就是只允許一個(gè)線(xiàn)程進(jìn)去執(zhí)行操作的區(qū)域,即同步代碼塊添瓷。CAS是一個(gè)原子性操作

此時(shí)的Mark word的結(jié)構(gòu)信息如下:

bit fields 是否偏向鎖 鎖標(biāo)志位
threadId epoch 1 01

此時(shí)偏向鎖的狀態(tài)為“1”梅屉,說(shuō)明對(duì)象的偏向鎖生效了,同時(shí)也可以看到鳞贷,哪個(gè)線(xiàn)程獲得了該對(duì)象的鎖坯汤。

那么,什么是偏向鎖?

偏向鎖是jdk1.6引入的一項(xiàng)鎖優(yōu)化搀愧,其中的“偏”是偏心的偏惰聂。它的意思就是說(shuō),這個(gè)鎖會(huì)偏向于第一個(gè)獲得它的線(xiàn)程咱筛,在接下來(lái)的執(zhí)行過(guò)程中搓幌,假如該鎖沒(méi)有被其他線(xiàn)程所獲取,沒(méi)有其他線(xiàn)程來(lái)競(jìng)爭(zhēng)該鎖迅箩,那么持有偏向鎖的線(xiàn)程將永遠(yuǎn)不需要進(jìn)行同步操作溉愁。
也就是說(shuō):
在此線(xiàn)程之后的執(zhí)行過(guò)程中,如果再次進(jìn)入或者退出同一段同步塊代碼沙热,并不再需要去進(jìn)行加鎖或者解鎖操作,而是會(huì)做以下的步驟:

  1. Load-and-test罢缸,也就是簡(jiǎn)單判斷一下當(dāng)前線(xiàn)程id是否與Markword當(dāng)中的線(xiàn)程id是否一致.
  2. 如果一致篙贸,則說(shuō)明此線(xiàn)程已經(jīng)成功獲得了鎖,繼續(xù)執(zhí)行下面的代碼.
  3. 如果不一致枫疆,則要檢查一下對(duì)象是否還是可偏向爵川,即“是否偏向鎖”標(biāo)志位的值。
  4. 如果還未偏向息楔,則利用CAS操作來(lái)競(jìng)爭(zhēng)鎖寝贡,也即是第一次獲取鎖時(shí)的操作。

如果此對(duì)象已經(jīng)偏向了值依,并且不是偏向自己圃泡,則說(shuō)明存在了競(jìng)爭(zhēng)。此時(shí)可能就要根據(jù)另外線(xiàn)程的情況愿险,可能是重新偏向颇蜡,也有可能是做偏向撤銷(xiāo),但大部分情況下就是升級(jí)成輕量級(jí)鎖了。
可以看出风秤,偏向鎖是針對(duì)于一個(gè)線(xiàn)程而言的鳖目,線(xiàn)程獲得鎖之后就不會(huì)再有解鎖等操作了,這樣可以省略很多開(kāi)銷(xiāo)缤弦。假如有兩個(gè)線(xiàn)程來(lái)競(jìng)爭(zhēng)該鎖話(huà)领迈,那么偏向鎖就失效了,進(jìn)而升級(jí)成輕量級(jí)鎖了碍沐。
為什么要這樣做呢狸捅?因?yàn)榻?jīng)驗(yàn)表明,其實(shí)大部分情況下抢韭,都會(huì)是同一個(gè)線(xiàn)程進(jìn)入同一塊同步代碼塊的薪贫。這也是為什么會(huì)有偏向鎖出現(xiàn)的原因。
在Jdk1.6中刻恭,偏向鎖的開(kāi)關(guān)是默認(rèn)開(kāi)啟的瞧省,適用于只有一個(gè)線(xiàn)程訪(fǎng)問(wèn)同步塊的場(chǎng)景。

鎖膨脹

剛才說(shuō)了鳍贾,當(dāng)出現(xiàn)有兩個(gè)線(xiàn)程來(lái)競(jìng)爭(zhēng)鎖的話(huà)鞍匾,那么偏向鎖就失效了,此時(shí)鎖就會(huì)膨脹骑科,升級(jí)為輕量級(jí)鎖橡淑。這也是我們經(jīng)常所說(shuō)的鎖膨脹

鎖撤銷(xiāo)

由于偏向鎖失效了,那么接下來(lái)就得把該鎖撤銷(xiāo)咆爽,鎖撤銷(xiāo)的開(kāi)銷(xiāo)花費(fèi)還是挺大的梁棠,其大概的過(guò)程如下:

  1. 在一個(gè)安全點(diǎn)停止擁有鎖的線(xiàn)程。
  2. 遍歷線(xiàn)程棧斗埂,如果存在鎖記錄的話(huà)符糊,需要修復(fù)鎖記錄和Markword,使其變成無(wú)鎖狀態(tài)呛凶。
  3. 喚醒當(dāng)前線(xiàn)程男娄,將當(dāng)前鎖升級(jí)成輕量級(jí)鎖。
    所以漾稀,如果某些同步代碼塊大多數(shù)情況下都是有兩個(gè)及以上的線(xiàn)程競(jìng)爭(zhēng)的話(huà)模闲,那么偏向鎖就會(huì)是一種累贅,對(duì)于這種情況崭捍,我們可以一開(kāi)始就把偏向鎖這個(gè)默認(rèn)功能給關(guān)閉

輕量級(jí)鎖

鎖撤銷(xiāo)升級(jí)為輕量級(jí)鎖之后尸折,那么對(duì)象的Markword也會(huì)進(jìn)行相應(yīng)的的變化。下面先簡(jiǎn)單描述下鎖撤銷(xiāo)之后殷蛇,升級(jí)為輕量級(jí)鎖的過(guò)程:

  1. 線(xiàn)程在自己的棧楨中創(chuàng)建鎖記錄 LockRecord翁授。
  2. 將鎖對(duì)象的對(duì)象頭中的MarkWord復(fù)制到線(xiàn)程的剛剛創(chuàng)建的鎖記錄中拣播。
  3. 將鎖記錄中的Owner指針指向鎖對(duì)象。
  4. 將鎖對(duì)象的對(duì)象頭的MarkWord替換為指向鎖記錄的指針收擦。

對(duì)應(yīng)的圖描述如下(圖來(lái)自周志明深入java虛擬機(jī))


圖片1
圖片2

之后Markwork如下:

bit fields 鎖標(biāo)志位
指向LockRecord的指針 00

注:鎖標(biāo)志位”00”表示輕量級(jí)鎖
輕量級(jí)鎖主要有兩種

  1. 自旋鎖
  2. 自適應(yīng)自旋鎖

自旋鎖

所謂自旋贮配,就是指當(dāng)有另外一個(gè)線(xiàn)程來(lái)競(jìng)爭(zhēng)鎖時(shí),這個(gè)線(xiàn)程會(huì)在原地循環(huán)等待塞赂,而不是把該線(xiàn)程給阻塞泪勒,直到那個(gè)獲得鎖的線(xiàn)程釋放鎖之后,這個(gè)線(xiàn)程就可以馬上獲得鎖的宴猾。
注意圆存,鎖在原地循環(huán)的時(shí)候,是會(huì)消耗cpu的仇哆,就相當(dāng)于在執(zhí)行一個(gè)啥也沒(méi)有的for循環(huán)沦辙。
所以,輕量級(jí)鎖適用于那些同步代碼塊執(zhí)行的很快的場(chǎng)景讹剔,這樣油讯,線(xiàn)程原地等待很短很短的時(shí)間就能夠獲得鎖了。
經(jīng)驗(yàn)表明延欠,大部分同步代碼塊執(zhí)行的時(shí)間都是很短很短的陌兑,也正是基于這個(gè)原因,才有了輕量級(jí)鎖這么個(gè)東西由捎。

自旋鎖的一些問(wèn)題

  1. 如果同步代碼塊執(zhí)行的很慢兔综,需要消耗大量的時(shí)間,那么這個(gè)時(shí)侯狞玛,其他線(xiàn)程在原地等待空消耗cpu软驰,這會(huì)讓人很難受。
  2. 本來(lái)一個(gè)線(xiàn)程把鎖釋放之后心肪,當(dāng)前線(xiàn)程是能夠獲得鎖的锭亏,但是假如這個(gè)時(shí)候有好幾個(gè)線(xiàn)程都在競(jìng)爭(zhēng)這個(gè)鎖的話(huà),那么有可能當(dāng)前線(xiàn)程會(huì)獲取不到鎖蒙畴,還得原地等待繼續(xù)空循環(huán)消耗cup贰镣,甚至有可能一直獲取不到鎖呜象。

基于這個(gè)問(wèn)題膳凝,我們必須給線(xiàn)程空循環(huán)設(shè)置一個(gè)次數(shù),當(dāng)線(xiàn)程超過(guò)了這個(gè)次數(shù)恭陡,我們就認(rèn)為蹬音,繼續(xù)使用自旋鎖就不適合了,此時(shí)鎖會(huì)再次膨脹休玩,升級(jí)為重量級(jí)鎖著淆。
默認(rèn)情況下劫狠,自旋的次數(shù)為10次,用戶(hù)可以通過(guò)-XX:PreBlockSpin來(lái)進(jìn)行更改永部。

自旋鎖是在JDK1.4.2的時(shí)候引入的

自適應(yīng)自旋鎖

所謂自適應(yīng)自旋鎖就是線(xiàn)程空循環(huán)等待的自旋次數(shù)并非是固定的独泞,而是會(huì)動(dòng)態(tài)著根據(jù)實(shí)際情況來(lái)改變自旋等待的次數(shù)。
其大概原理是這樣的:
假如一個(gè)線(xiàn)程1剛剛成功獲得一個(gè)鎖苔埋,當(dāng)它把鎖釋放了之后懦砂,線(xiàn)程2獲得該鎖,并且線(xiàn)程2在運(yùn)行的過(guò)程中组橄,此時(shí)線(xiàn)程1又想來(lái)獲得該鎖了荞膘,但線(xiàn)程2還沒(méi)有釋放該鎖,所以線(xiàn)程1只能自旋等待玉工,但是虛擬機(jī)認(rèn)為羽资,由于線(xiàn)程1剛剛獲得過(guò)該鎖,那么虛擬機(jī)覺(jué)得線(xiàn)程1這次自旋也是很有可能能夠再次成功獲得該鎖的遵班,所以會(huì)延長(zhǎng)線(xiàn)程1自旋的次數(shù)屠升。
另外,如果對(duì)于某一個(gè)鎖费奸,一個(gè)線(xiàn)程自旋之后弥激,很少成功獲得該鎖,那么以后這個(gè)線(xiàn)程要獲取該鎖時(shí)愿阐,是有可能直接忽略掉自旋過(guò)程微服,直接升級(jí)為重量級(jí)鎖的,以免空循環(huán)等待浪費(fèi)資源缨历。

輕量級(jí)鎖也被稱(chēng)為非阻塞同步以蕴、樂(lè)觀(guān)鎖,因?yàn)檫@個(gè)過(guò)程并沒(méi)有把線(xiàn)程阻塞掛起辛孵,而是讓線(xiàn)程空循環(huán)等待丛肮,串行執(zhí)行。

重量級(jí)鎖

輕量級(jí)鎖膨脹之后魄缚,就升級(jí)為重量級(jí)鎖了宝与。重量級(jí)鎖是依賴(lài)對(duì)象內(nèi)部的monitor鎖來(lái)實(shí)現(xiàn)的,而monitor又依賴(lài)操作系統(tǒng)的MutexLock(互斥鎖)來(lái)實(shí)現(xiàn)的冶匹,所以重量級(jí)鎖也被成為互斥鎖习劫。
當(dāng)輕量級(jí)所經(jīng)過(guò)鎖撤銷(xiāo)等步驟升級(jí)為重量級(jí)鎖之后,它的Markword部分?jǐn)?shù)據(jù)大體如下

bit fields 鎖標(biāo)志位
指向Mutex的指針 10

為什么說(shuō)重量級(jí)鎖開(kāi)銷(xiāo)大呢

主要是嚼隘,當(dāng)系統(tǒng)檢查到鎖是重量級(jí)鎖之后诽里,會(huì)把等待想要獲得鎖的線(xiàn)程進(jìn)行阻塞,被阻塞的線(xiàn)程不會(huì)消耗cup飞蛹。但是阻塞或者喚醒一個(gè)線(xiàn)程時(shí)谤狡,都需要操作系統(tǒng)來(lái)幫忙灸眼,這就需要從用戶(hù)態(tài)轉(zhuǎn)換到內(nèi)核態(tài),而轉(zhuǎn)換狀態(tài)是需要消耗很多時(shí)間的墓懂,有可能比用戶(hù)執(zhí)行代碼的時(shí)間還要長(zhǎng)焰宣。
這就是說(shuō)為什么重量級(jí)線(xiàn)程開(kāi)銷(xiāo)很大的。

互斥鎖(重量級(jí)鎖)也稱(chēng)為阻塞同步捕仔、悲觀(guān)鎖

總結(jié)

通過(guò)上面的分析宛徊,我們知道了為什么synchronized關(guān)鍵字為何又深得人心,也知道了鎖的演變過(guò)程逻澳。
也就是說(shuō)闸天,synchronized關(guān)鍵字并非一開(kāi)始就該對(duì)象加上重量級(jí)鎖,也是從偏向鎖斜做,輕量級(jí)鎖苞氮,再到重量級(jí)鎖的過(guò)程。
這個(gè)過(guò)程也告訴我們瓤逼,假如我們一開(kāi)始就知道某個(gè)同步代碼塊的競(jìng)爭(zhēng)很激烈笼吟、很慢的話(huà),那么我們一開(kāi)始就應(yīng)該使用重量級(jí)鎖了霸旗,從而省掉一些鎖轉(zhuǎn)換的開(kāi)銷(xiāo)贷帮。
講到這里就大概完了,希望能對(duì)你有所幫助

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末诱告,一起剝皮案震驚了整個(gè)濱河市撵枢,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌精居,老刑警劉巖锄禽,帶你破解...
    沈念sama閱讀 223,126評(píng)論 6 520
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異靴姿,居然都是意外死亡沃但,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,421評(píng)論 3 400
  • 文/潘曉璐 我一進(jìn)店門(mén)佛吓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)宵晚,“玉大人,你說(shuō)我怎么就攤上這事维雇∮偃校” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,941評(píng)論 0 366
  • 文/不壞的土叔 我叫張陵谆沃,是天一觀(guān)的道長(zhǎng)钝凶。 經(jīng)常有香客問(wèn)我仪芒,道長(zhǎng)唁影,這世上最難降的妖魔是什么耕陷? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,294評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮据沈,結(jié)果婚禮上哟沫,老公的妹妹穿的比我還像新娘。我一直安慰自己锌介,他們只是感情好嗜诀,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,295評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著孔祸,像睡著了一般隆敢。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上崔慧,一...
    開(kāi)封第一講書(shū)人閱讀 52,874評(píng)論 1 314
  • 那天拂蝎,我揣著相機(jī)與錄音,去河邊找鬼惶室。 笑死温自,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的皇钞。 我是一名探鬼主播悼泌,決...
    沈念sama閱讀 41,285評(píng)論 3 424
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼夹界!你這毒婦竟也來(lái)了馆里?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 40,249評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤可柿,失蹤者是張志新(化名)和其女友劉穎也拜,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體趾痘,經(jīng)...
    沈念sama閱讀 46,760評(píng)論 1 321
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡慢哈,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,840評(píng)論 3 343
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了永票。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片卵贱。...
    茶點(diǎn)故事閱讀 40,973評(píng)論 1 354
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖侣集,靈堂內(nèi)的尸體忽然破棺而出键俱,到底是詐尸還是另有隱情,我是刑警寧澤世分,帶...
    沈念sama閱讀 36,631評(píng)論 5 351
  • 正文 年R本政府宣布编振,位于F島的核電站,受9級(jí)特大地震影響臭埋,放射性物質(zhì)發(fā)生泄漏踪央。R本人自食惡果不足惜臀玄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,315評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望畅蹂。 院中可真熱鬧健无,春花似錦、人聲如沸液斜。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,797評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)少漆。三九已至臼膏,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間示损,已是汗流浹背讶请。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,926評(píng)論 1 275
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留屎媳,地道東北人夺溢。 一個(gè)月前我還...
    沈念sama閱讀 49,431評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像烛谊,于是被迫代替她去往敵國(guó)和親风响。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,982評(píng)論 2 361

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