深入JVM(八)線程安全與鎖優(yōu)化

并發(fā)處理的廣泛應(yīng)用是使得Amdahl定律代替摩爾定律成為計(jì)算機(jī)性能發(fā)展源動力的根本原因勘究,也是人類“壓榨”計(jì)算機(jī)運(yùn)算能力的最有力武器乱顾。

線程安全與鎖優(yōu)化

這幾天比較低沉走净。無論是天氣還是心情伏伯。不過今天在睡了一整天之后總算是“活”過來了。而且心態(tài)也調(diào)整過來了捌袜,決定把之前寫的這個(gè)深入JVM系列寫完说搅。其實(shí)也不過剩下最后一章,就是本文的線程安全與鎖優(yōu)化虏等。這本書其實(shí)讀的沒有多精細(xì)弄唧,通篇讀下來還是有一部分是沒有理解的。然后我著重記憶的也都是考點(diǎn)霍衫,或者說經(jīng)常提到或者用到的候引。我經(jīng)常說自己是考試前夕的學(xué)生敦跌。頭懸梁錐刺股為的也不過是及格澄干。有時(shí)候挺討厭這樣的自己的。閑話少敘柠傍,看文章內(nèi)容吧麸俘。

概述

書中概述的內(nèi)容較多。從面向過程的編程思想到面向?qū)ο蟮木幊趟枷刖宓选km然我們的整體變成已經(jīng)進(jìn)步了很多从媚。但是整體的思路是沒有變的。這句話我在以前也提過:先實(shí)現(xiàn)患整,再優(yōu)化静檬。
書中原文:

有時(shí)候,良好的設(shè)計(jì)原則不得不向現(xiàn)實(shí)做出一些讓步并级,我們必須讓程序在計(jì)算機(jī)正確無誤地運(yùn)行拂檩,然后再考慮如何將代碼組織得更好,讓程序運(yùn)行得更快嘲碧。對于這部分的主題 “高效并發(fā)” 來將稻励,首先需要保證并發(fā)的正確性,然后在此基礎(chǔ)上實(shí)現(xiàn)高效。本章先從如何保證并發(fā)的正確性和如何實(shí)現(xiàn)線程安全講起望抽。

線程安全

“線程安全”這個(gè)名稱加矛,很多人都會聽說過,甚至在戴拿編寫和走查的時(shí)候可能還會經(jīng)常掛在嘴邊煤篙。但是如何找到一個(gè)不太拗口的概念來定義線程安全卻不是一個(gè)容易的事情斟览。
網(wǎng)上的定義“如果一個(gè)對象可以安全的被多個(gè)線程同時(shí)使用,那么他就是線程安全的”辑奈。在書中還有Brian Goetz對線程安全的定義:“當(dāng)多個(gè)線程訪問一個(gè)對象時(shí)苛茂,如果不用考慮這些線程在運(yùn)行時(shí)環(huán)境下的調(diào)度和交替執(zhí)行,也不需要進(jìn)行額外的同步鸠窗,或者在調(diào)用方進(jìn)行任何其他的協(xié)調(diào)工作妓羊。調(diào)用這個(gè)對象的行為都可以獲得正確的結(jié)果,那這個(gè)對象是線程安全的”稍计。
其實(shí)總而言之躁绸,就是使用這個(gè)對象不用考慮多線程問題,更沒必要采取措施保證多線程的調(diào)用臣嚣。這個(gè)對象就是線程安全的净刮。
java語言中的線程安全
我們按照線程安全的“安全程度”由強(qiáng)到弱排序,分成五類:不可變硅则,絕對線程安全淹父,相對線程安全,線程兼容和線程對立抢埋。

  • 不可變: 在java語言中不可變的對象一定是線程安全的。無論是對象的方法實(shí)現(xiàn)還是方法的調(diào)用者督暂,都不需要采取任何的線程安全保障措施揪垄。 java語言中,共享數(shù)據(jù)是一個(gè)基本數(shù)據(jù)類型逻翁,只要在定義時(shí)加上final關(guān)鍵字就可以保證它是不可變的饥努。如果共享數(shù)據(jù)是一個(gè)對象,我們要保證對象的行為不會對其狀態(tài)產(chǎn)生任何影響八回。(可以想想string類型酷愧。調(diào)用它的substring(),replace()等都不影響它本來的值)
    保證對象行為不影響自己狀態(tài)的途徑有好多缠诅。最簡單的就是把對象的屬性都設(shè)置為final(書中說的是把對象的帶有狀態(tài)的變量都聲明為final溶浴。這樣在構(gòu)造函數(shù)結(jié)束以后,他就是不可變的管引。我理解就是所有屬性都是final士败。如果我說錯(cuò)了歡迎大家指出來)。
  • 絕對線程安全:絕對線程安全就能滿足上面我們對線程安全的定義。其實(shí)這個(gè)定義很嚴(yán)格的谅将。在java API中很多標(biāo)注自己是線程安全的類其實(shí)都不是絕對的線程安全漾狼。
    我們都知道java.util.Vector是一個(gè)線程安全的容器。因?yàn)樗腶dd()饥臂,get()逊躁,size()這類方法都是被synchronized修飾的,雖然這樣效率很低隅熙,但是確實(shí)是安全的稽煤。但是即使他的所有的方法都是同步的,也不意味著調(diào)用它的時(shí)候永遠(yuǎn)都不需要同步手段了猛们。
package demo;

import java.util.Vector;

public class VectorDemo {
    
    //首先創(chuàng)建一個(gè)vector的對象念脯。
    private static Vector<Integer> vector = new Vector<Integer>();
     
    public static void main(String[] args) {
        while (true) {
            for (int i = 0; i < 10; i++) {
                vector.add(i);
            }
            
            Thread removeThread = new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < vector.size(); i++) {
                        vector.remove(i);
                    }
                }
            });
            
            Thread printThread = new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < vector.size(); i++) {
                        System.out.println(vector.get(i));
                    }
                }
            });
            
            removeThread.start();
            printThread.start();
            
            //這個(gè)書上說線程過多會操作系統(tǒng)假死。
            while (Thread.activeCount() > 20);
        }
    }
}

講一下上面的代碼弯淘,我跑了不到五分鐘绿店,然后報(bào)錯(cuò)java.lang.ArrayIndexOutOfBoundsException。集合下標(biāo)越界庐橙。其實(shí)就是刪除和打印最后沖突了假勿。書中說的解決辦法就是把線程中的for循環(huán)前面加上線程鎖。改成如下這樣

package demo;

import java.util.Vector;

public class VectorDemo {
    
    //首先創(chuàng)建一個(gè)vector的對象态鳖。
    private static Vector<Integer> vector = new Vector<Integer>();
     
    public static void main(String[] args) {
        while (true) {
            for (int i = 0; i < 10; i++) {
                vector.add(i);
            }
            
            Thread removeThread = new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized(vector) {
                        for (int i = 0; i < vector.size(); i++) {
                            vector.remove(i);
                        }
                    }
                }
            });
            
            Thread printThread = new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized(vector) {
                        for (int i = 0; i < vector.size(); i++) {
                            System.out.println(vector.get(i));
                        }
                    }
                }
            });
            
            removeThread.start();
            printThread.start();
            
            //這個(gè)書上說線程過多會操作系統(tǒng)假死转培。
            while (Thread.activeCount() > 20);
        }
    }
}
  • 相對線程安全:相對線程安全才是我們通常意義上所講的線程安全。它需要保證對這個(gè)對象的單獨(dú)操作是線程安全的浆竭,我們不需要做額外的保證措施浸须。但是對一些特定順序的連續(xù)調(diào)用,需要在調(diào)用段使用額外的同步手段來保證調(diào)用的正確性邦泄。上面vector的代碼就是這種删窒。
  • 線程兼容:線程兼容值對象本身不是線程安全的,但是可以通過在調(diào)用端正確的使用同步手段來保證對象在并發(fā)環(huán)境中可以安全的使用顺囊。我們平常說的一個(gè)類不是線程安全的肌索,絕大多數(shù)就是這種情況。比如ArrayList和HashMap特碳。
  • 線程對立:指無論是夠采用同步措施诚亚,都無法在多線程環(huán)境中并發(fā)使用的代碼。
    比如Thread的suspend()和resume()方法午乓,同時(shí)使用很容易產(chǎn)生死鎖站宗。
    線程安全的實(shí)現(xiàn)方法
    互斥同步:互斥同步是一種常見的并發(fā)正確性保障手段。同步是指在多個(gè)線程并發(fā)訪問共享數(shù)據(jù)時(shí)益愈,保證共享數(shù)據(jù)在同一個(gè)時(shí)刻只被一個(gè)線程使用份乒。而互斥則是實(shí)現(xiàn)同步的一種手段。在這四個(gè)字中,互斥是因或辖,同步是果瘾英。互斥是手段颂暇,同步是目的缺谴。
    java語言中最基本的互斥同步手段就是synchronized。
    synchronized有兩點(diǎn)需要注意:
    1. synchronized同步塊對同一個(gè)線程可重復(fù)入耳鸯。
    2. synchronized同步塊在已進(jìn)入的線程執(zhí)行完畢之前會阻塞其他的線程湿蛔。
      然后因?yàn)榫€程阻塞或喚醒一個(gè)線程很消耗性能,所以 synchronized在java中是一個(gè)重量級的操作县爬。

除了 synchronized以外阳啥,還可以用java.util.concurrent包中的重入鎖實(shí)現(xiàn)同步,基本用法上财喳,ReentrantLock和 synchronized很相似察迟。都具備同一個(gè)線程可重入。并且相比 synchronized耳高,ReentrantLock增加了一些高級功能扎瓶。主要有:

  1. 等待可中斷
    當(dāng)持有鎖的線程長期不釋放鎖的時(shí)候,正在等待的線程可以選擇放棄等待泌枪,改為處理其他事情概荷,可中斷特性對處理執(zhí)行時(shí)間非常長的同步塊很有幫助。
  2. 可實(shí)現(xiàn)公平鎖
    多個(gè)線程在等待同一個(gè)鎖時(shí)碌燕,必須按照申請鎖的時(shí)間順序來依次獲得鎖误证;而非公平鎖則不保證這一點(diǎn),在鎖被釋放時(shí)修壕,任何一個(gè)等待鎖的線程都有機(jī)會獲得鎖愈捅。
    synchronized 中的鎖是非公平的,ReentrantLock 默認(rèn)情況下也是非公平的叠殷,但可以通過帶布爾值的構(gòu)造函數(shù)要求使用公平鎖改鲫。
  3. 鎖可以綁定多個(gè)條件
    一個(gè) ReentrantLock 對象可以同時(shí)綁定多個(gè) Condition 對象诈皿,而在 synchronized 中林束,鎖對象的 wait() 和 notify() 或 notifyAll() 方法可以實(shí)現(xiàn)一個(gè)隱含的條件,如果要和多于一個(gè)的條件關(guān)聯(lián)的時(shí)候稽亏,就不得不額外添加一個(gè)鎖壶冒,而 ReentrantLock 則無須這樣做,只需要多次調(diào)用 newCondition() 方法即可截歉。
    (我個(gè)人感覺就是ReentrantLock 比較靈活胖腾,可中斷,可排隊(duì),可有多個(gè)鎖條件)
    然后書中還有兩個(gè)鎖的性能對比咸作。但是是jdk1.5和1.6的锨阿。然后書中也說了synchronized在不斷優(yōu)化。1.6的時(shí)候兩者性能就持平了记罚。我覺得目前的開發(fā)都是1.6以上墅诡,所以就不額外說這個(gè)了。
  • 非阻塞同步:互斥同步最主要的問題就是線程阻塞和喚醒帶來的性能問題桐智。因此這個(gè)也叫做阻塞同步末早。從處理問題的方式來說,互斥同步屬于悲觀鎖说庭。而接下來要說的則屬于樂觀鎖然磷。
    通俗地說,就是先進(jìn)行操作刊驴,如果沒有其他線程爭用共享數(shù)據(jù)姿搜,那操作就成功了;如果共享數(shù)據(jù)有爭用缺脉,產(chǎn)生了沖突痪欲,那就再采取其他的補(bǔ)償措施(最常見的補(bǔ)償措施就是不斷地重試,知道成功為止)攻礼,這種樂觀的并發(fā)策略的許多實(shí)現(xiàn)都不需要把線程掛起业踢,因此這種同步操作稱為非阻塞同步。
    書中用到了以前volatile的例子(我再次貼出來防止大家忘記了礁扮。)知举。
package demo;

public class VolatileDemo {

    private static volatile int num = 0;

    public static void add() {
        num++;
    }

    public static void main(String[] args) {
        Thread[] threads = new Thread[20];
        for (Thread thread : threads) {
            thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 10000; i++) {
                        add();
                    }
                }
            });         
            thread.start();
        }
        
        while (Thread.activeCount()>1)      
            Thread.yield();
        System.out.println(num);
    }

}

當(dāng)時(shí)運(yùn)行的結(jié)果怎么都不是20w。因?yàn)閚um++這個(gè)操作不是原子性的太伊。在jvm運(yùn)行時(shí)會拆成三個(gè)指令雇锡。而我們?nèi)绻氡WC得到的是20w則要保證自增的原子性。用num.incrementAndGet()代替num++僚焦。
下面是incrementAndGet() 方法的 JDK 源碼:

    public final int incrementAndGet() {
        for (;;) {
            int current = get();
            int next = current + 1;
            if (compareAndSet(current, next))
                return next;
        }
    }

incrementAndGet() 方法在一個(gè)無限循環(huán)中锰提,不斷嘗試將一個(gè)比當(dāng)前值大 1 的新值賦給自己。如果失敗了芳悲,那說明在執(zhí)行 “獲取-設(shè)置” 操作的時(shí)候值已經(jīng)有了修改立肘,于是再次循環(huán)進(jìn)行下一次操作,直到設(shè)置成功為止名扛。其實(shí)這個(gè)方法也有一個(gè)問題谅年。一個(gè)變量初次讀取是A,檢查賦值的時(shí)候也是A肮韧。但是能確定它的值沒被改過融蹂?

  • 無同步方案:有一些類不需要同步就可以保證線程安全旺订。
    簡單的介紹兩個(gè)類:
  1. 可重入代碼:也叫純代碼。就是任何時(shí)刻中斷執(zhí)行別的代碼在控制權(quán)回來之后還可以正確運(yùn)行超燃。所有可重入代碼都是線程安全的区拳。但是并非所有線程安全的代碼都是可重入的。
    可重入代碼有一些共同的特征意乓,例如不依賴存儲在堆上的數(shù)據(jù)和公用的系統(tǒng)資源劳闹、用到的狀態(tài)量都由參數(shù)中傳入、不調(diào)用非可重入的方法等洽瞬。我們可以通過一個(gè)簡單的原則來判斷代碼是否具備可重入性:如果一個(gè)方法本涕,它的返回結(jié)果是可以預(yù)測的,只要輸入了相同的數(shù)據(jù)伙窃,就都能返回相同的結(jié)果菩颖,那它就滿足可重入性的要求,當(dāng)然也就是線程安全的为障。
  2. 線程本地存儲:如果一段代碼中所需要的數(shù)據(jù)必須與其他代碼共享晦闰,那就看看這些共享數(shù)據(jù)的代碼是否能保證在同一個(gè)線程中執(zhí)行?如果能保證鳍怨,我們就可以把共享數(shù)據(jù)的可見范圍限制在同一個(gè)線程之內(nèi)呻右,這樣,無須同步也能保證線程之間不出現(xiàn)數(shù)據(jù)爭用的問題鞋喇。
鎖優(yōu)化
  • 自旋鎖與自適應(yīng)自旋
    互斥同步最大的消耗是線程阻塞和喚醒声滥。同時(shí),虛擬機(jī)的開發(fā)團(tuán)隊(duì)也注意到在許多應(yīng)用上侦香,共享數(shù)據(jù)的鎖定狀態(tài)只會持續(xù)很短的一段時(shí)間落塑,為了這段時(shí)間去掛起和恢復(fù)線程并不值得。
    如果物理機(jī)器有一個(gè)以上的處理器罐韩,能讓兩個(gè)或以上的線程同時(shí)并行執(zhí)行憾赁,我們就可以讓后面請求鎖的那個(gè)線程 “稍等一下”,但不放棄處理器的執(zhí)行時(shí)間散吵,看看持有鎖的線程是否很快就會釋放鎖龙考。為了讓線程等待,我們只需讓線程執(zhí)行一個(gè)忙循環(huán)(自旋)矾睦,這項(xiàng)技術(shù)就是所謂的自旋鎖晦款。
    自適應(yīng)的自旋鎖。意味著自旋的時(shí)間不再固定了顷锰,而是由前一次在同一個(gè)鎖上的自旋時(shí)間及鎖的擁有者的狀態(tài)來決定柬赐。這個(gè)具體的時(shí)間算法有點(diǎn)復(fù)雜亡问,但是都由虛擬機(jī)實(shí)現(xiàn)官紫,所有我這里就不多說了肛宋。畢竟我自己看了幾遍都懵。這里只是簡單的了解束世。
  • 鎖消除
    鎖消除是指虛擬機(jī)即時(shí)編譯器在運(yùn)行時(shí)酝陈,對一些代碼上要求同步,但是被檢測到不可能存在共享數(shù)據(jù)競爭的鎖進(jìn)行消除毁涉。這個(gè)其實(shí)我感覺是虛擬機(jī)的優(yōu)化沉帮,和我們本身的關(guān)系。贫堰。就跟語法糖似的穆壕,知道不知道我們編寫代碼的時(shí)候都是差不多沒影響的。
  • 鎖粗化
    原則上其屏,我們在編寫代碼的時(shí)候喇勋,總是推薦將同步塊的作用范圍限制得盡量小——只在共享數(shù)據(jù)的實(shí)際作用域中才進(jìn)行同步,這樣是為了使得需要同步的操作數(shù)量盡可能變小偎行,如果存在鎖競爭川背,那等待鎖的線程也能盡快拿到鎖。
    大部分情況下蛤袒,上面的原則都是正確的熄云,但是如果一系列的連續(xù)操作都對同一個(gè)對象反復(fù)加鎖和解鎖,甚至加鎖操作是出現(xiàn)在循環(huán)體中妙真,那即使沒有線程競爭缴允,頻繁地進(jìn)行互斥同步操作也會導(dǎo)致不必要的性能損耗。如果虛擬機(jī)探測到這種情況珍德,會把加鎖同步的范圍擴(kuò)展(粗化)到整個(gè)操作序列的外部癌椿。
  • 偏向鎖
    其實(shí)這個(gè)概念挺好玩的。
    偏向鎖的 “偏”菱阵,就是偏心的 “偏”踢俄、偏袒的 “偏”,它的意思是這個(gè)鎖會偏向于第一個(gè)獲得它的線程晴及,如果在接下來的執(zhí)行過程中都办,該鎖沒有被其他的線程獲取,則持有偏向鎖的線程將永遠(yuǎn)不需要再進(jìn)行同步虑稼。
    打個(gè)比方琳钉,你父母就一個(gè)孩子,那么什么都是你的蛛倦,眼里心里都是你歌懒。但是如果沒有二胎會一直這么下去。但是假如有了二胎溯壶,這種偏心立刻沒了及皂!這個(gè)鎖也是這樣甫男。
    當(dāng)鎖對象第一次被線程獲取的時(shí)候,虛擬機(jī)將會把對象頭中的標(biāo)志位設(shè)為 “01”验烧,即偏向模式板驳。持有偏向鎖的線程以后每次進(jìn)入這個(gè)鎖相關(guān)的同步塊時(shí),虛擬機(jī)都可以不再進(jìn)行如何同步操作碍拆。當(dāng)有另外一個(gè)線程去嘗試獲取這個(gè)鎖時(shí)若治,偏向模式就宣告結(jié)束。根據(jù)鎖對象目前是否處于被鎖定的狀態(tài)感混,撤銷偏向后恢復(fù)到未鎖定或輕量級鎖定的狀態(tài)端幼。(ps:這里有個(gè)輕量級鎖我沒寫。因?yàn)榭戳税胩爝€沒太理解弧满。等我理解了再補(bǔ)充上來)

然后到此静暂,深入理解java虛擬機(jī)這本書就看完了。其實(shí)心情很復(fù)雜谱秽,有著看完一本書的驕傲和自豪洽蛀,也有著遺憾和可惜。我一直講敲代碼是樂趣疟赊。學(xué)習(xí)一些知識也是郊供。但是如此的填鴨式學(xué)習(xí),死記硬背加上刪刪減減近哟,我自己都覺得是對知識的不尊重驮审。可是然后呢吉执?聊一下題外話疯淫,最近的面試遇到過各種各樣的問題,簡單的戳玫,基礎(chǔ)的熙掺,重要的,核心的咕宿,奇葩的币绩,超預(yù)計(jì)的。也心里不平衡過府阀,覺得問的什么狗屁問題缆镣!也自卑過,驚訝于自己很多基礎(chǔ)都不扎實(shí)试浙,應(yīng)該會的問題都沒說清董瞻。不過學(xué)海無涯。我覺得應(yīng)該堅(jiān)持一下自己的一直以來的態(tài)度:多學(xué)學(xué)多看看田巴,總不會有壞處的钠糊。

最后~~~~全文手打不易挟秤。如果你覺得稍微幫到了你一點(diǎn)點(diǎn),請點(diǎn)個(gè)喜歡點(diǎn)個(gè)關(guān)注眠蚂。有不同意見或者問題的歡迎評論或者私信。祝大家工作生活都順順利利吧斗躏。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末逝慧,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子啄糙,更是在濱河造成了極大的恐慌笛臣,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件隧饼,死亡現(xiàn)場離奇詭異沈堡,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)燕雁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進(jìn)店門诞丽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人拐格,你說我怎么就攤上這事僧免。” “怎么了捏浊?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵懂衩,是天一觀的道長。 經(jīng)常有香客問我金踪,道長浊洞,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任胡岔,我火速辦了婚禮法希,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘靶瘸。我一直安慰自己铁材,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布奕锌。 她就那樣靜靜地躺著著觉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪惊暴。 梳的紋絲不亂的頭發(fā)上饼丘,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天,我揣著相機(jī)與錄音辽话,去河邊找鬼肄鸽。 笑死卫病,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的典徘。 我是一名探鬼主播蟀苛,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼逮诲!你這毒婦竟也來了帜平?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤梅鹦,失蹤者是張志新(化名)和其女友劉穎裆甩,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體齐唆,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡嗤栓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了箍邮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片茉帅。...
    茶點(diǎn)故事閱讀 40,133評論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖锭弊,靈堂內(nèi)的尸體忽然破棺而出担敌,到底是詐尸還是另有隱情,我是刑警寧澤廷蓉,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布全封,位于F島的核電站,受9級特大地震影響桃犬,放射性物質(zhì)發(fā)生泄漏刹悴。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一攒暇、第九天 我趴在偏房一處隱蔽的房頂上張望土匀。 院中可真熱鬧,春花似錦形用、人聲如沸就轧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽妒御。三九已至,卻和暖如春镇饺,著一層夾襖步出監(jiān)牢的瞬間乎莉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留惋啃,地道東北人哼鬓。 一個(gè)月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像边灭,于是被迫代替她去往敵國和親异希。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評論 2 355

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