Java并發(fā)系列—并發(fā)編程基礎(chǔ)

特別說(shuō)明:文章內(nèi)容是《Java并發(fā)編程的藝術(shù)》讀書筆記

Java是一種多線程語(yǔ)言,從誕生開始就內(nèi)置了對(duì)多線程的支持。正確地使用多線程可以顯著提高程序性能鞍历,但過(guò)多地創(chuàng)建線程和對(duì)線程的不當(dāng)管理也很容易造成問(wèn)題毒涧。

線程簡(jiǎn)介

線程定義

現(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)程荷愕,在一個(gè)進(jìn)程里可以創(chuàng)建多個(gè)線程衡怀,這些線程都擁有各自的計(jì)算器、堆棧和局部變量等屬性安疗,并且能夠訪問(wèn)共享的內(nèi)存變量抛杨。處理器在這些線程上高速切換,讓使用者感覺到這些線程在同時(shí)執(zhí)行荐类。

Java程序天生就是多線程程序蝶桶,可以通過(guò)JMX查看一個(gè)普通的Java程序包含那些線程,代碼如下:

public class MutilThread {

    public static void main(String[] args) {
        // 獲取Java線程管理MXBean
        ThreadMXBean threadMXBean =  ManagementFactory.getThreadMXBean();
        // 獲取線程和線程堆棧信息
        ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false,false);
        // 遍歷線程線程掉冶,僅打印線程ID和線程名稱信息
        for(ThreadInfo threadInfo:threadInfos){
            System.out.println("["+threadInfo.getThreadId()+"]"+threadInfo.getThreadName());
        }
    }
}

運(yùn)行結(jié)果如下:

一個(gè)普通的Java程序包含那些線程

使用多線程的原因

正確使用多線程真竖,總是能夠給開發(fā)人員帶來(lái)顯著的好處脐雪,而使用多線程的原因主要有以下幾點(diǎn):

1、更多的處理器核心

隨著處理器上的核心數(shù)量越來(lái)越多恢共,以及超線程技術(shù)的廣泛運(yùn)用战秋,現(xiàn)在大多數(shù)計(jì)算機(jī)都比以往更加擅長(zhǎng)并行計(jì)算,而處理器性能的提升方式讨韭,也從更高的主頻向更多的核心發(fā)展脂信。

2、更快的響應(yīng)時(shí)間

有時(shí)我們會(huì)編寫一些業(yè)務(wù)邏輯比較復(fù)雜的代碼透硝,例如狰闪,一筆訂單的創(chuàng)建,它包括插入訂單數(shù)據(jù)濒生、生成訂單快照埋泵、發(fā)送郵件通知賣家和記錄貨品銷售數(shù)量等。用戶從單擊“訂購(gòu)”按鈕開始罪治,就要等待這些操作全部完成才能看到訂購(gòu)成功的結(jié)果丽声。但是這么多業(yè)務(wù)操作,如何能夠讓其更快地完成呢觉义?

在上面的場(chǎng)景中雁社,可以使用多線程技術(shù),即將數(shù)據(jù)一致性不強(qiáng)的操作派發(fā)給其他線程處理(也可以使用消息隊(duì)列)晒骇,如生成訂單快照霉撵、發(fā)送郵件等。這樣做的好處是響應(yīng)用戶請(qǐng)求的線程能夠盡可能快地處理完成洪囤,縮短了響應(yīng)時(shí)間徒坡,提升了用戶體驗(yàn)。

3箍鼓、 更好的編程模型

Java為多線程編程提供了一致的編程模型,使開發(fā)人員能夠更加專注于問(wèn)題的解決呵曹,即為所遇到的問(wèn)題建立合適的模型款咖,而不是絞盡腦汁地考慮如何將其多線程化。

線程優(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線程中赘被,通過(guò)一個(gè)整型成員變量priority來(lái)控制優(yōu)先級(jí)是整,優(yōu)先級(jí)的范圍從1~10,在線程構(gòu)建的時(shí)候可以通過(guò)setPriority(int)方法來(lái)修改優(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ú)占野舶。

注意:線程優(yōu)先級(jí)不能作為程序正確性的依賴易迹,因?yàn)椴僮飨到y(tǒng)可以完全不用理會(huì)Java線程對(duì)于優(yōu)先級(jí)的設(shè)定。

線程的狀態(tài)

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

狀態(tài)名稱 說(shuō)明
NEW 初始狀態(tài)巢掺,線程被構(gòu)建句伶,但是還沒有調(diào)用start()方法
RUNNABLE 運(yùn)行狀態(tài),Java線程將操作系統(tǒng)中的就緒和運(yùn)行兩種狀態(tài)籠統(tǒng)地稱作“運(yùn)行中”
BLOCKED 阻塞狀態(tài)陆淀,表示線程阻塞于鎖
WAITING 等待狀態(tài)考余,表示線程進(jìn)入等待狀態(tài),進(jìn)入該狀態(tài)表示當(dāng)前線程需要等待其他線程做出一些特定動(dòng)作(通知或中斷)
TIME_WAITING 超時(shí)等待狀態(tài)轧苫,該狀態(tài)不同于WAITING楚堤,它是可以在指定的時(shí)間自行返回的
TERMINATED 終止?fàn)顟B(tài),表示當(dāng)前線程已經(jīng)執(zhí)行完畢

線程在自身的生命周期中含懊,并不是固定地處于某個(gè)狀態(tài)身冬,而是隨著代碼的執(zhí)行在不同的狀態(tài)之間進(jìn)行切換,Java線程狀態(tài)變遷如下圖:

Java線程狀態(tài)變遷

Java將操作系統(tǒng)中的運(yùn)行和就緒兩個(gè)狀態(tài)合并稱為運(yùn)行狀態(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)方法雏门。

Daemon線程

Daemon線程是一種支持型線程嘿歌,因?yàn)樗饕挥米鞒绦蛑泻笈_(tái)調(diào)度以及支持性工作。當(dāng)一個(gè)Java虛擬機(jī)中不存在非Daemon線程的時(shí)候茁影,Java虛擬機(jī)將會(huì)退出宙帝。可以通過(guò)調(diào)用Thread.setDaemon(true)將線程設(shè)置為Daemon線程募闲。Daemon屬性需要在啟動(dòng)線程之前設(shè)置步脓,不能在啟動(dòng)線程之后設(shè)置

在構(gòu)建Daemon線程時(shí),不能依靠finally塊中的內(nèi)容來(lái)確保執(zhí)行關(guān)閉或清理資源的邏輯靴患。如下代碼:

public class Daemon {

    public static void main(String[] args) {
        Thread thread = new Thread(new DeamonRunner(),"DeamonRunner");
        thread.setDaemon(true);
        thread.start();
    }

    static class DeamonRunner implements Runnable{

        @Override
        public void run() {
            try {
                Thread.sleep(2000l);
            } catch (InterruptedException e) {
                //
            }finally {
                System.out.println("DeamonThread finally run.");
            }
        }
    }
}

運(yùn)行Deamon程序仍侥,可以看到在終端或者命令提示符沒有任何輸出。

啟動(dòng)線程

在運(yùn)行線程之前首先要構(gòu)造一個(gè)線程對(duì)象蚁廓,線程對(duì)象在構(gòu)造的時(shí)候需要提供線程所需要的屬性访圃,如線程所屬的線程組、線程優(yōu)先級(jí)相嵌、是否是Daemon線程等信息腿时。

private void init(ThreadGroup g, Runnable target, String name,long stackSize,AccessControlContext acc) {
    if (name == null) {
        throw new NullPointerException("name cannot be null");
    }
    // 當(dāng)前線程就是該線程的父線程
    Thread parent = currentThread();
    this.group = g;
    // 將daemon、priority屬性設(shè)置為父線程的對(duì)應(yīng)屬性
    this.daemon = parent.isDaemon();
    this.priority = parent.getPriority();
    this.name = name.toCharArray();
    this.target = target;
    setPriority(priority);
    // 將父線程的InheritableThreadLocal復(fù)制過(guò)來(lái)
    if (parent.inheritableThreadLocals != null)
        this.inheritableThreadLocals=ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
    // 分配一個(gè)線程ID
    tid = nextThreadID();
}

在上述過(guò)程中饭宾,一個(gè)新構(gòu)造的線程對(duì)象是由其parent線程來(lái)進(jìn)行空間分配的批糟,而child線程繼承了parent是否為Deamon、優(yōu)先級(jí)和加載資源的ContextClassLoader以及可繼承的ThreadLocal看铆,同時(shí)還會(huì)分配一個(gè)唯一的ID來(lái)標(biāo)識(shí)這個(gè)child線程徽鼎。

線程對(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)行問(wèn)題排查時(shí)助泽,就會(huì)給開發(fā)人員提供一些提示啰扛,自定義的線程最好能夠起個(gè)名字。

理解中斷

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

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

從Java的API中可以看到炸宵,許多聲明拋出InterruptedException的方法(例如Thread.sleep(longmillis)方法)這些方法在拋出InterruptedException之前辟躏,Java虛擬機(jī)會(huì)先將該線程的中斷標(biāo)識(shí)位清除谷扣,然后拋出InterruptedException,此時(shí)調(diào)用isInterrupted()方法將會(huì)返回false。

過(guò)期的suspend()会涎、resume()和stop()

suspend()裹匙、resume()和stop()方法完成了線程的暫停、恢復(fù)和終止工作末秃,而且非掣乓常“人性化”。但是這些API是過(guò)期的练慕,也就是不建議使用的惰匙。

不建議使用的原因主要有:以suspend()方法為例,在調(diào)用后铃将,線程不會(huì)釋放已經(jīng)占有的資源(比如鎖)项鬼,而是占有著資源進(jìn)入睡眠狀態(tài),這樣容易引發(fā)死鎖問(wèn)題劲阎。同樣绘盟,stop()方法在終結(jié)一個(gè)線程時(shí)不保證線程的資源正常釋放,通常是沒有給予線程完成資源釋放工作的機(jī)會(huì)悯仙,因此會(huì)導(dǎo)致程序可能工作在不確定狀態(tài)下龄毡。

因?yàn)閟uspend()、resume()和stop()方法帶來(lái)的副作用锡垄,這些方法才被標(biāo)注為不建議使用的過(guò)期方法沦零,而暫停和恢復(fù)操作可以用等待/通知機(jī)制來(lái)替代。

安全地終止線程

中斷操作是一種簡(jiǎn)便的線程間交互方式偎捎,而這種交互方式最適合用來(lái)取消或停止任務(wù)蠢终。除了中斷以外,還可以利用一個(gè)boolean變量來(lái)控制是否需要停止任務(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ì)CountThread進(jìn)行中斷,使CountThread能夠感知中斷而結(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;
        }
    }
}

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

線程間通信

線程開始運(yùn)行申尼,擁有自己的椏遄浚空間,就如同一個(gè)腳本一樣师幕,按照既定的代碼一步一步地執(zhí)行粟按,直到終止诬滩。但是,每個(gè)運(yùn)行中的線程灭将,如果僅僅是孤立地運(yùn)行疼鸟,那么沒有一點(diǎn)兒價(jià)值,或者說(shuō)價(jià)值很少庙曙,如果多個(gè)線程能夠相互配合完成工作空镜,這將會(huì)帶來(lái)巨大的價(jià)值。

volatile和synchronized關(guān)鍵字

Java支持多個(gè)線程同時(shí)訪問(wèn)一個(gè)對(duì)象或者對(duì)象的成員變量捌朴,由于每個(gè)線程可以擁有這個(gè)變量的拷貝(雖然對(duì)象以及成員變量分配的內(nèi)存是在共享內(nèi)存中的吴攒,但是每個(gè)執(zhí)行的線程還是可以擁有一份拷貝,這樣做的目的是加速程序的執(zhí)行砂蔽,這是現(xiàn)代多核處理器的一個(gè)顯著特性)舶斧,所以程序在執(zhí)行過(guò)程中,一個(gè)線程看到的變量并不一定是最新的察皇。

關(guān)鍵字volatile可以用來(lái)修飾字段(成員變量)茴厉,就是告知程序任何對(duì)該變量的訪問(wèn)均需要從共享內(nèi)存中獲取,而對(duì)它的改變必須同步刷新回共享內(nèi)存什荣,它能保證所有線程對(duì)變量訪問(wèn)的可見性矾缓。

關(guān)鍵字synchronized可以修飾方法或者以同步塊的形式來(lái)進(jìn)行使用,它主要確保多個(gè)線程在同一個(gè)時(shí)刻稻爬,只能有一個(gè)線程處于方法或者同步塊中嗜闻,它保證了線程對(duì)變量訪問(wèn)的可見性和排他性

通過(guò)使用javap工具查看生成的class文件信息來(lái)分析synchronized關(guān)鍵字的實(shí)現(xiàn)細(xì)節(jié)桅锄,代碼如下

public class Synchronized {

    public static void main(String[] args) {
        synchronized (Synchronized.class){
            m();
        }
    }

    public static synchronized void m(){

    }
}

執(zhí)行javap -v Synchronized.class琉雳,部分相關(guān)輸出如下所示:

javap -v Synchronized.class部分輸出內(nèi)容

對(duì)于同步塊的實(shí)現(xiàn)使用了monitorenter和monitorexit指令,而同步方法則是依賴方法修飾符上的ACC_SYNCHRONIZED來(lái)完成友瘤。無(wú)論采用哪種方式翠肘,其本質(zhì)是對(duì)一個(gè)對(duì)象的監(jiān)視器進(jìn)行獲取,而這個(gè)獲取過(guò)程是排他的辫秧,也就是同一時(shí)刻只能有一個(gè)線程獲取到由synchronized所保護(hù)對(duì)象的監(jiān)視器束倍。

任意一個(gè)對(duì)象都擁有自己的監(jiān)視器,當(dāng)這個(gè)對(duì)象由同步塊或者這個(gè)對(duì)象的同步方法調(diào)用時(shí)盟戏,執(zhí)行方法的線程必須先獲取到該對(duì)象的監(jiān)視器才能進(jìn)入同步塊或者同步方法绪妹,而沒有獲取到監(jiān)視器(執(zhí)行該方法)的線程將會(huì)被阻塞在同步塊和同步方法的入口處,進(jìn)入BLOCKED狀態(tài)柿究。

等待/通知機(jī)制

等待/通知機(jī)制是指一個(gè)線程A調(diào)用了對(duì)象O的wait()方法進(jìn)入等待狀態(tài)邮旷,而另一個(gè)線程B調(diào)用了對(duì)象O的notify()或notifyAll()方法,線程A收到通知后從對(duì)象O的wait()方法返回蝇摸,進(jìn)而執(zhí)行后續(xù)操作婶肩。上述兩個(gè)線程對(duì)象O來(lái)完成交互糕簿,而對(duì)象上的wait()和notify/notifyAll()的關(guān)系就如同開關(guān)信號(hào)一樣,用來(lái)完成等待方通知方之間的交互工作狡孔。

等待/通知的相關(guān)方法是任意Java對(duì)象都具備的,這些方法被定義在所有對(duì)象的超類java.lang.Object上蜂嗽。

1苗膝、實(shí)現(xiàn)生產(chǎn)者-消費(fèi)者模型,代碼如下:

public class WaitNotify {

    private final static int CONTAINER_MAX_LENGTH = 3;

    private static Queue<Integer> resources = new LinkedList<Integer>();

    //作為synchronized的對(duì)象監(jiān)視器
    private static final Object lock = new Object();

    /**
     * 消息者
     */
    static class Consumer implements Runnable {

        @Override
        public void run() {
            synchronized (lock) {
                // 不能使用if判斷植旧,防止過(guò)早喚醒
                while (resources.isEmpty()) {
                    try {
                        // 當(dāng)前釋放鎖辱揭,線程進(jìn)入等待狀態(tài)。
                        lock.wait(); 
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread().getName() + " get number is " + resources.remove());
                // 喚醒所有等待狀態(tài)的線程
                lock.notifyAll();
            }
        }
    }


    /**
     * 生產(chǎn)者
     */
    static class Producer implements Runnable {

        @Override
        public void run() {
            synchronized (lock) {
                while (resources.size() == CONTAINER_MAX_LENGTH) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                int number = (int) (Math.random() * 100);
                System.out.println(Thread.currentThread().getName() + " produce number is " + number);
                resources.add(number);
                lock.notifyAll();
            }
        }
    }


    public static void main(String[] args) {
        for (int i = 0; i < 50; i++) {
            new Thread(new Consumer(), "consumer-" + i).start();
        }

        for (int i = 0; i < 50; i++) {
            new Thread(new Producer(), "producer-" + i).start();
        }
    }
}

調(diào)用wait()病附、notify()以及notifyAll()時(shí)需要注意的細(xì)節(jié)问窃,如下:

  • 使用wait()、notify()和notifyAll()時(shí)需要先對(duì)調(diào)用對(duì)象加鎖完沪。

  • 調(diào)用wait()方法后域庇,線程狀態(tài)由RUNNING變?yōu)閃AITING,并將當(dāng)前線程放置到對(duì)象的等待隊(duì)列覆积。

  • notify()或notifyAll()方法調(diào)用后听皿,等待線程依舊不會(huì)從wait()返回,需要調(diào)用notify()或notifAll()的線程釋放鎖之后宽档,等待線程才有機(jī)會(huì)從wait()返回尉姨。

  • notify()方法將等待隊(duì)列中的一個(gè)等待線程從等待隊(duì)列中移到同步隊(duì)列中,而notifyAll()方法則是將等待隊(duì)列中所有的線程全部移到同步隊(duì)列吗冤,被移動(dòng)的線程狀態(tài)由WAITING變?yōu)锽LOCKED又厉。

  • 從wait()方法返回的前提是獲得了調(diào)用對(duì)象的鎖。

2椎瘟、面試題:設(shè)計(jì)一個(gè)程序覆致,啟動(dòng)三個(gè)線程A,B,C,各個(gè)線程只打印特定的字母,各打印10次肺蔚,例如A線程只打印‘A’篷朵。要求在控制臺(tái)依次顯示“ABCABC…”

public class WaitNotify02 {


    public static void main(String[] args) {
        Print print = new Print(15);
        new Thread(print, "A").start();
        new Thread(print, "B").start();
        new Thread(print, "C").start();
    }


    private final static Object lock = new Object();

    static class Print implements Runnable {

        private int max_print;

        private int count = 0;

        private String str = "A";

        public Print(int max_print) {
            this.max_print = max_print;
        }

        @Override
        public void run() {
            synchronized (lock) {
                String name = Thread.currentThread().getName();
                while (count < max_print) {
                    if (str.equals(name)) {
                        System.out.print(name);
                        if (str.equals("A")) {
                            str = "B";
                        } else if (str.equals("B")) {
                            str = "C";
                        } else {
                            count++;
                            str = "A";
                        }
                        lock.notifyAll();
                    } else {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市婆排,隨后出現(xiàn)的幾起案子声旺,更是在濱河造成了極大的恐慌,老刑警劉巖段只,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件腮猖,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡赞枕,警方通過(guò)查閱死者的電腦和手機(jī)澈缺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門坪创,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人姐赡,你說(shuō)我怎么就攤上這事莱预。” “怎么了项滑?”我有些...
    開封第一講書人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵依沮,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我枪狂,道長(zhǎng)危喉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任州疾,我火速辦了婚禮辜限,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘严蓖。我一直安慰自己薄嫡,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開白布颗胡。 她就那樣靜靜地躺著岂座,像睡著了一般。 火紅的嫁衣襯著肌膚如雪杭措。 梳的紋絲不亂的頭發(fā)上费什,一...
    開封第一講書人閱讀 52,158評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音手素,去河邊找鬼鸳址。 笑死,一個(gè)胖子當(dāng)著我的面吹牛泉懦,可吹牛的內(nèi)容都是我干的稿黍。 我是一名探鬼主播,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼崩哩,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼巡球!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起邓嘹,我...
    開封第一講書人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤酣栈,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后汹押,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體矿筝,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年棚贾,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了窖维。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片榆综。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖铸史,靈堂內(nèi)的尸體忽然破棺而出鼻疮,到底是詐尸還是另有隱情,我是刑警寧澤琳轿,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布判沟,位于F島的核電站,受9級(jí)特大地震影響利赋,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜猩系,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一媚送、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧寇甸,春花似錦塘偎、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至绽淘,卻和暖如春涵防,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背沪铭。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工壮池, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人杀怠。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓椰憋,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親赔退。 傳聞我的和親對(duì)象是個(gè)殘疾皇子橙依,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359

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