三、Java并發(fā)編程基礎(chǔ)

轉(zhuǎn):《Java并發(fā)編程的藝術(shù)》

1 線程簡介

現(xiàn)代操作系統(tǒng)在運(yùn)行一個(gè)程序時(shí)狡汉,會(huì)為其創(chuàng)建一個(gè)進(jìn)程娄徊。例如,啟動(dòng)一個(gè)Java程序盾戴,操作
系統(tǒng)就會(huì)創(chuàng)建一個(gè)Java進(jìn)程〖娜瘢現(xiàn)代操作系統(tǒng)調(diào)度的最小單元是線程,也叫輕量級(jí)進(jìn)程(Light Weight Process)尖啡,在一個(gè)進(jìn)程里可以創(chuàng)建多個(gè)線程橄仆,這些線程都擁有各自的計(jì)數(shù)器、堆棧和局部變量等屬性衅斩,并且能夠訪問共享的內(nèi)存變量盆顾。處理器在這些線程上高速切換,讓使用者感覺到這些線程在同時(shí)執(zhí)行畏梆。

2 線程優(yōu)先級(jí)

現(xiàn)代操作系統(tǒng)基本采用時(shí)分的形式調(diào)度運(yùn)行的線程您宪, 操作系統(tǒng)會(huì)分出一個(gè)個(gè)時(shí)間片奈懒, 線程會(huì)分配到若干時(shí)間片, 當(dāng)線程的時(shí)間片用完了就會(huì)發(fā)生線程調(diào)度宪巨, 并等待著下次分配磷杏。 線程分配到的時(shí)間片多少也就決定了線程使用處理器資源的多少, 而線程優(yōu)先級(jí)就是決定線程需要多或者少分配一些處理器資源的線程屬性捏卓。

在Java線程中极祸,通過一個(gè)整型成員變量priority來控制優(yōu)先級(jí), 優(yōu)先級(jí)的范圍從1~10怠晴, 在線程構(gòu)建的時(shí)候可以通過setPriority(int)方法來修改優(yōu)先級(jí)贿肩, 默認(rèn)優(yōu)先級(jí)是5, 優(yōu)先級(jí)高的線程分配時(shí)間片的數(shù)量要多于優(yōu)先級(jí)低的線程龄寞。 設(shè)置線程優(yōu)先級(jí)時(shí), 針對(duì)頻繁阻塞(休眠或者I/O操作) 的線程需要設(shè)置較高優(yōu)先級(jí)汤功, 而偏重計(jì)算(需要較多CPU時(shí)間或者偏運(yùn)算) 的線程則設(shè)置較低的優(yōu)先級(jí)物邑, 確保處理器不會(huì)被獨(dú)占。 在不同的JVM以及操作系統(tǒng)上滔金, 線程規(guī)劃會(huì)存在差異色解,有些操作系統(tǒng)甚至?xí)雎詫?duì)線程優(yōu)先級(jí)的設(shè)定(因此,在程序中設(shè)置線程優(yōu)先級(jí)的實(shí)踐意義并不大餐茵,因?yàn)榫€程優(yōu)先級(jí)的最終解釋權(quán)在底層操作系統(tǒng))科阎。

3 并發(fā)與并行的區(qū)別

如果某個(gè)系統(tǒng)支持兩個(gè)或者多個(gè)操作(Action)同時(shí)存在,那么這個(gè)系統(tǒng)就是一個(gè)并發(fā)系統(tǒng)忿族。如果某個(gè)系統(tǒng)支持兩個(gè)或者多個(gè)動(dòng)作同時(shí)執(zhí)行锣笨,那么這個(gè)系統(tǒng)就是一個(gè)并行系統(tǒng)。并發(fā)系統(tǒng)與并行系統(tǒng)這兩個(gè)定義之間的關(guān)鍵差異在于“存在”這個(gè)詞道批。

在并發(fā)程序中可以同時(shí)擁有兩個(gè)或者多個(gè)線程错英。這意味著,如果程序在單核處理器上運(yùn)行隆豹,那么這兩個(gè)線程將交替地?fù)Q入或者換出內(nèi)存椭岩。這些線程是同時(shí)“存在”的——每個(gè)線程都處于執(zhí)行過程中的某個(gè)狀態(tài)如果程序能夠并行執(zhí)行璃赡,那么就一定是運(yùn)行在多核處理器上判哥。此時(shí),程序中的每個(gè)線程都將分配到一個(gè)獨(dú)立的處理器核上碉考,因此可以同時(shí)運(yùn)行塌计。

“并行”概念是“并發(fā)”概念的一個(gè)子集。也就是說侯谁,你可以編寫一個(gè)擁有多個(gè)線程或者進(jìn)程的并發(fā)程序夺荒,但如果沒有多核處理器來執(zhí)行這個(gè)程序瞒渠,那么就不能以并行方式來運(yùn)行代碼。因此技扼,凡是在求解單個(gè)問題時(shí)涉及多個(gè)執(zhí)行流程的編程模式或者執(zhí)行行為伍玖,都屬于并發(fā)編程的范疇。

用一個(gè)極其簡單的生活實(shí)例來解釋如下:
  你吃飯吃到一半剿吻,電話來了窍箍,你一直到吃完了以后才去接,這就說明你不支持并發(fā)也不支持并行丽旅。
  你吃飯吃到一半椰棘,電話來了,你停了下來接了電話榄笙,接完后繼續(xù)吃飯邪狞,這說明你支持并發(fā)。
  你吃飯吃到一半茅撞,電話來了帆卓,你一邊打電話一邊吃飯,這說明你支持并行米丘。
  并發(fā)的關(guān)鍵是你有處理多個(gè)任務(wù)的能力剑令,不一定要同時(shí)。并行的關(guān)鍵是你有同時(shí)處理多個(gè)任務(wù)的能力拄查。

4 線程狀態(tài)及其切換

下面的這個(gè)圖非常重要吁津!你如果看懂了這個(gè)圖,那么對(duì)于多線程的理解將會(huì)更加深刻堕扶。


  1. 新建狀態(tài)(New):新創(chuàng)建了一個(gè)線程對(duì)象碍脏。
  2. 就緒狀態(tài)(Runnable):線程對(duì)象創(chuàng)建后,其他線程調(diào)用了該對(duì)象的start()方法稍算。該狀態(tài)的線程位于可運(yùn)行線程隊(duì)列中潮酒,變得可運(yùn)行,等待獲取CPU的使用權(quán)邪蛔。
  3. 運(yùn)行狀態(tài)(Running):就緒狀態(tài)的線程獲取了CPU急黎,執(zhí)行程序代碼。
  4. 阻塞狀態(tài)(Blocked):阻塞狀態(tài)是線程因?yàn)槟撤N原因放棄CPU使用權(quán)侧到,暫時(shí)停止運(yùn)行勃教。直到線程進(jìn)入就緒狀態(tài),才有機(jī)會(huì)再次轉(zhuǎn)到運(yùn)行狀態(tài)匠抗。

阻塞的情況分三種:
等待阻塞:運(yùn)行的線程執(zhí)行wait()方法故源,JVM會(huì)把該線程放入等待池中(wait會(huì)釋放持有的鎖)
同步阻塞:運(yùn)行的線程在獲取對(duì)象的同步鎖時(shí)汞贸,若該同步鎖被別的線程占用绳军,則JVM會(huì)把該線程放入鎖池中印机。
其他阻塞運(yùn)行的線程執(zhí)行sleep()或join()方法,或者發(fā)出了I/O請(qǐng)求時(shí)门驾,JVM會(huì)把該線程置為阻塞狀態(tài)射赛。當(dāng)sleep()狀態(tài)超時(shí)它改、join()等待線程終止或者超時(shí)呼股、或者I/O處理完畢時(shí)陈轿,線程重新轉(zhuǎn)入就緒狀態(tài)(注意岸军,sleep不會(huì)釋放線程所持有的鎖)

  1. 死亡狀態(tài)(Dead):線程執(zhí)行完了或者因異常退出了run()方法怀泊,該線程結(jié)束生命周期本砰。

Java線程在運(yùn)行的生命周期中可能處于下圖表中所示的6種不同的狀態(tài)蜒蕾, 在給定的一個(gè)時(shí)刻及汉,線程只能處于其中的一個(gè)狀態(tài)沮趣。

下面使用jstack工具(可以選擇打開終端, 鍵入jstack或者到JDK安裝目錄的bin目錄下執(zhí)行命令)坷随, 嘗試查看示例代碼運(yùn)行時(shí)的線程信息房铭, 更加深入地理解線程狀態(tài)。測試代碼如下:

public class ThreadState {
    // 該線程不斷地進(jìn)行睡眠
    static class TimeWaiting implements Runnable {
        @Override
        public void run() {
            while (true) {
                SleepUtils.second(100);
            }
        }
    }

    // 該線程在Waiting.class實(shí)例上等待
    static class Waiting implements Runnable {
        @Override
        public void run() {
            while (true) {
                synchronized (Waiting.class) {
                    try {
                        Waiting.class.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    // 該線程在Blocked.class實(shí)例上加鎖后甸箱, 不會(huì)釋放該鎖
    static class Blocked implements Runnable {
        @Override
        public void run() {
            synchronized (Blocked.class) {
                while (true) {
                    SleepUtils.second(100);
                }
            }
        }
    }

    public static void main(String[] args) {
        new Thread(new TimeWaiting (), "TimeWaitingThread").start();
        new Thread(new Waiting(), "WaitingThread").start();
        // 使用兩個(gè)Blocked線程, 一個(gè)獲取鎖成功迅脐, 另一個(gè)被阻塞
        new Thread(new Blocked(), "BlockedThread-1").start();
        new Thread(new Blocked(), "BlockedThread-2").start();
    }
}

上述示例中使用的SleepUtils代碼如下:

public class SleepUtils {

    public static final void second(long seconds) {
        try {
            TimeUnit.SECONDS.sleep(seconds) ;
        } catch (InterruptedException e) {
        }
    }
}

運(yùn)行該示例芍殖, 打開終端或者命令提示符, 鍵入“jps”谴蔑, 輸出如下:

16544 Jps
13700
10156 ThreadState

可以看到運(yùn)行示例對(duì)應(yīng)的進(jìn)程ID是10156豌骏,接著再輸入“jstack 10156”,部分輸出如下:

//BlockedThread-2線程阻塞在獲取Blocked.class示例的鎖上
"BlockedThread-2" #13 prio=5 os_prio=0 tid=0x00000000180ad800 nid=0x108c waiting for monitor entry [0x0000000018e8f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at ThreadState$Blocked.run(ThreadState.java:35)
        - waiting to lock <0x00000000e01e4db0> (a java.lang.Class for ThreadState$Blocked)
        at java.lang.Thread.run(Thread.java:745)
//BlockedThread-1線程獲取到了Blocked.class的鎖隐锭,處于睡眠狀態(tài)
"BlockedThread-1" #12 prio=5 os_prio=0 tid=0x00000000180ad000 nid=0x2740 waiting on condition [0x0000000018d8e000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
        at java.lang.Thread.sleep(Native Method)
        at java.lang.Thread.sleep(Thread.java:340)
        at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
        at SleepUtils.second(SleepUtils.java:6)
        at ThreadState$Blocked.run(ThreadState.java:35)
        - locked <0x00000000e01e4db0> (a java.lang.Class for ThreadState$Blocked)
        at java.lang.Thread.run(Thread.java:745)
//WaitingThread線程在Waitting實(shí)例上等待
"WaitingThread" #11 prio=5 os_prio=0 tid=0x00000000180a6000 nid=0x93c in Object.wait() [0x0000000018c8f000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x00000000e01e37c0> (a java.lang.Class for ThreadState$Waiting)
        at java.lang.Object.wait(Object.java:502)
        at ThreadState$Waiting.run(ThreadState.java:21)
        - locked <0x00000000e01e37c0> (a java.lang.Class for ThreadState$Waiting)
        at java.lang.Thread.run(Thread.java:745)
//TimeWaitingThread線程處于超時(shí)等待
"TimeWaitingThread" #10 prio=5 os_prio=0 tid=0x00000000180a5000 nid=0x8c4 waiting on condition [0x0000000018b8f000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
        at java.lang.Thread.sleep(Native Method)
        at java.lang.Thread.sleep(Thread.java:340)
        at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
        at SleepUtils.second(SleepUtils.java:6)
        at ThreadState$TimeWaiting.run(ThreadState.java:8)
        at java.lang.Thread.run(Thread.java:745)

通過示例窃躲, 我們了解到Java程序運(yùn)行中線程狀態(tài)的具體含義。 線程在自身的生命周期中钦睡,并不是固定地處于某個(gè)狀態(tài)蒂窒, 而是隨著代碼的執(zhí)行在不同的狀態(tài)之間進(jìn)行切換。

下面是一張更詳細(xì)的線程狀態(tài)遷移圖:

從圖中可以看到荞怒, 線程創(chuàng)建之后洒琢, 調(diào)用start()方法開始運(yùn)行(這里的運(yùn)行狀態(tài)其實(shí)是就緒態(tài)和運(yùn)行態(tài)的合集)。 當(dāng)線程執(zhí)行wait()方法之后褐桌, 線程進(jìn)入等待狀態(tài)衰抑。 進(jìn)入等待狀態(tài)的線程需要依靠其他線程的通知才能夠返回到運(yùn)行狀態(tài), 而超時(shí)等待狀態(tài)相當(dāng)于在等待狀態(tài)的基礎(chǔ)上增加了超時(shí)限制荧嵌, 也就是超時(shí)時(shí)間到達(dá)時(shí)將會(huì)返回到運(yùn)行狀態(tài)呛踊。 當(dāng)線程調(diào)用同步方法時(shí)砾淌, 在沒有獲取到鎖的情況下, 線程將會(huì)進(jìn)入到阻塞狀態(tài)谭网。 線程在執(zhí)行Runnable的run()方法之后將會(huì)進(jìn)入到終止?fàn)顟B(tài)汪厨。

注意:阻塞狀態(tài)是線程在進(jìn)入synchronized關(guān)鍵字修飾的方法或代碼塊(嘗試獲取鎖) 時(shí)沒有拿到鎖的狀態(tài),但是阻塞在java.concurrent包中Lock接口 的線程狀態(tài)卻是等待狀態(tài)蜻底, 因?yàn)閖ava.concurrent包中 Lock接口對(duì)于阻塞的實(shí)現(xiàn)均使用了LockSupport類中的相關(guān)方法骄崩。

5 線程的啟動(dòng)、中斷與終止

線程對(duì)象在初始化完成之后薄辅, 調(diào)用start()方法就可以啟動(dòng)這個(gè)線程要拂。 線程start()方法的含義是: 當(dāng)前線程(即parent線程) 同步告知Java虛擬機(jī), 只要線程規(guī)劃器空閑站楚, 應(yīng)立即啟動(dòng)調(diào)用start()方法的線程脱惰。

注意:啟動(dòng)一個(gè)線程前, 最好為這個(gè)線程設(shè)置線程名 稱窿春, 因?yàn)檫@樣在使用jstack分析程序或者進(jìn)行問題排查時(shí)拉一, 就會(huì)給開發(fā)人員提供一些提示, 自定義的線程最好能夠起個(gè)名字旧乞。

中斷可以理解為線程的一個(gè)標(biāo)識(shí)位屬性蔚润, 它表示一個(gè)運(yùn)行中的線程是否被其他線程進(jìn)行了中斷操作。 中斷好比其他線程對(duì)該線程打了個(gè)招呼尺栖, 其他線程通過調(diào)用該線程的interrupt()方法對(duì)其進(jìn)行中斷操作嫡纠。

線程通過檢查自身是否被中斷來進(jìn)行響應(yīng), 線程通過方法isInterrupted()來進(jìn)行判斷是否被中斷延赌, 也可以調(diào)用靜態(tài)方法Thread.interrupted()對(duì)當(dāng)前線程的中斷標(biāo)識(shí)位進(jìn)行復(fù)位除盏。 如果該線程已經(jīng)處于終結(jié)狀態(tài), 即使該線程被中斷過挫以, 在調(diào)用該線程對(duì)象的isInterrupted()時(shí)依舊會(huì)返回false者蠕。

調(diào)用某個(gè)線程的interrupt()方法,將會(huì)設(shè)置該線程為中斷狀態(tài)掐松,即設(shè)置為true踱侣。線程中斷后的結(jié)果是死亡、還是等待新的任務(wù)或是繼續(xù)運(yùn)行至下一步大磺,取決于這個(gè)程序本身泻仙。線程可以不時(shí)地檢測這個(gè)中斷標(biāo)識(shí)位,以判斷線程是否應(yīng)該被中斷(中斷標(biāo)志是否為true)量没。它并不像stop方法那樣會(huì)真的會(huì)粗暴地打斷一個(gè)正在運(yùn)行的線程玉转。

從Java的API中可以看到, 有許多聲明拋出InterruptedException的方法(例如Thread.sleep(long millis)方法)殴蹄, 這些方法在拋出InterruptedException之前究抓, Java虛擬機(jī)會(huì)先將該線程的中斷標(biāo)識(shí)位清除猾担, 然后拋出InterruptedException, 此時(shí)調(diào)用isInterrupted()方法將會(huì)返回false刺下。

測試代碼如下绑嘹,首先創(chuàng)建了兩個(gè)線程, SleepThread和BusyThread橘茉, 前者不停地睡眠工腋, 后者一直運(yùn)行, 然后對(duì)這兩個(gè)線程分別進(jìn)行中斷操作畅卓, 觀察二者的中斷標(biāo)識(shí)位擅腰。

public class Interrupted {

    public static void main(String[ ] args) throws Exception {
        // sleepThread不停的嘗試睡眠
        Thread sleepThread = new Thread(new SleepRunner() , "SleepThread");
        sleepThread.setDaemon(true);
        // busyThread不停的運(yùn)行
        Thread busyThread = new Thread(new BusyRunner() , "BusyThread");
        busyThread.setDaemon(true);
        sleepThread.start();
        busyThread.start();

        // 休眠5秒, 讓sleepThread和busyThread充分運(yùn)行
        TimeUnit.SECONDS.sleep(5);
        sleepThread.interrupt();
        busyThread.interrupt();
        System.out.println("SleepThread interrupted is " + sleepThread.isInterrupted());
        System.out.println("BusyThread interrupted is " + busyThread.isInterrupted());

        // 防止sleepThread和busyThread立刻退出
        SleepUtils. second(2);

    }

    static class SleepRunner implements Runnable {
        @Override
        public void run() {
            while (true) {
                SleepUtils. second(10) ;
            }
        }
    }

    static class BusyRunner implements Runnable {
        @Override
        public void run() {
            while (true) {

            }
        }   
    }
}

輸出如下:

SleepThread interrupted is false
BusyThread interrupted is true

從結(jié)果可以看出翁潘, 拋出InterruptedException的線程SleepThread趁冈, 其中斷標(biāo)識(shí)位被清除了,而一直忙碌運(yùn)作的線程BusyThread拜马, 中斷標(biāo)識(shí)位沒有被清除渗勘。

中斷狀態(tài)是線程的一個(gè)標(biāo)識(shí)位, 而中斷操作是一種簡便的線程間交互方式俩莽, 而這種交互方式最適合用來取消或停止任務(wù)旺坠。 除了中斷以外, 還可以利用一個(gè)boolean共享變量來控制是否需要停止任務(wù)并終止該線程扮超,這是最受推薦的終止一個(gè)線程(就是讓一個(gè)線程徹底停止運(yùn)行)的方式取刃,使用共享變量(shared variable)來發(fā)出信號(hào),告訴線程必須停止正在運(yùn)行的任務(wù)瞒津。線程必須周期性的核查這一變量蝉衣,然后有秩序地停止任務(wù)括尸。測試代碼如下:

public class Shutdown {

    public static void main(String[ ] args) throws Exception {
        Runner one = new Runner() ;
        Thread countThread = new Thread(one, "CountThread") ;
        countThread.start() ;

        // 睡眠1秒巷蚪,main線程對(duì)Runner one進(jìn)行中斷, 使CountThread能夠感知中斷標(biāo)識(shí)位的置位而結(jié)束
        TimeUnit.SECONDS.sleep(1) ;
        countThread.interrupt() ;
        Runner two = new Runner() ;
        countThread = new Thread(two, "CountThread") ;
        countThread.start() ;
        // 睡眠1秒濒翻,main線程對(duì)Runner two進(jìn)行取消屁柏, 使CountThread能夠感知on為false而結(jié)束
        TimeUnit.SECONDS.sleep(1) ;
        two.cancel() ;
    }

    private static class Runner implements Runnable {

        private long i;
        private volatile boolean on = true;

        @Override
        public void run() {
            while (on && ! Thread.currentThread().isInterrupted()) {
                i++;
            }
            System.out.println("Count i = " + i);
        }

        public void cancel() {
            on = false; 
        }
    }       
}

輸出結(jié)果如下(多次運(yùn)行結(jié)果可能不同):

Count i = 543487324
Count i = 540898082

示例在執(zhí)行過程中, main線程通過中斷操作和cancel()方法均可使CountThread得以終止有送。這種通過標(biāo)識(shí)位或者中斷操作的方式能夠使線程在終止時(shí)有機(jī)會(huì)去清理資源淌喻, 而不是武斷地將線程停止, 因此這種終止線程的做法顯得更加安全和優(yōu)雅雀摘。

注意:suspend()裸删、resume()和stop()方法也可以完成線程的暫停、恢復(fù)和終止工作阵赠,而且非逞乃“人性化”肌稻。但是這些API是過期的,也就是不建議使用的匕荸。
不建議使用的原因主要有:以suspend()方法為例爹谭,在調(diào)用后,線程不會(huì)釋放已經(jīng)占有的資源(比如鎖)榛搔,而是占有著資源進(jìn)入睡眠狀態(tài)诺凡,這樣容易引發(fā)死鎖問題。同樣践惑,stop()方法在終結(jié)一個(gè)線程時(shí)不會(huì)保證線程的資源正常釋放腹泌,通常是沒有給予線程完成資源釋放工作的機(jī)會(huì),因此會(huì)導(dǎo)致程序可能工作在不確定狀態(tài)下童本。
正因?yàn)閟uspend()真屯、resume()和stop()方法帶來的副作用,這些方法才被標(biāo)注為不建議使用的過期方法穷娱,而暫停和恢復(fù)操作可以用后面提到的等待/通知機(jī)制來替代绑蔫。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市泵额,隨后出現(xiàn)的幾起案子配深,更是在濱河造成了極大的恐慌,老刑警劉巖嫁盲,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件篓叶,死亡現(xiàn)場離奇詭異,居然都是意外死亡羞秤,警方通過查閱死者的電腦和手機(jī)缸托,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瘾蛋,“玉大人俐镐,你說我怎么就攤上這事〔负撸” “怎么了佩抹?”我有些...
    開封第一講書人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長取董。 經(jīng)常有香客問我棍苹,道長,這世上最難降的妖魔是什么茵汰? 我笑而不...
    開封第一講書人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任枢里,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘栏豺。我一直安慰自己梭灿,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開白布冰悠。 她就那樣靜靜地躺著堡妒,像睡著了一般。 火紅的嫁衣襯著肌膚如雪溉卓。 梳的紋絲不亂的頭發(fā)上皮迟,一...
    開封第一講書人閱讀 52,246評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音桑寨,去河邊找鬼伏尼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛尉尾,可吹牛的內(nèi)容都是我干的爆阶。 我是一名探鬼主播,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼沙咏,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼辨图!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起肢藐,我...
    開封第一講書人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤故河,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后吆豹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鱼的,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年痘煤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了凑阶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡衷快,死狀恐怖宙橱,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情烦磁,我是刑警寧澤养匈,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布哼勇,位于F島的核電站都伪,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏积担。R本人自食惡果不足惜陨晶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧先誉,春花似錦湿刽、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至铃芦,卻和暖如春雅镊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背刃滓。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來泰國打工仁烹, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人咧虎。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓卓缰,卻偏偏與公主長得像,于是被迫代替她去往敵國和親砰诵。 傳聞我的和親對(duì)象是個(gè)殘疾皇子征唬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359

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