synchronized

同步鎖synchronized關鍵字
1>>修飾實例方法 對象鎖為this
2>>修飾靜態(tài)方法 對象鎖是當前類的字節(jié)碼文件,即this.getClass();少用-->占內存,垃圾回收無法處理
3>>修飾代碼塊 對象鎖為synchronized(obj) 指定的obj
4>>解決了線程不安全的情況,但是多個線程需要判斷鎖,搶鎖,比較耗資源

2>lock()鎖
1>>重入鎖
lock鎖和synchronized的區(qū)別:
1>synchronized 是內部鎖,自動化的上鎖與釋放鎖,而lock是手動的,需要人為的上鎖和釋放鎖,lock比較靈活,但是代碼相對較多
2>lock接口異常的時候不會自動的釋放鎖,同樣需要手動的釋放鎖,所以一般寫在finally語句塊中,而synchronized則會在異常的時候自動的釋放鎖
3>lock超時獲取鎖:在指定的截止時間之前獲取鎖,如果截止時間到了仍舊無法獲取鎖,則返回
4>lock嘗試非阻塞的獲取鎖:當前線程嘗試獲取鎖,如果這一時刻沒有被其他線程獲取到,則成功獲取并持有鎖。
5>lock能被中斷的獲取鎖:獲取到鎖的線程能夠響應中斷,當獲取到鎖的線程被中斷時癣缅,中斷異常將被拋出,同事釋放鎖哄酝。

volatile關鍵字作用:使變量在多個線程之間可見,強制線程去主內存中取該數(shù)據(jù).
volatile與synchronized區(qū)別:
1>volatile輕量級,只能修飾變量,synchronized重量級,還可以修飾方法.
2>volatile只能保證數(shù)據(jù)的可見性,不能保證線程的安全性(原子性)
3>synchronized不僅保證可見性友存,而且還保證原子性,因為陶衅,只有獲得了鎖的線程才能進入臨界區(qū)屡立,從而保證臨界區(qū)中的所有語句都全部執(zhí)行。多個線程爭搶synchronized鎖對象時搀军,會出現(xiàn)阻塞膨俐。
4>volatile 禁止重排序(重排序:CPU會對代碼執(zhí)行實現(xiàn)優(yōu)化,但不會對有依賴關系的做重排序,代碼可能改變順序,但不會改變結果,重排序的意義是提高并行度,但是在多線程情況下有可能有影響到結果,此時需要用volatile)


CAS算法理解

對CAS的理解勇皇,CAS是一種無鎖算法,CAS有3個操作數(shù)焚刺,內存值V敛摘,舊的預期值A,要修改的新值B乳愉。當且僅當預期值A和內存值V相同時兄淫,將內存值V修改為B,否則什么都不做蔓姚。

java 中的鎖:
隱式鎖:在Java代碼中不能看到加鎖過程的鎖(Synchronized就是隱式鎖)拖叙;
顯式鎖:在Java代碼中能看到加鎖過程的鎖(java.util.concurrent包下的那些鎖

二、 樂觀鎖和悲觀鎖:
1赂乐、樂觀鎖是一種樂觀思想,即認為讀多寫少咖气,遇到并發(fā)寫的可能性低挨措,每次去拿數(shù)據(jù)的時候都認為別人不會修改,所以不會上鎖崩溪,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數(shù)據(jù)浅役,采取在寫時先讀出當前版本號,然后加鎖操作(比較跟上一次的版本號伶唯,如果一樣則更新)觉既,如果失敗則要重復讀?比較?執(zhí)行寫操作。java中的樂觀鎖基本都是通過CAS操作實現(xiàn)的乳幸,CAS是一種更新的原子操作瞪讼,比較當前值跟傳入值是否一樣,一樣則更新粹断,否則失敗符欠。
2、悲觀鎖是就是悲觀思想瓶埋,即認為寫多讀少希柿,遇到并發(fā)寫的可能性高,每次去拿數(shù)據(jù)的時候都認為別人會修改养筒,所以每次在讀寫數(shù)據(jù)的時候都會上鎖曾撤,這樣別人想讀寫這個數(shù)據(jù)就會block(阻塞等待)直到拿到鎖。java中的悲觀鎖就是Synchronized,AQS框架下的鎖則是先嘗試cas樂觀鎖去獲取鎖晕粪,獲取不到挤悉,才會轉換為悲觀鎖,如ReentrantLock兵多。

三尖啡、 重入鎖與非重入鎖:
在一個同步區(qū)域中有一個或多個同步區(qū)域橄仆,這兩個或多個同步區(qū)域的鎖對象是同一個,同一個線程拿到了最外層同步區(qū)域的鎖后能夠進入內層的同步區(qū)域衅斩,這樣的鎖機制就是重入鎖盆顾,反之就是非重入鎖。

四畏梆、 讀寫鎖:
多線程并發(fā)或者并行讀操作的時候您宪,不進行互斥,一旦有寫操作就進行互斥的鎖的機制奠涌。(讀鎖與讀鎖不互斥宪巨,讀鎖與寫鎖互斥,寫鎖與寫鎖互斥)

五溜畅、 偏向鎖捏卓、輕量級鎖、自旋鎖慈格、重量級鎖(JVM 通過monitor指令去調用底層C++):
1怠晴、偏向鎖、輕量級鎖浴捆、自旋鎖屬于樂觀鎖蒜田;
2、重量級鎖屬于悲觀鎖选泻。

重量級鎖(synchronized):
1.synchronized代碼塊反編譯后冲粤,輸出的字節(jié)碼有monitorenter和monitorexit語句
2.每一個對象都會和一個監(jiān)視器monitor關聯(lián)。監(jiān)視器被占用時會被鎖住页眯,其他線程無法來獲取該monitor梯捕。
3.當JVM執(zhí)行某個線程的某個方法內部的monitorenter時,它會嘗試去獲取當前對象對應的monitor的所有權餐茵。其過程如下:
若monior的進入數(shù)為0科阎,線程可以進入monitor,并將monitor的進入數(shù)置為1忿族。當前線程成為monitor的owner(所有者)
若線程已擁有monitor的所有權锣笨,允許它重入monitor,并遞增monitor的進入數(shù)
若其他線程已經占有monitor的所有權道批,那么當前嘗試獲取monitor的所有權的線程會被阻塞错英,直到monitor的進入數(shù)變?yōu)?,才能重新嘗試獲取monitor的所有權隆豹。
4.能執(zhí)行monitorexit指令的線程一定是擁有當前對象的monitor的所有權的線程椭岩。
執(zhí)行monitorexit時會將monitor的進入數(shù)減1。當monitor的進入數(shù)減為0時,當前線程退出monitor判哥,不再擁有monitor的所有權献雅,此時其他被這個monitor阻塞的線程可以嘗試去獲取這個monitor的所有權。

monitor
每一個JAVA對象都會與一個監(jiān)視器monitor關聯(lián)塌计,我們可以把它理解成為一把鎖挺身,當一個線程想要執(zhí)行一段被synchronized圈起來的同步方法或者代碼塊時,該線程得先獲取到synchronized修飾的對象對應的monitor锌仅。

我們的java代碼里不會顯示地去創(chuàng)造這么一個monitor對象章钾,我們也無需創(chuàng)建,事實上可以這么理解:我們是通過synchronized修飾符告訴JVM需要為我們的某個對象創(chuàng)建關聯(lián)的monitor對象热芹。

在hotSpot虛擬機中贱傀,monitor是由ObjectMonitor實現(xiàn)的。其源碼是用c++來實現(xiàn)的伊脓,位于hotSpot虛擬機源碼ObjectMonitor.hpp文件中府寒。


堆中的對象,由對象頭,實例數(shù)據(jù),對齊填充構成
對象頭:
1.對象頭形式
普通對象頭


image.png

數(shù)組對象頭


image.png

對象頭(Header):包含兩部分,
第一部分(mark word)用于存儲對象自身的運行時數(shù)據(jù)报腔,如哈希碼椰棘、GC分代年齡、鎖狀態(tài)標志榄笙、線程持有的鎖、偏向線程 ID祷蝌、偏向時間戳等茅撞,32 位虛擬機占 32 bit,64 位虛擬機占 64 bit巨朦。官方稱為 ‘Mark Word’米丘;
第二部分(KLASS)是類型指針,即對象指向它的類的元數(shù)據(jù)指針糊啡,虛擬機通過這個指針確定這個對象是哪個類的實例拄查,
另外,如果是 Java 數(shù)組棚蓄,對象頭中還必須有一塊用于記錄數(shù)組長度的數(shù)據(jù)堕扶,因為普通對象可以通過 Java 對象元數(shù)據(jù)確定大小,而數(shù)組對象不可以梭依;


image.png
image.png
/**
 * synchronized關鍵字的底層原理
 *
 * 由于虛擬機默認開啟指針壓縮稍算,所以整個對象頭的占12個字節(jié)
 * 在VM參數(shù)中加入:-XX:-UseCompressedOops關閉指針壓縮。
 *
 * 由于Intel是采用小端存儲的役拴,所以是數(shù)據(jù)的低位保存在內存的低地址中糊探,
 * 而數(shù)據(jù)的高位保存在內存的高地址中
 * 地址:以字節(jié)為單位低----------->高
 *(object header)     01 00 00 00  (0_0000_0_01 00000000 00000000 00000000) (1)
 *(object header)     00 00 00 00 (0_0000000 00000000 00000000 00000000) (0)
 *
 *前8位分析:0沒有用到   0000表示GC的年齡    0表示是否偏向   01表示鎖的級別和GC狀態(tài)標識
 *
 *所以的得出結論:
 *關于鎖的狀態(tài)就觀察對象頭的第一個字節(jié)的后3位。
 *第一位表示是否是偏向鎖狀態(tài),
 *第二科平、三位表示鎖的級別和GC的標記褥紫。01無鎖,00輕量級鎖  10重量級鎖  11 GC標記
 *綜上所述:
 *001:無鎖瞪慧,101偏向鎖髓考, 末尾兩位00輕量級鎖  末尾兩位10重量級鎖
 *因為輕量級鎖和重量級鎖, 代表偏向的位用于其他表示了,不在代表偏向鎖
 */
public class Test {

    private int k = 0;

    private Object myLock = new Object();

    public static void main(String[] args) {

        Test test = new Test();
        System.out.println("計算hashCode之前----------------------");
        System.out.println(ClassLayout.parseInstance(test).toPrintable());

        System.out.println("計算hashCode之后----------------------");
        int hashCode = test.hashCode();
        System.out.println("hashCode:"+hashCode);
        System.out.println("轉為16進制的hashCode:"+Integer.toHexString(hashCode));
        System.out.println(ClassLayout.parseInstance(test).toPrintable());
        System.out.println(ClassLayout.parseInstance(test).toPrintable());
    }
}

運行結果如下:


image.png

對象的狀態(tài)有幾種:
無鎖,偏向鎖,輕量級鎖,重量級鎖,GC標志五個狀態(tài)

鎖的膨脹過程:
無鎖:
程序多線程執(zhí)行過程中,沒有去執(zhí)行synchronized修飾區(qū)域或者方法

偏向鎖:
發(fā)生在程序多線程過程中,由始至終只有一個線程去執(zhí)行過synchronized修飾的區(qū)域或者方法,由于是由始至終只有一個線程去執(zhí)行,所以,沒有發(fā)生競爭,等待,搶鎖的情況,他不會調用操作系統(tǒng)的函數(shù)去實現(xiàn)同步.

輕量級鎖:
發(fā)生在程序多線程執(zhí)行過程中有去執(zhí)行synchronized修飾區(qū)域或方法,且沒有發(fā)生競爭,等待,搶鎖的情況或者發(fā)生了競爭,等待,搶鎖,但是競爭,等待和搶鎖的時間沒有超過一個JVM設定的自旋時間或次數(shù)的時候,他是在虛擬機內部去實現(xiàn)的同步,不會調用操作系統(tǒng)的函數(shù)去實現(xiàn)同步.

重量級鎖:
發(fā)生在程序多線程執(zhí)行過程中有去執(zhí)行synchronized修飾區(qū)域或者方法,且發(fā)生了競爭汞贸、等待绳军、搶鎖且競爭、等待和搶鎖的時間已經超過一個JVM設定的自旋時間或者次數(shù)的時候矢腻,它會調用操作系統(tǒng)的函數(shù)去實現(xiàn)同步(調用操作系統(tǒng)實現(xiàn)同步门驾,需要的步驟很多,導致性能相對于其它鎖實現(xiàn)同步的方式就很低)多柑。

/**
     * synchronized關鍵字的底層原理
     * 加鎖之后不睡眠則:變成了輕量級鎖
     * 因為是JVM默認開啟了偏向鎖延遲開啟的開關
     *
     * 注意:偏向鎖:101奶是,的第一個1表示的是這個是可偏向狀態(tài),
     * 而不是說它已經是一個偏向鎖了竣灌,如何辨別呢聂沙?
     * 看其他字節(jié)是否有存儲數(shù)據(jù),如果有就是已經是偏向鎖了初嘹,
     * 如果沒有及汉,則還是處于一個可偏向狀態(tài)的無鎖。
     * -XX:BiasedLockingStartupDelay=0  可以設置延遲開啟偏向鎖的時間
     * @author Peter
     */
    public static void main(String[] args) throws InterruptedException {

        /*
         * JVM啟動需要啟動很多我們不知道的線程屯烦,比如GC坷随,
         * 要花費4秒時間,所以延遲開啟偏向鎖的時間默認為4秒
         */
       // Thread.sleep(4100);
        Test test = new Test();
        System.out.println("計算加鎖之前----------------------");
        System.out.println(ClassLayout.parseInstance(test).toPrintable());

        synchronized (test){
            System.out.println("計算加鎖之后----------------------");
            System.out.println(ClassLayout.parseInstance(test).toPrintable());
        }
    }

運行結果如下:


image.png

保存偏向線程ID,表示當前的線程就是這個線程,如果下次還是這個線程的話,則直接放行(獲取鎖).

/**
     * synchronized關鍵字的底層原理
     *
     *  -XX:BiasedLockingStartupDelay=0
     * 演示計算了hashCode的對象不能成為偏向鎖
     * 會直接成為輕量級鎖驻龟,因為沒有地方存關于偏向鎖的信息了
     * 就直接成為輕量級鎖温眉,并把hashCode放入記錄的線程信息中
     */
    public static void main(String[] args) {
        Test test=new Test();
        //這里計算一下hashCode
        test.hashCode();
        System.out.println("------------------------------加鎖之前--------------------------------");
        System.out.println(ClassLayout.parseInstance(test).toPrintable());
        synchronized (test) {
            System.out.println("-------------------------------加鎖之后------------------------------");
            System.out.println(ClassLayout.parseInstance(test).toPrintable());
        }

    }

運行結果如下:


image.png
/**
     * synchronized關鍵字的底層原理
     *
     * -XX:BiasedLockingStartupDelay=0
     * 如果調用wait方法,則立刻變?yōu)橹亓考夋i
     * wait方法就是monitor實現(xiàn)的
     *wait表示等待,說明會有競爭搶鎖的情況,并且時間不會短,所以直接變?yōu)橹亓考夋i
     * synchronized內置的鎖的膨脹過程不可逆
     */
    public static void main(String[] args) throws InterruptedException {
        final Object  testLock=new Object();
        System.out.println("------------------------------加鎖之前------------------------");
        System.out.println(ClassLayout.parseInstance(testLock).toPrintable());
        synchronized (testLock) {
            System.out.println("-----------------------加鎖之后等待之前------------------");
            System.out.println(ClassLayout.parseInstance(testLock).toPrintable());
            testLock.wait(1_000);
            System.out.println("--------------------加鎖之后等待之后------------------------");
            System.out.println(ClassLayout.parseInstance(testLock).toPrintable());
        }
        System.out.println("--------------------退出同步代碼塊之后----------------------");
        System.out.println(ClassLayout.parseInstance(testLock).toPrintable());
    }

運行結果如下:


image.png
/**
 * synchronized關鍵字的底層原理
 *
 * 證明:
 * 偏向鎖偏向一個線程后翁狐,不會發(fā)生重偏向
 * 另一個線程的情況类溢,只會膨脹為輕量級鎖。
 * 注意:這里因為是主線程去進入同步代碼區(qū)域
 * 所以會膨脹為輕量級鎖
 * -XX:BiasedLockingStartupDelay=0
 */
public static void main(String[] args) throws InterruptedException {
        final Object  testLock=new Object();
        final Thread t1 = new Thread("子線程:"){
            @Override
            public void run() {
                String threadName = Thread.currentThread().getName();
                System.out.println(threadName+"---------------------加鎖前------------------");
                System.out.println(ClassLayout.parseInstance(testLock).toPrintable());
                synchronized (testLock) {
                    System.out.println(threadName+"--------------------加鎖后-----------------");
                    System.out.println(ClassLayout.parseInstance(testLock).toPrintable());
                }
            }
        };
        t1.start();
        t1.join();

        System.out.println("主線程:------------------加鎖之前--------------------------");
        System.out.println(ClassLayout.parseInstance(testLock).toPrintable());
        synchronized (testLock) {
            System.out.println("主線程:----------------------加鎖之后------------------------");
            System.out.println(ClassLayout.parseInstance(testLock).toPrintable());
        }
    }

運行結果如下:


image.png

說明,偏向鎖不會重新偏向.

/**
     * synchronized關鍵字的底層原理
     * -XX:BiasedLockingStartupDelay=0
     * 證明:
     * 偏向鎖的含義不是只有兩個線程在交替執(zhí)行露懒。
     *
     * 我認為:不管是多少個線程去執(zhí)行闯冷,只要是沒有產生競爭關系
     * 就不會膨脹為輕量級鎖,但是這個是有一些前提的懈词,后面講解窃躲。
     *
     * 結論:不是網上說的只要有第三個線程去執(zhí)行了且沒有產生競爭關系
     * 時就會膨脹為輕量級鎖。
     */
    public static void main(String[] args) throws InterruptedException {

        final Object  testLock=new Object();


        final Thread t1 = new Thread("線程1:"){

            @Override
            public void run() {
                String threadName = Thread.currentThread().getName();
                System.out.println(threadName+"-----------------加鎖前------------------------");
                System.out.println(ClassLayout.parseInstance(testLock).toPrintable());
                synchronized (testLock) {
                    System.out.println(threadName+"-----------------加鎖后--------------------");
                    System.out.println(ClassLayout.parseInstance(testLock).toPrintable());
                }
            }
        };
        t1.start();
        //保證t2在執(zhí)行時不會和t1發(fā)生競爭
        t1.join();

        Thread t2 = new Thread("線程2:"){

            @Override
            public void run() {
                String threadName = Thread.currentThread().getName();
                System.out.println(threadName+"-----------------加鎖前-------------------");
                System.out.println(ClassLayout.parseInstance(testLock).toPrintable());
                synchronized (testLock) {
                    System.out.println(threadName+"-------------------加鎖后------------------");
                    System.out.println(ClassLayout.parseInstance(testLock).toPrintable());
                }
            }
        };
        t2.start();
        t2.join();

        Thread t3 = new Thread("線程3:"){

            @Override
            public void run() {
                String threadName = Thread.currentThread().getName();
                System.out.println(threadName+"-----------------加鎖前--------------------");
                System.out.println(ClassLayout.parseInstance(testLock).toPrintable());
                synchronized (testLock) {
                    System.out.println(threadName+"------------------加鎖后----------------");
                    System.out.println(ClassLayout.parseInstance(testLock).toPrintable());
                }
            }
        };
        t3.start();
        /*t3.join();
        System.out.println("主線程:--------------------------加鎖前----------------------------");
        System.out.println(ClassLayout.parseInstance(testLock).toPrintable());
        synchronized (testLock) {
            System.out.println("主線程:-------------------加鎖后----------------------");
            System.out.println(ClassLayout.parseInstance(testLock).toPrintable());
        }*/
    }

運行結果,以上層序運行結果為,均是偏上線程1 的偏向鎖.即無論多少個線程執(zhí)行,只要沒有競爭關系,都不會膨脹為輕量級鎖.
但是,如果其中一個線程是以上線程的主線程,則主線程加鎖之后會直接變成輕量級鎖.

運行描述:
線程1執(zhí)行同步前,為可偏向無鎖狀態(tài)鎖,
線程1執(zhí)行synchroized后,變成偏向鎖,偏向線程1,
線程1退出同步代碼塊,依然是偏向鎖,偏向線程1,
保持線程1存活,
線程2執(zhí)行synchronized,變成輕量級鎖
線程2執(zhí)行同步結束,釋放鎖,變成不可偏向的無鎖狀態(tài).
線程1此時又進入同步代碼塊,鎖直接變成輕量級鎖.


偏向鎖獲取過程


image.png

其他優(yōu)化:
1)自旋鎖:
互斥同步時,掛起和恢復線程都需要切換到內核態(tài)完成,這對性能并發(fā)帶來了不少的壓力横腿。同時在許多應用上屎媳,共享數(shù)據(jù)的鎖定狀態(tài)只會持續(xù)很短的一段時間垒酬,為了這段較短的時間而去掛起和恢復線程并不值得昌跌。那么如果有多個線程同時并行執(zhí)行污桦,可以讓后面請求鎖的線程通過自旋(CPU忙循環(huán)執(zhí)行空指令)的方式稍等一會兒针肥,看看持有鎖的線程是否會很快的釋放鎖衰抑,這樣就不需要放棄CPU的執(zhí)行時間適應性自旋

       在輕量級鎖獲取過程中象迎,線程執(zhí)行 CAS 操作失敗時,需要通過自旋來獲取重量級鎖呛踊。如果鎖被占的時間比較短砾淌,那么自旋等待的效果就會比較好,而如果鎖占用的時間很長谭网,自旋的線程則會白白浪費 CPU 資源汪厨。解決這個問題的最簡答的辦法就是:指定自旋的次數(shù),如果在限定次數(shù)內還沒獲取到鎖(例如10次)愉择,就按傳統(tǒng)的方式掛起線程進入阻塞狀態(tài)劫乱。JDK1.6 之后引入了自適應性自旋的方式,如果在同一鎖對象上锥涕,一線程自旋等待剛剛成功獲得鎖衷戈,并且持有鎖的線程正在運行中,那么JVM 會認為這次自旋也有可能再次成功獲得鎖层坠,進而允許自旋等待相對更長的時間(例如100次)另一方面殖妇,如果某個鎖自旋很少成功獲得,那么以后要獲得這個鎖時將省略自旋過程破花,以避免浪費 CPU拉一。

2)鎖消除:
鎖消除就是編譯器運行時,對一些被檢測到不可能存在共享數(shù)據(jù)競爭的鎖進行消除旧乞。如果判斷一
段代碼中,堆上的數(shù)據(jù)不會逃逸出去從而被其他線程訪問到磅氨,則可以把他們當做棧上的數(shù)據(jù)對待尺栖,認為它們是線程私有的,不必要加鎖

3)鎖粗化:
鎖粗化就是JVM檢測到一串零碎的操作都對同一個對象加鎖烦租,則會把加鎖同步的范圍粗化到整個操作序列的外部延赌。

批量重偏向問題
子線程創(chuàng)建了同一個類的多個對象并且對這個對象進行了加鎖.
主線程也在這些對象加鎖后,也對這些對象加鎖(沒有發(fā)生競爭加鎖)
因為要執(zhí)行CAS進行線程信息的替換(鎖的升級),那么就會進行多次偏向鎖的撤銷,那么JVM就會認為后面的對象都需要批量重偏向,那么后面的對象就會是加偏向鎖,而不再是輕量級鎖
偏向鎖大量重偏向的門檻(閾值)
intx BiasedLockingBulkRebiasThreshold = 20

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市叉橱,隨后出現(xiàn)的幾起案子挫以,更是在濱河造成了極大的恐慌,老刑警劉巖窃祝,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掐松,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機大磺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門抡句,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人杠愧,你說我怎么就攤上這事待榔。” “怎么了流济?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵锐锣,是天一觀的道長。 經常有香客問我绳瘟,道長雕憔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任稽荧,我火速辦了婚禮橘茉,結果婚禮上,老公的妹妹穿的比我還像新娘姨丈。我一直安慰自己畅卓,他們只是感情好,可當我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布蟋恬。 她就那樣靜靜地躺著翁潘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪歼争。 梳的紋絲不亂的頭發(fā)上拜马,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天,我揣著相機與錄音沐绒,去河邊找鬼俩莽。 笑死,一個胖子當著我的面吹牛乔遮,可吹牛的內容都是我干的扮超。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼蹋肮,長吁一口氣:“原來是場噩夢啊……” “哼出刷!你這毒婦竟也來了?” 一聲冷哼從身側響起坯辩,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤馁龟,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后漆魔,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體坷檩,經...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡却音,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了淌喻。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片僧家。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖裸删,靈堂內的尸體忽然破棺而出八拱,到底是詐尸還是另有隱情,我是刑警寧澤涯塔,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布肌稻,位于F島的核電站,受9級特大地震影響匕荸,放射性物質發(fā)生泄漏爹谭。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一榛搔、第九天 我趴在偏房一處隱蔽的房頂上張望诺凡。 院中可真熱鬧,春花似錦践惑、人聲如沸腹泌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽凉袱。三九已至,卻和暖如春侦铜,著一層夾襖步出監(jiān)牢的瞬間专甩,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工钉稍, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留涤躲,地道東北人。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓贡未,卻偏偏與公主長得像种樱,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子羞秤,可洞房花燭夜當晚...
    茶點故事閱讀 45,691評論 2 361