線程間通信之等待通知機(jī)制

等待/通知機(jī)制

前面部分介紹了Java語(yǔ)言中多線程的使用恨溜,以及方法及變量在同步情況下的處理方式,本節(jié)將介紹多個(gè)線程之間進(jìn)行通信摆寄,通過(guò)本節(jié)的學(xué)習(xí)可以了解到垃环,線程與線程之間不是獨(dú)立的個(gè)體,他們彼此之間可以互相通信和協(xié)作

不使用等待/通知機(jī)制實(shí)現(xiàn)線程間通信

創(chuàng)建項(xiàng)目异赫,在試驗(yàn)中使用sleep()結(jié)合while(true)死循環(huán)法來(lái)實(shí)現(xiàn)多個(gè)線程間通信

代碼為

import java.util.ArrayList;
import java.util.List;
class MyList{
    private List list = new ArrayList();
    public void add(){
        list.add("秦加興");
    }
    public int size(){
        return list.size();
    }
}
//定義線程類ThreadA以及ThreadB
class ThreadA extends Thread{
    private MyList list;

    public ThreadA(MyList list) {
        super();
        this.list = list;
    }
    @Override
    public void run() {
        try {
            for(int i=0;i<10;i++){
                list.add();
                System.out.println("添加了 "+(i+1)+" 個(gè)元素");
                Thread.sleep(500);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

class ThreadB extends Thread{
    private MyList list;

    public ThreadB(MyList list) {
        super();
        this.list = list;
    }
    @Override
    public void run() {
        try {
            System.out.println("-------"+list.size());
            while(true){
                if(list.size()==5){
                    System.out.println("==5了椅挣,線程b要退出了!");
                    throw new InterruptedException();
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }   
    }
}
public class Test1 {
    public static void main(String[] args) {
        MyList service = new MyList();
        ThreadA a = new ThreadA(service);
        a.setName("A");
        a.start();
        ThreadB b = new ThreadB(service);
        b.setName("B");
        b.start();
    }
}

程序云運(yùn)行后出現(xiàn)!](http://upload-images.jianshu.io/upload_images/12188537-aec0ea58f7df4bd0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

解釋:雖然兩個(gè)線程間實(shí)現(xiàn)了通信塔拳,但有一個(gè)弊端就是鼠证,線程ThreadB.java不停的通過(guò)while語(yǔ)句輪詢機(jī)制來(lái)檢測(cè)某一個(gè)條件會(huì)很浪費(fèi)CPU資源

什么是等待/通知機(jī)制

等待/通知機(jī)制在生活中比比皆是,比如在就餐時(shí)就會(huì)出現(xiàn)如圖所示:
就餐時(shí)出現(xiàn)等待通知

廚師和服務(wù)員之間的交互要在“菜品傳遞臺(tái)”上靠抑,在這期間會(huì)有幾個(gè)問(wèn)題

  1. 廚師做完一道菜的時(shí)間不確定量九,所以廚師將菜品放在"菜品傳遞臺(tái)"上的時(shí)間也不確定。
  2. 服務(wù)員取到菜的時(shí)間取決于廚師颂碧,所以服務(wù)員就有“等待”(wait)的狀態(tài)荠列。
  3. 服務(wù)員如何能取到菜呢?這又得取決于廚師载城。廚師將菜放在“菜品傳遞臺(tái)”上肌似,其實(shí)就相當(dāng)于一種通知(notify),這是服務(wù)員才可以拿到菜并交給就餐者诉瓦。
  4. 在這個(gè)過(guò)程中出現(xiàn)了“等待/通知”機(jī)制锈嫩。

需要說(shuō)明一下,前面章節(jié)中多個(gè)線程之間也可以實(shí)現(xiàn)通信垦搬,原因就是多個(gè)線程共同訪問(wèn)同一個(gè)變量呼寸,但那種通信機(jī)制不是“等待/通知”,兩個(gè)線程完全是主動(dòng)式地讀取一個(gè)共享變量,在花費(fèi)讀取時(shí)間的基礎(chǔ)上猴贰,讀到的值是不是想要的对雪,并不能完全確定。所以現(xiàn)在迫切想要一種“等待/通知”機(jī)制來(lái)滿足上面的需求米绕。

等待/通知機(jī)制的實(shí)現(xiàn)

方法wait()的作用

當(dāng)前執(zhí)行代碼的線程進(jìn)行等待瑟捣,wait()方法是Object類的方法馋艺,該方法用來(lái)將當(dāng)前線程置入“預(yù)執(zhí)行隊(duì)列”中,并且在wait()所在的代碼行處停止執(zhí)行迈套,知道街道通知或被中斷為止捐祠。在調(diào)用wait()之前,線程必須獲得該對(duì)象級(jí)別鎖桑李,即只能在同步方法或同步代碼塊中調(diào)用wait()方法踱蛀。 在執(zhí)行wait()方法后,當(dāng)前線程釋放鎖贵白。 在從wait()返回前率拒,線程與其他線程競(jìng)爭(zhēng)重新獲得鎖。如果調(diào)用wait()時(shí)沒(méi)有持有適當(dāng)?shù)逆i禁荒,則拋出IllegalMonitorStateException 猬膨,它是RuntimeException 的一個(gè)子類,因此呛伴,不需要try-catch 語(yǔ)句進(jìn)行捕獲異常勃痴。

方法notify作用

也要在同步方法或同步塊中調(diào)用,即在調(diào)用前热康,線程也必須獲得該對(duì)象的對(duì)象級(jí)別鎖召耘。如果調(diào)用notify()時(shí)沒(méi)有持有適當(dāng)?shù)逆i,也會(huì)拋出IllegalMonitorStateException 褐隆。該方法用來(lái)通知那些可能等待該對(duì)象的對(duì)象鎖的其他線程污它,如果有多個(gè)線程等待,則由線程規(guī)劃器隨機(jī)挑選其中一個(gè)呈wait狀態(tài)的線程庶弃,對(duì)其發(fā)出通知notify衫贬,并使它等待獲取該對(duì)象的對(duì)象鎖。需要說(shuō)明的是歇攻,在執(zhí)行notify()方法后固惯,當(dāng)前線程不會(huì)馬上釋放該對(duì)象鎖, 呈wait狀態(tài)的線程并不能馬上獲取該對(duì)象鎖缴守,要等待執(zhí)行notify()方法的線程將程序執(zhí)行完葬毫,也就是推出synchronized代碼后,當(dāng)前線程才會(huì)釋放鎖屡穗,而成wait狀態(tài)所在的線程才可以獲取該對(duì)象鎖贴捡。當(dāng)?shù)谝粋€(gè)獲得了該對(duì)象鎖的wait線程運(yùn)行完畢之后,它會(huì)釋放掉該對(duì)象鎖村砂,此時(shí)如果該對(duì)象沒(méi)有再次使用notify語(yǔ)句烂斋,則即便該對(duì)象已經(jīng)空閑,其他wait狀態(tài)等待的線程由于咩有得到該對(duì)象的通知,還會(huì)繼續(xù)阻塞在wait狀態(tài)汛骂,知道這個(gè)對(duì)象發(fā)出一個(gè)notify或notifyAll罕模。

  • 用一句話總結(jié)一下wait和notify

wait使線程停止運(yùn)行,而notify使停止的線程繼續(xù)運(yùn)行帘瞭。

wait()和notify()的簡(jiǎn)單使用

package three;
/**
 *輸出: 
開(kāi)始   wait time=1493298291380
開(kāi)始 notify time=1493298294382
結(jié)束 notify time=1493298294383
結(jié)束   wait  time=1493298294384
 * @author jiaxing
 *
 */
//定義兩個(gè)定義線程
class MyThread1 extends Thread{
    private Object lock;

    public MyThread1(Object lock) {
        super();
        this.lock = lock;
    }
    @Override
    public void run() {
        super.run();
        //在線程塊內(nèi)執(zhí)行wait()方法
        try {
            synchronized (lock) {
                System.out.println("開(kāi)始   wait time="+System.currentTimeMillis());
                lock.wait();
                System.out.println("結(jié)束   wait  time="+System.currentTimeMillis());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
class MyThread2 extends Thread{
    private Object lock;

    public MyThread2(Object lock) {
        super();
        this.lock = lock;
    }
    @Override
    public void run() {
        super.run();
        //在線程塊內(nèi)執(zhí)行notify()方法
        synchronized (lock) {
            System.out.println("開(kāi)始 notify time="+System.currentTimeMillis());
            lock.notify();
            System.out.println("結(jié)束 notify time="+System.currentTimeMillis());
        }
    }
}
public class Test2 {
    public static void main(String[] args) {
        try {
            Object lock = new Object();
            //啟動(dòng)兩個(gè)線程
            MyThread1 t1 = new MyThread1(lock);
            t1.start();
            Thread.sleep(3000);
            MyThread2 t2 = new MyThread2(lock);
            t2.start();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

從控制臺(tái)中可以看出3秒后線程被notify通知喚醒

如何使用wait()和notify()來(lái)實(shí)現(xiàn)前面size()等于5呢

  • 看下面例子:
package three;

import java.util.ArrayList;
import java.util.List;
/***
 * 輸出:
wait begin 1493298319090
添加了1個(gè)元素
添加了2個(gè)元素
添加了3個(gè)元素
添加了4個(gè)元素
已發(fā)出通知淑掌!
添加了5個(gè)元素
添加了6個(gè)元素
添加了7個(gè)元素
添加了8個(gè)元素
添加了9個(gè)元素
添加了10個(gè)元素
wait end 1493298329143
 *解釋:日志信息中wait end 在最后輸出,這也說(shuō)明notify()方法執(zhí)行后并不立刻釋放鎖蝶念。這個(gè)知識(shí)點(diǎn)在后面進(jìn)行補(bǔ)充介紹抛腕。
 * @author jiaxing
 *
 */
class MyList3{
    private static List list = new ArrayList(); 
    public static void add(){
        list.add("anything");
    }
    public static int size(){
        return list.size();
    }
}
class ThreadA3 extends Thread{
    private Object lock;
    
    public ThreadA3(Object lock) {
        super();
        this.lock = lock;
    }

    @Override
    public void run() {
        super.run();
        try {
            synchronized(lock){
                if(MyList3.size()!=5){
                    System.out.println("wait begin "+System.currentTimeMillis());
                    lock.wait();
                    System.out.println("wait end "+System.currentTimeMillis());
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
class ThreadB3 extends Thread{
    private Object lock;

    public ThreadB3(Object lock) {
        super();
        this.lock = lock;
    }
    @Override
    public void run() {
        super.run();
        try {
            synchronized (lock) {
                for(int i=0;i<10;i++){
                    MyList3.add();
                    if(MyList3.size()==5){
                        lock.notify();
                        System.out.println("已發(fā)出通知!");
                    }
                    System.out.println("添加了"+(i+1)+"個(gè)元素");
                    Thread.sleep(1000);
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class Test3 {
    public static void main(String[] args) {
        try {
            Object lock = new Object();
            ThreadA3 a = new ThreadA3(lock);
            a.start();
            Thread.sleep(50);
            ThreadB3 b = new ThreadB3(lock);
            b.start();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

  • 關(guān)鍵字synchronized 可以將任何一個(gè)Obejct 對(duì)象作為同步對(duì)象看待祸轮,而java為每個(gè)Object 都實(shí)現(xiàn)了wait()notify() 方法,他們必須在被synchronized 同步的Obejct 的臨界區(qū)內(nèi)侥钳。通過(guò)調(diào)用wait() 方法可以使處于臨界內(nèi)的線程進(jìn)入等待狀態(tài)适袜,同時(shí)釋放被同步對(duì)象的鎖。而notify操作可以喚醒一個(gè)因調(diào)用了wait 操作而處于阻塞狀態(tài)中的線程舷夺,使其進(jìn)入就緒狀態(tài)苦酱。被重新喚醒的線程會(huì)視圖重新獲得臨界區(qū)的控制權(quán),也就是鎖给猾,并繼續(xù)執(zhí)行臨界區(qū)內(nèi)wait 之后的代碼疫萤。如果發(fā)出notify 操作時(shí)沒(méi)有處于阻塞狀態(tài)中的線程,那么該命令會(huì)被忽略敢伸。

  • wait() 方法可以調(diào)用該方法的線程釋放共享資源的鎖扯饶,然后從運(yùn)行狀態(tài)推出,進(jìn)入等待隊(duì)列池颈,知道被再次喚醒尾序。

  • notify() 方法可以隨機(jī)喚醒等待隊(duì)列中等待同一共享資源的“一個(gè)”線程,并使該線程退出等待隊(duì)列躯砰,進(jìn)入可運(yùn)行狀態(tài)每币,也就是notify() 方法僅通知“一個(gè)”線程。

  • notifyAll() 方法可以使所有正在等待隊(duì)列中等待同一共享資源的“全部”線程從等待狀態(tài)退出琢歇,進(jìn)入可運(yùn)行狀態(tài)兰怠。此時(shí),優(yōu)先級(jí)最高的那個(gè)線程最先執(zhí)行李茫,但也有可能是隨機(jī)執(zhí)行揭保,因?yàn)檫@要取決于JVM虛擬機(jī)的實(shí)現(xiàn)。

前面的章節(jié)中已經(jīng)介紹了與Thread有關(guān)的大部分API魄宏,這些API可以改變線程對(duì)象的狀態(tài)掖举,如圖3-7所示
線程狀態(tài)切換示意圖
  1. 新創(chuàng)建一個(gè)新的線程對(duì)象后,再調(diào)用它的start() 方法,系統(tǒng)會(huì)為此線程分配CPU 資
    源塔次,使其處于Runnable(可運(yùn)行) 狀態(tài)方篮,這是一個(gè)準(zhǔn)備運(yùn)行的階段。如果線程搶占到CPU 資
    源励负,此線程就處于Running(運(yùn)行) 狀態(tài)藕溅。

  2. Runnable 狀態(tài)和Running 狀態(tài)可相互切換,因?yàn)橛锌赡芫€程運(yùn)行一段時(shí)間后继榆,有其
    他高優(yōu)先級(jí)的線程搶占了CPU 資源巾表,這時(shí)此線程就從Running 狀態(tài)變成Runnable 狀態(tài)。

線程進(jìn)入Runnable狀態(tài)大致分為如下5中情況:

  • 調(diào)用sleep() 方法后經(jīng)過(guò)的時(shí)間超過(guò)了指定的休眠時(shí)間略吨。
  • 線程調(diào)用的阻塞IO 已經(jīng)返回集币,阻塞方法執(zhí)行完畢。
  • 線程成功地獲得了試圖同步的監(jiān)視器翠忠。
  • 線程正在等待某個(gè)通知鞠苟,其他線程發(fā)出了通知。
  • 處于掛起狀態(tài)的線程調(diào)用了resume 恢復(fù)方法秽之。
  1. Blocked 是阻塞的意思当娱,例如遇到了一個(gè)IO 操作,此時(shí)CPU 處于空閑狀態(tài)考榨,可能會(huì)
    轉(zhuǎn)而把CPU 時(shí)間片分配給其他線程跨细,這時(shí)也可以稱為"暫停"狀態(tài)。Blocked 狀態(tài)結(jié)束后‘
    進(jìn)入Runnable 狀態(tài)河质, 等待系統(tǒng)重新分配資掘冀惭。

出現(xiàn)阻塞的情況大體分為如下5種:

  • 線程調(diào)用sleep 方法, 主動(dòng)放棄占用的處理器資源掀鹅。
  • 線程調(diào)用了阻塞式IO 方法云头,在該方法返回前,該線程被阻塞淫半。
  • 線程試圖獲得一個(gè)同步監(jiān)視器溃槐,但該同步監(jiān)視器正被其他線程所持有。
  • 線程等待某個(gè)通知科吭。
  • 程序調(diào)用了suspend 方法將該線程掛起昏滴。此方法容易導(dǎo)致死鎖,盡量避免使用該方法对人。
  1. run() 方法運(yùn)行結(jié)束后進(jìn)入銷毀階段谣殊, 整個(gè)線程執(zhí)行完畢。

每個(gè)對(duì)象都有兩個(gè)隊(duì)列牺弄,一個(gè)是就緒隊(duì)列姻几,一個(gè)是阻塞隊(duì)列。就緒隊(duì)列存儲(chǔ)了將要獲得鎖的線程,阻塞隊(duì)列存儲(chǔ)了被阻塞的線程蛇捌。一個(gè)線程被喚醒后抚恒,才會(huì)進(jìn)入就緒隊(duì)列,等待CPU的調(diào)度络拌;反之俭驮,一個(gè)線程被wait后,就會(huì)進(jìn)入阻塞隊(duì)列春贸,等待下一次被喚醒混萝。

方法wait()鎖釋放與notify()鎖不釋放

當(dāng)方法wait()被釋放后,鎖被自動(dòng)釋放萍恕,但執(zhí)行完notify()方法逸嘀,鎖卻不自動(dòng)釋放。

  • 看下面的例子展示:
package three;
/***
 * 輸出結(jié)果:
begin wait()
begin wait()
 * @author jiaxing
 *
 */
class Service{
    public void testMethod(Object lock){
        try {
            synchronized (lock) {
                System.out.println("begin wait()");
                //Thread.sleep(4000); 同步效果
                lock.wait();
                System.out.println("   end wait()");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
class ThreadA4 extends Thread{
    private Object lock;

    public ThreadA4(Object lock) {
        super();
        this.lock = lock;
    }
    @Override
    public void run() {
        super.run();
        //實(shí)例化對(duì)象
        Service service = new Service();
        service.testMethod(lock);
    }
}
class ThreadB4 extends Thread{
    private Object lock;

    public ThreadB4(Object lock) {
        super();
        this.lock = lock;
    }
    @Override
    public void run() {
        super.run();
        Service service = new Service();
        service.testMethod(lock);
    }
}
public class Test4 {
    public static void main(String[] args) {
        Object lock = new Object();
        //傳入一個(gè)對(duì)象
        ThreadA4 a = new ThreadA4(lock);
        a.start();
        ThreadB4 b= new ThreadB4(lock);
        b.start();
    }
}

還有一個(gè)實(shí)驗(yàn):方法notify()被執(zhí)行后允粤,不釋放鎖 崭倘,下面看代碼展示:

package three;
/***
 * 輸出
begin wait() ThreadName=Thread-0
begin notify() ThreadName=Thread-2
  end notify() ThreadName=Thread-2
begin notify() ThreadName=Thread-1
  end notify() ThreadName=Thread-1
  end wait() ThreadName=Thread-0
解釋:
結(jié)果顯示:必須執(zhí)行完notify()方法所在的同步synchronized代碼塊后才釋放鎖
 * @author jiaxing
 *
 */
class Service5{
    //多個(gè)通知一個(gè)等待
    public void testMethod(Object lock){
        //等待方法
        try {
            synchronized (lock) {
                System.out.println("begin wait() ThreadName="+Thread.currentThread().getName());
                lock.wait();
                System.out.println("  end wait() ThreadName="+Thread.currentThread().getName());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    //通知notify方法
    public void synNotifyMethod(Object lock){
        try {
            synchronized (lock) {
                System.out.println("begin notify() ThreadName="+Thread.currentThread().getName());
                lock.notify();
                Thread.sleep(5000);
                System.out.println("  end notify() ThreadName="+Thread.currentThread().getName());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
//自定義Thread方法
class ThreadA5 extends Thread{
    private Object lock;

    public ThreadA5(Object lock) {
        super();
        this.lock = lock;
    }
    @Override
    public void run() {
        super.run();
        Service5 service = new Service5();
        service.testMethod(lock);
    }
}
//自定義Thread方法調(diào)用notify方法
class NotifyThread extends Thread{
    private Object lock;

    public NotifyThread(Object lock) {
        super();
        this.lock = lock;
    }
    @Override
    public void run() {
        super.run();
        //實(shí)例化后調(diào)用notify方法
        Service5 service = new Service5();
        service.synNotifyMethod(lock);
    }
}
//自定義SynNotifyThread方法調(diào)用notify方法
class SynNotifyThread extends Thread{
    private Object lock;

    public SynNotifyThread(Object lock) {
        super();
        this.lock = lock;
    }
    @Override
    public void run() {
        super.run();
        //實(shí)例化后調(diào)用notify方法
        Service5 service = new Service5();
        service.synNotifyMethod(lock);
    }
}
//測(cè)試類
public class Test5 {
    public static void main(String[] args) {
        Object lock = new Object();
        //線程a啟動(dòng)  wait方法
        ThreadA5 a = new ThreadA5(lock);
        a.start();
        //線程b啟動(dòng) notify方法
        NotifyThread b = new NotifyThread(lock);
        b.start();
        //線程c啟動(dòng) notify方法
        SynNotifyThread c = new SynNotifyThread(lock);
        c.start();
    }
}

當(dāng)interrupt方法遇到wait方法

  • 當(dāng)線程呈wait() 狀態(tài)時(shí),調(diào)用線程對(duì)象的interrupt() 方法會(huì)出現(xiàn)InterruptedException 異常**维哈。
  • 創(chuàng)建項(xiàng)目后绳姨,測(cè)試部分代碼如下:則當(dāng)程序運(yùn)行后登澜,停止wait狀態(tài)下的線程出現(xiàn)異常
public void main (String[] args){
    try {
        Obejct lock = new Object();
        ThreadA a = new ThreadA(lock);
        a.start();
        Thread.sleep(5000);
        a.interrupted();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

通過(guò)上面的幾個(gè)實(shí)驗(yàn)可以總結(jié)如下3點(diǎn):

  1. 執(zhí)行完同步代碼塊就會(huì)釋放對(duì)象的鎖阔挠。
  2. 在執(zhí)行同步代碼塊的過(guò)程中,遇到異常而導(dǎo)致線程終止脑蠕,鎖也會(huì)被釋放购撼。
  3. 在執(zhí)行同步代碼塊的過(guò)程中,執(zhí)行了鎖所屬對(duì)象的wait() 方法谴仙,這個(gè)線程會(huì)釋放對(duì)象鎖迂求,而此線程對(duì)象會(huì)進(jìn)入線程等待池中,等待被喚醒晃跺。

只通知一個(gè)線程

  • 調(diào)用notify() 一次只隨機(jī) 通知一個(gè)線程揩局;
  • 當(dāng)多次調(diào)用notify()方法時(shí),會(huì)隨機(jī)將等待wait 狀態(tài)的線程進(jìn)行喚醒掀虎。

喚醒所有線程-->notifyAll()方法

  • 只需將之前的代碼中的notify()方法改寫(xiě)成notifyAll()即可凌盯。

方法wait(long)的使用

  • 帶一個(gè)參數(shù)的wait(long)方法的功能是等待某一時(shí)間內(nèi)是否有線程對(duì)鎖進(jìn)行喚醒,如果超過(guò)這個(gè)時(shí)間則自動(dòng)喚醒烹玉。舉例略驰怎。

通知過(guò)早

  • 如果通知過(guò)早,則會(huì)打亂程序正常的運(yùn)行邏輯二打。也即:notify()如果在wait()之前執(zhí)行時(shí)县忌,則會(huì)打亂正常的運(yùn)行邏輯。-->可能會(huì)導(dǎo)致wait()不能被執(zhí)行。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末症杏,一起剝皮案震驚了整個(gè)濱河市装获,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鸳慈,老刑警劉巖饱溢,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異走芋,居然都是意外死亡绩郎,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門翁逞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)肋杖,“玉大人,你說(shuō)我怎么就攤上這事挖函∽粗玻” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵怨喘,是天一觀的道長(zhǎng)津畸。 經(jīng)常有香客問(wèn)我,道長(zhǎng)必怜,這世上最難降的妖魔是什么肉拓? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮梳庆,結(jié)果婚禮上暖途,老公的妹妹穿的比我還像新娘。我一直安慰自己膏执,他們只是感情好驻售,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著更米,像睡著了一般欺栗。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上征峦,一...
    開(kāi)封第一講書(shū)人閱讀 49,772評(píng)論 1 290
  • 那天迟几,我揣著相機(jī)與錄音,去河邊找鬼眶痰。 笑死瘤旨,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的竖伯。 我是一名探鬼主播存哲,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼因宇,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了祟偷?” 一聲冷哼從身側(cè)響起察滑,我...
    開(kāi)封第一講書(shū)人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎修肠,沒(méi)想到半個(gè)月后贺辰,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡嵌施,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年饲化,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吗伤。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡吃靠,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出足淆,到底是詐尸還是另有隱情巢块,我是刑警寧澤,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布巧号,位于F島的核電站族奢,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏丹鸿。R本人自食惡果不足惜越走,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望卜高。 院中可真熱鬧弥姻,春花似錦南片、人聲如沸掺涛。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)薪缆。三九已至,卻和暖如春伞广,著一層夾襖步出監(jiān)牢的瞬間拣帽,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工嚼锄, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留减拭,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓区丑,卻偏偏與公主長(zhǎng)得像拧粪,于是被迫代替她去往敵國(guó)和親修陡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348