我會(huì)手動(dòng)創(chuàng)建線程臭笆,為什么讓我使用線程池?

| 好看請(qǐng)贊,養(yǎng)成習(xí)慣

  • 你有一個(gè)思想愁铺,我有一個(gè)思想鹰霍,我們交換后,一個(gè)人就有兩個(gè)思想

  • If you can NOT explain it simply, you do NOT understand it well enough

現(xiàn)陸續(xù)將Demo代碼和技術(shù)文章整理在一起 Github實(shí)踐精選 茵乱,方便大家閱讀查看茂洒,本文同樣收錄在此,覺(jué)得不錯(cuò)似将,還請(qǐng)Star??

上一篇文章 面試問(wèn)我获黔,創(chuàng)建多少個(gè)線程合適蚀苛?我該怎么說(shuō) 從定性到定量的分析了如何創(chuàng)建正確個(gè)數(shù)的線程來(lái)最大化利用系統(tǒng)資源(其實(shí)就是幾道小學(xué)數(shù)學(xué)題)在验。通常來(lái)講,有了個(gè)這個(gè)知識(shí)點(diǎn)傍身堵未,按需手動(dòng)創(chuàng)建相應(yīng)個(gè)數(shù)的線程就好

但是現(xiàn)實(shí)中腋舌,你也許聽(tīng)過(guò)或者被要求:

盡量避免手動(dòng)創(chuàng)建線程,應(yīng)使用線程池統(tǒng)一管理線程

為什么會(huì)有這樣的要求渗蟹?背后的道理又是怎樣的呢块饺?順著這個(gè)經(jīng)驗(yàn)理論來(lái)推斷,那肯定是手動(dòng)創(chuàng)建線程有缺點(diǎn)

手動(dòng)創(chuàng)建線程有什么缺點(diǎn)雌芽?

  1. 不受控風(fēng)險(xiǎn)
  2. 頻繁創(chuàng)建開(kāi)銷大

不受控風(fēng)險(xiǎn)

這個(gè)缺點(diǎn)授艰,相信你也可以說(shuō)出一二

系統(tǒng)資源有限,每個(gè)人針對(duì)不同業(yè)務(wù)都可以手動(dòng)創(chuàng)建線程世落,并且創(chuàng)建標(biāo)準(zhǔn)不一樣(比如線程沒(méi)有名字)淮腾。當(dāng)系統(tǒng)運(yùn)行起來(lái),所有線程都在瘋狂搶占資源屉佳,無(wú)組織無(wú)紀(jì)律谷朝,混亂場(chǎng)面可想而知(出現(xiàn)問(wèn)題,自然也就不可能輕易的發(fā)現(xiàn)和解決)

如果有位神奇的小伙伴武花,為每個(gè)請(qǐng)求都創(chuàng)建一個(gè)線程圆凰,當(dāng)大量請(qǐng)求鋪面而來(lái)的時(shí)候,這好比一個(gè)正規(guī)木馬程序体箕,內(nèi)存被無(wú)情榨干耗盡(你無(wú)情专钉,你冷酷,你無(wú)理取鬧)

另外累铅,過(guò)多的線程自然也會(huì)引起上下文切換的開(kāi)銷

總的來(lái)說(shuō)驶沼,不受控風(fēng)險(xiǎn)很大

頻繁創(chuàng)建開(kāi)銷大

面試問(wèn):頻繁手動(dòng)創(chuàng)建線程有什么問(wèn)題?

答:開(kāi)銷大

這貌似是一個(gè)不假思索就可以回答出來(lái)的正確答案争群。那我要繼續(xù)問(wèn)了

面試官:創(chuàng)建一個(gè)線程干了什么就開(kāi)銷大了回怜?和我們創(chuàng)建一個(gè)普通 Java 對(duì)象有什么差別?

答: ... 嗯...啊

按照常規(guī)理解 new Thread() 創(chuàng)建一個(gè)線程和 new Object() 沒(méi)有什么差別。Java中萬(wàn)物接對(duì)象玉雾,因?yàn)?Thread 的老祖宗也是 Object

如果你真是這么理解的翔试,說(shuō)明你對(duì)線程的生命周期還不是很理解,請(qǐng)回看之前的 Java線程生命周期這樣理解挺簡(jiǎn)單的

在這篇文章中我們明確說(shuō)明复旬,new Thread() 在操作系統(tǒng)層面并沒(méi)有創(chuàng)建新的線程垦缅,這是編程語(yǔ)言特有的。真正轉(zhuǎn)換為操作系統(tǒng)層面創(chuàng)建一個(gè)線程驹碍,還要調(diào)用操作系統(tǒng)內(nèi)核的API壁涎,然后操作系統(tǒng)要為該線程分配一系列的資源

廢話不多說(shuō),我們將二者做個(gè)對(duì)比:

new Object() 過(guò)程

Object obj = new Object();

當(dāng)我需要【對(duì)象】時(shí)志秃,我就會(huì)給自己 new 一個(gè)(不知你是否和我一樣)怔球,這個(gè)過(guò)程你應(yīng)該很熟悉了:

  1. 分配一塊內(nèi)存 M
  2. 在內(nèi)存 M 上初始化該對(duì)象
  3. 將內(nèi)存 M 的地址賦值給引用變量 obj

就是這么簡(jiǎn)單

創(chuàng)建一個(gè)線程的過(guò)程

上面已經(jīng)提到了,創(chuàng)建一個(gè)線程還要調(diào)用操作系統(tǒng)內(nèi)核API浮还。為了更好的理解創(chuàng)建并啟動(dòng)一個(gè)線程的開(kāi)銷竟坛,我們需要看看 JVM 在背后幫我們做了哪些事情:

  1. 它為一個(gè)線程棧分配內(nèi)存,該棧為每個(gè)線程方法調(diào)用保存一個(gè)棧幀
  2. 每一棧幀由一個(gè)局部變量數(shù)組钧舌、返回值担汤、操作數(shù)堆棧和常量池組成
  3. 一些支持本機(jī)方法的 jvm 也會(huì)分配一個(gè)本機(jī)堆棧
  4. 每個(gè)線程獲得一個(gè)程序計(jì)數(shù)器,告訴它當(dāng)前處理器執(zhí)行的指令是什么
  5. 系統(tǒng)創(chuàng)建一個(gè)與Java線程對(duì)應(yīng)的本機(jī)線程
  6. 將與線程相關(guān)的描述符添加到JVM內(nèi)部數(shù)據(jù)結(jié)構(gòu)中
  7. 線程共享堆和方法區(qū)域

這段描述稍稍有點(diǎn)抽象洼冻,用數(shù)據(jù)來(lái)說(shuō)明創(chuàng)建一個(gè)線程(即便不干什么)需要多大空間呢崭歧?答案是大約 1M 左右

java -XX:+UnlockDiagnosticVMOptions -XX:NativeMemoryTracking=summary -XX:+PrintNMTStatistics -version

上圖是我用 Java8 的測(cè)試結(jié)果,19個(gè)線程撞牢,預(yù)留和提交的大概都是19000+KB率碾,平均每個(gè)線程大概需要 1M 左右的大小(Java11的結(jié)果完全不同普泡,這個(gè)大家自行測(cè)試吧)

相信到這里你已經(jīng)明白了播掷,對(duì)于性能要求嚴(yán)苛的現(xiàn)在,頻繁手動(dòng)創(chuàng)建/銷毀線程的代價(jià)是非常巨大的撼班,解決方案自然也是你知道的線程池了

什么是線程池歧匈?

你常見(jiàn)的數(shù)據(jù)庫(kù)連接池,實(shí)例池砰嘁,還有XX池件炉,OO池,各種池矮湘,都是一種池化(pooling)思想斟冕,簡(jiǎn)而言之就是為了最大化收益,并最小化風(fēng)險(xiǎn)缅阳,將資源統(tǒng)一在一起管理的思想

Java 也提供了它自己實(shí)現(xiàn)的線程池模型—— ThreadPoolExecutor磕蛇。套用上面池化的想象來(lái)說(shuō),Java線程池就是為了最大化高并發(fā)帶來(lái)的性能提升,并最小化手動(dòng)創(chuàng)建線程的風(fēng)險(xiǎn)秀撇,將多個(gè)線程統(tǒng)一在一起管理的思想

為了了解這個(gè)管理思想超棺,我們當(dāng)前只需要關(guān)注 ThreadPoolExecutor 構(gòu)造方法就可以了

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
}

這么復(fù)雜的構(gòu)造方法在JDK中還真是不多見(jiàn),為了個(gè)更形象化的讓大家理解這幾個(gè)核心參數(shù)呵燕,我們以多數(shù)人都經(jīng)歷過(guò)的春運(yùn)(北京——上海)來(lái)說(shuō)明

序號(hào) 參數(shù)名稱 參數(shù)解釋 春運(yùn)形象說(shuō)明
1 corePoolSize 表示常駐核心線程數(shù)棠绘,如果大于0,即使本地任務(wù)執(zhí)行完也不會(huì)被銷毀 日常固定的列車數(shù)輛(不管是不是春運(yùn)再扭,都要有固定這些車次運(yùn)行)
2 maximumPoolSize 表示線程池能夠容納可同時(shí)執(zhí)行的最大線程數(shù) 春運(yùn)客流量大氧苍,臨時(shí)加車,加車后泛范,總列車次數(shù)不能超過(guò)這個(gè)最大值让虐,否則就會(huì)出現(xiàn)調(diào)度不開(kāi)等問(wèn)題 (結(jié)合workqueue)
3 keepAliveTime 表示線程池中線程空閑的時(shí)間,當(dāng)空閑時(shí)間達(dá)到該值時(shí)敦跌,線程會(huì)被銷毀澄干,只剩下 corePoolSize 個(gè)線程位置 春運(yùn)壓力過(guò)后逛揩,臨時(shí)的加車(如果空閑時(shí)間超過(guò)keepAliveTime)就會(huì)被撤掉柠傍,只保留日常固定的列車車次數(shù)量用于日常運(yùn)營(yíng)
4 unit keepAliveTime 的時(shí)間單位,最終都會(huì)轉(zhuǎn)換成【納秒】辩稽,因?yàn)镃PU的執(zhí)行速度杠杠滴 keepAliveTime 的單位惧笛,春運(yùn)以【天】為計(jì)算單位
5 workQueue 當(dāng)請(qǐng)求的線程數(shù)大于 corePoolSize 時(shí),線程進(jìn)入該阻塞隊(duì)列 春運(yùn)壓力異常大逞泄,(達(dá)到corePoolSize)也不能滿足要求患整,所有乘坐請(qǐng)求都會(huì)進(jìn)入該阻塞隊(duì)列中排隊(duì), 隊(duì)列滿,還有額外請(qǐng)求喷众,就需要加車了
6 threadFactory 顧名思義各谚,線程工廠,用來(lái)生產(chǎn)一組相同任務(wù)的線程到千,同時(shí)也可以通過(guò)它增加前綴名昌渤,虛擬機(jī)棧分析時(shí)更清晰 比如(北京——上海)就屬于該段列車所有前綴,表明列車運(yùn)輸職責(zé)
7 handler 執(zhí)行拒絕策略憔四,當(dāng) workQueue 達(dá)到上限膀息,同時(shí)也達(dá)到 maximumPoolSize 就要通過(guò)這個(gè)來(lái)處理,比如拒絕了赵,丟棄等潜支,這是一種限流的保護(hù)措施 當(dāng)workQueue排隊(duì)也達(dá)到隊(duì)列最大上線,maximumPoolSize 就要提示無(wú)票等拒絕策略了,因?yàn)槲覀儾荒芗榆嚵耸裂矗?dāng)前所有車次已經(jīng)滿負(fù)載

整體來(lái)看就是這樣:

<fancybox>
</fancybox>

試想冗酿,如果有請(qǐng)求就新建一趟列車,請(qǐng)求結(jié)束就“銷毀”這趟列車,頻繁往復(fù)這樣操作裁替,這樣的代價(jià)肯定是不能接受的鸠窗。

可以看到,使用線程池不但能完成手動(dòng)創(chuàng)建線程可以做到的工作胯究,同時(shí)也填補(bǔ)了手動(dòng)線程不能做到的空白稍计。歸納起來(lái)說(shuō),線程池的作用包括:

  1. 利用線程池管理并服用線程裕循,控制最大并發(fā)數(shù)(手動(dòng)創(chuàng)建線程很難得到保證)
  2. 實(shí)現(xiàn)任務(wù)線程隊(duì)列緩存策略和拒絕機(jī)制
  3. 實(shí)現(xiàn)某些與實(shí)踐相關(guān)的功能臣嚣,如定時(shí)執(zhí)行,周期執(zhí)行等(比如列車指定時(shí)間運(yùn)行)
  4. 隔離線程環(huán)境剥哑,比如硅则,交易服務(wù)和搜索服務(wù)在同一臺(tái)服務(wù)器上,分別開(kāi)啟兩個(gè)線程池株婴,交易線程的資源消耗明顯要大怎虫。因此,通過(guò)配置獨(dú)立的線程池困介,將較慢的交易服務(wù)與搜索服務(wù)個(gè)離開(kāi)大审,避免個(gè)服務(wù)線程互相影響

相信到這里,你已經(jīng)了解線程池的基本思想了座哩,在使用過(guò)程中還是有幾個(gè)注意事項(xiàng)要說(shuō)明一下的

線程池使用思想/注意事項(xiàng)

不能忽略的線程池拒絕策略

我們很難準(zhǔn)確的預(yù)測(cè)未來(lái)的最大并發(fā)量徒扶,所以定制合理的拒絕策略是必不可少的步驟。默認(rèn)情況根穷, ThreadPoolExecutor 提供了四種拒絕策略:

  1. AbortPolicy:默認(rèn)的拒絕策略姜骡,會(huì) throw RejectedExecutionException 拒絕

  2. CallerRunsPolicy:提交任務(wù)的線程自己去執(zhí)行該任務(wù)

  3. DiscardOldestPolicy:丟棄最老的任務(wù),其實(shí)就是把最早進(jìn)入工作隊(duì)列的任務(wù)丟棄屿良,然后把新任務(wù)加入到工作隊(duì)列

  4. DiscardPolicy:相當(dāng)大膽的策略圈澈,直接丟棄任務(wù),沒(méi)有任何異常拋出

不同的框架(Netty尘惧,Dubbo)都有不同的拒絕策略康栈,我們也可以通過(guò)實(shí)現(xiàn) RejectedExecutionHandler 自定義的拒絕策略

對(duì)于采用何種策略,具體要看執(zhí)行的任務(wù)重要程度褥伴。如果是一些不重要任務(wù)谅将,可以選擇直接丟棄;如果是重要任務(wù)重慢,可以采用降級(jí)(所謂降級(jí)就是在服務(wù)無(wú)法正常提供功能的情況下饥臂,采取的補(bǔ)救措施。具體采用何種降級(jí)手段似踱,這也是要看具體場(chǎng)景)處理隅熙,例如將任務(wù)信息插入數(shù)據(jù)庫(kù)或者消息隊(duì)列稽煤,啟用一個(gè)專門用作補(bǔ)償?shù)木€程池去進(jìn)行補(bǔ)償

沒(méi)有絕對(duì)的拒絕策略,只有適合那一個(gè)囚戚,但在設(shè)計(jì)過(guò)程中千萬(wàn)不要忽略掉拒絕策略就可以

禁止使用Executors創(chuàng)建線程池

相信很多人都看到過(guò)這個(gè)問(wèn)題(阿里巴巴Java開(kāi)發(fā)手冊(cè)說(shuō)明禁止使用 Executors 創(chuàng)建線程池)酵熙,我把出處(P247)截圖在此:

Executors 大大的簡(jiǎn)化了我們創(chuàng)建各種類型線程池的方式,為什么還不讓使用呢驰坊?

其實(shí)匾二,只要你打開(kāi)看看它的靜態(tài)方法參數(shù)就會(huì)明白了

傳入的workQueue 是一個(gè)邊界為 Integer.MAX_VALUE 隊(duì)列,我們也可以變相的稱之為無(wú)界隊(duì)列了拳芙,因?yàn)檫吔缣罅瞬烀辏@么大的等待隊(duì)列也是非常消耗內(nèi)存的

/**
 * Creates a {@code LinkedBlockingQueue} with a capacity of
 * {@link Integer#MAX_VALUE}.
 */
public LinkedBlockingQueue() {
  this(Integer.MAX_VALUE);
}

另外該 ThreadPoolExecutor方法使用的是默認(rèn)拒絕策略(直接拒絕),但并不是所有業(yè)務(wù)場(chǎng)景都適合使用這個(gè)策略舟扎,當(dāng)很重要的請(qǐng)求過(guò)來(lái)直接選擇拒絕顯然是不合適的

總的來(lái)說(shuō)分飞,使用 Executors 創(chuàng)建的線程池太過(guò)于理想化,并不能滿足很多現(xiàn)實(shí)中的業(yè)務(wù)場(chǎng)景睹限,所以要求我們通過(guò) ThreadPoolExecutor來(lái)創(chuàng)建譬猫,并傳入合適的參數(shù)

總結(jié)

當(dāng)我們需要頻繁的創(chuàng)建線程時(shí),我們要考慮到通過(guò)線程池統(tǒng)一管理線程資源羡疗,避免不可控風(fēng)險(xiǎn)以及額外的開(kāi)銷

了解了線程池的幾個(gè)核心參數(shù)概念后染服,我們也需要經(jīng)過(guò)調(diào)優(yōu)的過(guò)程來(lái)設(shè)置最佳線程參數(shù)值(這個(gè)過(guò)程時(shí)必不可少的)

線程池雖然彌補(bǔ)了手動(dòng)創(chuàng)建線程的缺陷和空白,同時(shí)顺囊,合理的降級(jí)策略能大大增加系統(tǒng)的穩(wěn)定性

阿里巴巴手冊(cè)都是前輩們無(wú)數(shù)填坑后總結(jié)的精華肌索,你也應(yīng)該遵守相應(yīng)的指示蕉拢,結(jié)合自己的實(shí)際業(yè)務(wù)場(chǎng)景特碳,設(shè)定合適的參數(shù)來(lái)創(chuàng)建線程池

靈魂追問(wèn)

  1. 我們說(shuō)了這么多線程池的好,那使用線程池有哪些缺點(diǎn)或限制呢晕换?
  2. 為什么不建議所有業(yè)務(wù)共用一個(gè)線程池午乓?有什么缺點(diǎn)?
  3. 給線程池設(shè)置指定前綴闸准,有哪些方式益愈?

參考

感謝前輩們總結(jié)的精華,自己所寫(xiě)的并發(fā)系列好多都參考了以下資料

  • Java 并發(fā)編程實(shí)戰(zhàn)
  • Java 并發(fā)編程之美
  • 碼出高效
  • Java 并發(fā)編程的藝術(shù)
  • ifeve
  • 美團(tuán)技術(shù)團(tuán)隊(duì)

個(gè)人博客:https://dayarch.top
加我微信好友, 進(jìn)群娛樂(lè)學(xué)習(xí)交流夷家,備注「進(jìn)群」

歡迎持續(xù)關(guān)注公眾號(hào):「日拱一兵」

  • 前沿 Java 技術(shù)干貨分享
  • 高效工具匯總 | 回復(fù)「工具」
  • 面試問(wèn)題分析與解答
  • 技術(shù)資料領(lǐng)取 | 回復(fù)「資料」

以讀偵探小說(shuō)思維輕松趣味學(xué)習(xí) Java 技術(shù)棧相關(guān)知識(shí)蒸其,本著將復(fù)雜問(wèn)題簡(jiǎn)單化,抽象問(wèn)題具體化和圖形化原則逐步分解技術(shù)問(wèn)題库快,技術(shù)持續(xù)更新摸袁,請(qǐng)持續(xù)關(guān)注......


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市义屏,隨后出現(xiàn)的幾起案子靠汁,更是在濱河造成了極大的恐慌蜂大,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蝶怔,死亡現(xiàn)場(chǎng)離奇詭異奶浦,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)踢星,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門澳叉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人沐悦,你說(shuō)我怎么就攤上這事耳高。” “怎么了所踊?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵泌枪,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我秕岛,道長(zhǎng)碌燕,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任继薛,我火速辦了婚禮修壕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘遏考。我一直安慰自己慈鸠,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布灌具。 她就那樣靜靜地躺著青团,像睡著了一般。 火紅的嫁衣襯著肌膚如雪咖楣。 梳的紋絲不亂的頭發(fā)上督笆,一...
    開(kāi)封第一講書(shū)人閱讀 51,631評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音诱贿,去河邊找鬼娃肿。 笑死,一個(gè)胖子當(dāng)著我的面吹牛珠十,可吹牛的內(nèi)容都是我干的料扰。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼焙蹭,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼晒杈!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起壳嚎,我...
    開(kāi)封第一講書(shū)人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤桐智,失蹤者是張志新(化名)和其女友劉穎末早,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體说庭,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡然磷,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了刊驴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片姿搜。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖捆憎,靈堂內(nèi)的尸體忽然破棺而出舅柜,到底是詐尸還是另有隱情,我是刑警寧澤躲惰,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布致份,位于F島的核電站,受9級(jí)特大地震影響础拨,放射性物質(zhì)發(fā)生泄漏氮块。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一诡宗、第九天 我趴在偏房一處隱蔽的房頂上張望滔蝉。 院中可真熱鬧,春花似錦塔沃、人聲如沸蝠引。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)螃概。三九已至,卻和暖如春名扛,著一層夾襖步出監(jiān)牢的瞬間谅年,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工肮韧, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人旺订。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓弄企,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親区拳。 傳聞我的和親對(duì)象是個(gè)殘疾皇子拘领,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

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