線程池很容易理解的

  • 線程池介紹
  • 并發(fā)隊(duì)列
  • 線程池原理分析
  • 自定義線程池

文中部分代碼使用 lambda 表達(dá)式以簡化代碼衩椒。

線程池

什么是線程池粟按?

Java中的線程池是運(yùn)用場景最多的并發(fā)框架锅尘,幾乎所有需要異步或并發(fā)執(zhí)行任務(wù)的程序都可以使用線程池饲齐。在開發(fā)過程中爽待,合理地使用線程池能夠帶來3個好處愈捅。

  • 降低資源消耗遏考。通過重復(fù)利用已創(chuàng)建的線程降低線程創(chuàng)建和銷毀造成的消耗。
  • 提高響應(yīng)速度蓝谨。當(dāng)任務(wù)到達(dá)時(shí)灌具,任務(wù)可以不需要等到線程創(chuàng)建就能立即執(zhí)行青团。
  • 提高線程的可管理性。線程是稀缺資源咖楣,如果無限制地創(chuàng)建督笆,不僅會消耗系統(tǒng)資源,還會降低系統(tǒng)的穩(wěn)定性诱贿,使用線程池可以進(jìn)行統(tǒng)一分配娃肿、調(diào)優(yōu)和監(jiān)控

線程狀態(tài)

線程生命周期

新建狀態(tài)

當(dāng)用new操作符創(chuàng)建一個線程時(shí), 例如new Thread(r)珠十,線程還沒有開始運(yùn)行料扰,此時(shí)線程處在新建狀態(tài)。

new Thread(() -> System.out.println("run 任務(wù)執(zhí)行"))

就緒狀態(tài)

一個新創(chuàng)建的線程并不自動開始運(yùn)行焙蹭,要執(zhí)行線程晒杈,必須調(diào)用線程的start()方法。處于就緒狀態(tài)的線程并不一定立即運(yùn)行run()方法孔厉,線程還必須同其他線程競爭CPU時(shí)間拯钻,只有獲得CPU時(shí)間才可以運(yùn)行線程。

new Thread(() -> System.out.println("run 任務(wù)執(zhí)行")).start();

運(yùn)行狀態(tài)

當(dāng)線程獲得CPU時(shí)間后撰豺,它才進(jìn)入運(yùn)行狀態(tài)粪般,真正開始執(zhí)行run()方法。也就是 System.out.println("run 任務(wù)執(zhí)行") 郑趁。

run 任務(wù)執(zhí)行

阻塞狀態(tài)

線程運(yùn)行過程中刊驴,可能由于各種原因進(jìn)入阻塞狀態(tài) :

  • 線程執(zhí)行了Thread.sleep(int n)方法,線程放棄CPU,睡眠n毫秒,然后恢復(fù)運(yùn)行。

  • 線程要執(zhí)行一段同步代碼,由于無法獲得相關(guān)的同步鎖,只好進(jìn)入阻塞狀態(tài),等到獲得了同步鎖,才能恢復(fù)運(yùn)行寡润。

  • 線程執(zhí)行了一個對象的wait()方法,進(jìn)入阻塞狀態(tài),只有等到其他線程執(zhí)行了該對象的notify()或notifyAll()方法,才可能將其喚醒捆憎。

更多原因參考

死亡狀態(tài)

有兩個原因會導(dǎo)致線程死亡:

  • run方法正常退出而自然死亡
  • 一個未捕獲的異常終止了run方法而使線程死亡

使用 isAlive() 方法可判斷線程在當(dāng)前是否存活著

并發(fā)隊(duì)列

在并發(fā)隊(duì)列上JDK提供了兩套實(shí)現(xiàn),一個是以ConcurrentLinkedDeque為代表的高性能隊(duì)列非阻塞隊(duì)列梭纹,一個是以BlockingQueue接口為代表的阻塞隊(duì)列躲惰,無論哪種都繼承自Queue

ConcurrentLinkedDeque 非阻塞式隊(duì)列

  • 無界線程安全隊(duì)列
  • 先進(jìn)先出的原則
  • 不允許null元素

重要方法:

  • add() 和 offer() 都是加入元素的方法
  • poll() 和 peek() 都是取頭元素節(jié)點(diǎn)变抽,區(qū)別在于前者會刪除元素础拨,后者不會

適用于高并發(fā)場景下的隊(duì)列,通過無鎖的方式绍载,實(shí)現(xiàn)了高并發(fā)狀態(tài)下的高性能诡宗,通常ConcurrentLinkedQueue性能好于BlockingQueue.它是一個基于鏈接節(jié)點(diǎn)的無界線程安全隊(duì)列。該隊(duì)列的元素遵循先進(jìn)先出的原則击儡。頭是最先
加入的塔沃,尾是最近加入的,該隊(duì)列不允許null元素

public static void main(String[] args) {
        // 非阻塞式用法 無界隊(duì)列 - 先進(jìn)先出的原則
        ConcurrentLinkedQueue concurrentLinkedQueue = new ConcurrentLinkedQueue<String>();
        concurrentLinkedQueue.offer("第一個進(jìn)隊(duì)列");
        concurrentLinkedQueue.offer("第二個進(jìn)隊(duì)列");
        // 獲取單個隊(duì)列信息 peek 獲取隊(duì)列
        System.out.println(concurrentLinkedQueue.peek());
        System.out.println(concurrentLinkedQueue.size());
        // 獲取單個隊(duì)列信息 poll 獲取隊(duì)列之后 會刪除隊(duì)列信息 移除
        System.out.println(concurrentLinkedQueue.poll());
        System.out.println(concurrentLinkedQueue.size());
    }
第一個進(jìn)隊(duì)列
2
第一個進(jìn)隊(duì)列
1

BlockingQueue 阻塞式隊(duì)列

被阻塞的情況主要有如下兩種:

  • 當(dāng)隊(duì)列滿了的時(shí)候進(jìn)行入隊(duì)列操作
  • 當(dāng)隊(duì)列空了的時(shí)候進(jìn)行出隊(duì)列操作

以下簡單介紹 BlockingQueue 成員

ArrayBlockingQueue

有邊界的阻塞隊(duì)列阳谍,它的內(nèi)部實(shí)現(xiàn)是一個數(shù)組蛀柴,先進(jìn)先出原則螃概。使用阻塞必須加加超時(shí)時(shí)間

public static void main(String[] args) throws InterruptedException {
        // 阻塞式隊(duì)列
        ArrayBlockingQueue<Object> arrayBlockingQueue = new ArrayBlockingQueue<>(3);
        // 沒有加超時(shí)時(shí)間都是為非阻塞式
        arrayBlockingQueue.offer("張三");
        // 獲取單個隊(duì)列信息,并且會刪除該隊(duì)列
        System.out.println(arrayBlockingQueue.poll(3, TimeUnit.SECONDS));
        System.out.println(arrayBlockingQueue.poll(3, TimeUnit.SECONDS));
        System.out.println(arrayBlockingQueue.size());

    }

new ArrayBlockingQueue<>(3) 設(shè)定(隊(duì)列)有界大小3。
offer("張三") - “張三“ 進(jìn)入隊(duì)列
第一個 poll(3, TimeUnit.SECONDS) 取出數(shù)據(jù)鸽疾,“張三”從隊(duì)列中移除
第二個 poll(3, TimeUnit.SECONDS) 吊洼,此時(shí)隊(duì)列已經(jīng)沒有數(shù)據(jù)了會阻塞等待3秒,如果隊(duì)列在這3秒內(nèi)有數(shù)據(jù)入隊(duì)列會立即取出數(shù)據(jù)并結(jié)束阻塞制肮,3秒阻塞超時(shí)就返回null

張三
null
0

以上示例是 當(dāng)隊(duì)列空了的時(shí)候進(jìn)行出隊(duì)列阻塞

public static void main(String[] args) throws InterruptedException {
        // 阻塞式隊(duì)列
        ArrayBlockingQueue<Object> arrayBlockingQueue = new ArrayBlockingQueue<>(3);
        // 沒有加超時(shí)時(shí)間都是為非阻塞式
        arrayBlockingQueue.offer("張一", 3, TimeUnit.SECONDS);
        arrayBlockingQueue.offer("張二", 3, TimeUnit.SECONDS);
        arrayBlockingQueue.offer("張三", 3, TimeUnit.SECONDS);
        arrayBlockingQueue.offer("張四", 3, TimeUnit.SECONDS);
        // 獲取單個隊(duì)列信息,并且會刪除該隊(duì)列
        System.out.println(arrayBlockingQueue.poll(3, TimeUnit.SECONDS));
        System.out.println(arrayBlockingQueue.size());

    }

new ArrayBlockingQueue<>(3) 設(shè)定(隊(duì)列)有界大小3冒窍。
offer("張一") - “張一“ 進(jìn)入隊(duì)列
offer("張二") - “張二“ 進(jìn)入隊(duì)列
offer("張三") - “張三“ 進(jìn)入隊(duì)列 , 此時(shí)隊(duì)列已滿
offer("張四",3, TimeUnit.SECOND) 此時(shí)隊(duì)列已滿 , 這里給了3秒阻塞時(shí)間等待數(shù)據(jù)出列才有位置弄企,期間如果有數(shù)據(jù)出列立即添加“張四”入隊(duì)列并結(jié)束阻塞超燃,如果沒數(shù)據(jù)出列阻塞超時(shí)會廢棄當(dāng)前數(shù)據(jù)“張四”

張一
2

以上示例是 當(dāng)隊(duì)列滿了的時(shí)候進(jìn)行入隊(duì)列阻塞

常見的阻塞式隊(duì)列如下:

  • LinkedBlockingQueue
  • PriorityBlockingQueue
  • SynchronousQueue

有興趣可以去實(shí)踐下

ThreadPoolExecutor

  • Executor - execute 方法接口
  • Executors - 工廠類
  • ThreadPoolExecutor - Executor 框架的最頂層實(shí)現(xiàn)類

Executor框架的最頂層實(shí)現(xiàn)是ThreadPoolExecutor類,Executors工廠類中提供的newScheduledThreadPool拘领、newFixedThreadPool、newCachedThreadPool 靜態(tài)方法其實(shí)也只是ThreadPoolExecutor的構(gòu)造函數(shù)參數(shù)不同而已樱调。通過傳入不同的參數(shù)约素,就可以構(gòu)造出適用于不同應(yīng)用場景下的線程池,來看下構(gòu)造的參數(shù)笆凌。

public ThreadPoolExecutor(
    int corePoolSize,
    int maximumPoolSize,
    long keepAliveTime,
    TimeUnit unit,
    BlockingQueue<Runnable> workQueue) {   
     ...   
}
  • corePoolSize
    線程池核心線程數(shù)圣猎,默認(rèn)情況下,核心線程會在線程池中一直存活乞而,即使它們處于閑置狀態(tài)送悔。如果ThreadPoolExecutor的allowCoreThreadTimeOut屬性設(shè)置為true,那么閑置的核心線程在等待新任務(wù)到來時(shí)會有超時(shí)策略,超過keepAliveTime 時(shí)間后爪模,核心線程就會被終止欠啤。
  • maximumPoolSize
    線程池所能容納的最大線程數(shù),當(dāng)活動線程達(dá)到這個數(shù)值后屋灌,后續(xù)的新任務(wù)將被阻塞洁段。
  • keepAliveTime
    非核心線程超過這個時(shí)長就會被回收。當(dāng)ThreadPoolExecutor的allowCoreThreadTimeOut屬性設(shè)置為true時(shí)共郭,keepAliveTime同樣會作用于核心線程
  • unit
    keepAliveTime 參數(shù)的時(shí)間單位
  • workQueue
    執(zhí)行前用于保持任務(wù)的隊(duì)列, 此隊(duì)列僅由 execute 方法提交的 Runnable 任務(wù)祠丝。

newCachedThreadPool

這里用 可緩存的 newCachedThreadPool 線程池來分析

ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(
        0,
        Integer.MAX_VALUE,
        60L, 
        TimeUnit.SECONDS, 
        new SynchronousQueue<Runnable>());
    }

newCachedThreadPool的corePoolSize被設(shè)置為0, maximumPoolSize被設(shè)置為Integer.MAX_VALUE, 即maximum是無界的。這里keepAliveTime設(shè)置為60秒,意味著空閑的線程最多可以等待任務(wù)60秒,否則將被回收除嘹。

newCachedThreadPool使用沒有容量的SynchronousQueue作為主線程池的工作隊(duì)列,它是一個不存儲元素阻塞隊(duì)列写半。

線程池中的線程是被線程池緩存了的,也就是說,線程沒有任務(wù)要執(zhí)行時(shí),便處于空閑狀態(tài),處于空閑狀態(tài)的線程并不會被立即銷毀(會被緩存住),只有當(dāng)空閑時(shí)間超出一段時(shí)間(默認(rèn)為60s)后,線程池才會銷毀該線程(相當(dāng)于清除過時(shí)的緩存)。新任務(wù)到達(dá)后,線程池首先會讓被緩存住的線程(空閑狀態(tài))去執(zhí)行任務(wù),如果沒有可用線程(無空閑線程),便會創(chuàng)建新的線程尉咕。

根據(jù)特性可知 :

  • 長時(shí)間不提交任務(wù)的CachedThreadPool不會占用系統(tǒng)資源
  • 極端情況下,CachedThreadPool會因?yàn)閯?chuàng)建過多線程而耗盡CPU資源及內(nèi)存
代碼示例
public static void main(String[] args) {
        // 創(chuàng)建線程(四種方式) 1.可緩存叠蝇、定長、定時(shí)龙考、單例
        ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
        for (int i = 0; i < 100; i++) {
            final int temp = i;
            // execute方法作用: 執(zhí)行任務(wù)
            newCachedThreadPool.execute(() -> {
                System.out.println(Thread.currentThread().getName() + ",i:" + temp);
            });
        }
    }

newCachedThreadPool 線程池執(zhí)行 100 次任務(wù)

pool-1-thread-3,i:2
pool-1-thread-1,i:0
pool-1-thread-2,i:1
pool-1-thread-4,i:3
pool-1-thread-5,i:4
pool-1-thread-7,i:6
pool-1-thread-6,i:5
pool-1-thread-9,i:8
pool-1-thread-10,i:9
pool-1-thread-8,i:7
pool-1-thread-11,i:10
pool-1-thread-1,i:21
pool-1-thread-3,i:20

可以看到線程 pool-1-thread-3蟆肆、pool-1-thread-1 被重復(fù)使用了

newFixedThreadPool

定長的 newFixedThreadPool 線程池

ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(3);
public static ExecutorService newFixedThreadPool(int nThreads) {
     return new ThreadPoolExecutor(
          nThreads, nThreads,
          0L, TimeUnit.MILLISECONDS,
          new LinkedBlockingQueue<Runnable>());
}

可以看到 newFixedThreadPool 的核心線程和最大的線程都是一樣的矾睦,最多3個線程將處于活動狀態(tài)。如果提交了3個以上的線程炎功,那么它們將保持在隊(duì)列中枚冗,直到線程可用。

代碼示例
public static void main(String[] args) {
        // 可固定長度的線程池 核心線程數(shù) 為3 最多創(chuàng)建3個線程
        ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(3);
        for (int i = 0; i < 10; i++) {
            final int temp = i;
            // execute方法作用: 執(zhí)行任務(wù)
            newFixedThreadPool.execute(() -> {
                System.out.println(Thread.currentThread().getName() + ",i:" + temp);
            });
        }
    }
pool-1-thread-3,i:2
pool-1-thread-2,i:1
pool-1-thread-1,i:0
pool-1-thread-3,i:3
pool-1-thread-2,i:5
pool-1-thread-3,i:6
pool-1-thread-1,i:4
pool-1-thread-3,i:8
pool-1-thread-2,i:7
pool-1-thread-1,i:9

可以看到始終只有pool-1-thread-1蛇损、pool-1-thread-2赁温、pool-1-thread-3 三個線程

newScheduledThreadPool

可定時(shí)的 newScheduledThreadPool 線程池

public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }

newScheduledThreadPool 的核心線程為 傳入的corePoolSize,最大線程為Integer.MAX_VALUE 淤齐, DelayedWorkQueue隊(duì)列實(shí)現(xiàn)BlockingQueue接口股囊,所以使用阻塞式的BlockingQueue隊(duì)列。

代碼示例
public static void main(String[] args) {
        // 可定時(shí)線程池 3核心線程數(shù)
        ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(3);
        newScheduledThreadPool.scheduleAtFixedRate(
                    // Runnable 任務(wù)
                () -> System.out.println(Thread.currentThread().getName() + "run "), 
                1000,  // 初次執(zhí)行需等待時(shí)間
                100, TimeUnit.MILLISECONDS);  // 周期執(zhí)行時(shí)間(3個線程搶cpu時(shí)間)

    }
pool-1-thread-1run 
pool-1-thread-2run 
pool-1-thread-3run 
pool-1-thread-3run 
pool-1-thread-2run 

每 100 毫秒執(zhí)行一次

newSingleThreadExecutor

單例的 newSingleThreadExecutor 線程池

代碼示例
public static void main(String[] args) {
        // 單線線程
        ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 10; i++) {
            final int temp = i;
            // execute方法作用: 執(zhí)行任務(wù)
            newSingleThreadExecutor.execute(() -> System.out.println(Thread.currentThread().getName() + ",i:" + temp));
        }
    }
pool-1-thread-1,i:0
pool-1-thread-1,i:1
pool-1-thread-1,i:2
pool-1-thread-1,i:3
pool-1-thread-1,i:4
pool-1-thread-1,i:5
pool-1-thread-1,i:6
pool-1-thread-1,i:7
pool-1-thread-1,i:8
pool-1-thread-1,i:9

始終只有一個線程執(zhí)行任務(wù)

線程池原理剖析

提交一個任務(wù)到線程池中更啄,線程池的處理流程如下:

  • 1 .判斷線程池里的核心線程是否都在執(zhí)行任務(wù)稚疹,如果不是(核心線程空閑或者還有核心線程沒有被創(chuàng)建)則創(chuàng)建一個新的工作線程來執(zhí)行任務(wù)。如果核心線程都在執(zhí)行任務(wù)祭务,則進(jìn)入下個流程内狗。

  • 2 .線程池判斷工作隊(duì)列是否已滿,如果工作隊(duì)列沒有滿义锥,則將新提交的任務(wù)存儲在這個工作隊(duì)列里柳沙。如果工作隊(duì)列滿了,則進(jìn)入下個流程拌倍。

  • 3 . 判斷線程池里的線程是否都處于工作狀態(tài)赂鲤,如果沒有,則創(chuàng)建一個新的工作線程來執(zhí)行任務(wù)柱恤。如果已經(jīng)滿了数初,則交給飽和策略來處理這個任務(wù)。

自定義線程線程池

上面列舉到 newCachedThreadPool膨更、newFixedThreadPool ... 底層都是對ThreadPoolExecutor的構(gòu)造器進(jìn)行包裝使用妙真。在來看下

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

所以咱們?nèi)绻獙?shí)現(xiàn)一個自定義線程池就 直接 newThreadPoolExecutor(...) 就就行,現(xiàn)在來自定義一個荚守。

ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 2, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(4));

這里自定義線程池 :核心線程1個珍德,最大創(chuàng)建2個線程,60s等待超時(shí)銷毀矗漾,使用阻塞式有界ArrayBlockingQueue 隊(duì)列锈候,最多緩存4個任務(wù)。

public class CustomThread {

    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 2, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(4));
        for (int i = 1; i <= 6; i++) {
            TaskThred t1 = new TaskThred("任務(wù)" + i);
            executor.execute(t1);
        }
        executor.shutdown();
    }
}

class TaskThred implements Runnable {
    private String taskName;

    public TaskThred(String taskName) {
        this.taskName = taskName;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + taskName);
    }
}

execute 執(zhí)行6個任務(wù)

pool-1-thread-1任務(wù)1
pool-1-thread-2任務(wù)6
pool-1-thread-2任務(wù)2
pool-1-thread-1任務(wù)4
pool-1-thread-1任務(wù)5
pool-1-thread-2任務(wù)3

相關(guān)的異常信息

RejectedExecutionException
原因:

  • 提交任務(wù)量大敞贡, 隊(duì)列緩存較小
  • 確保不要在shutdown()之后在執(zhí)行任務(wù)
java.util.concurrent.RejectedExecutionException: Task com.snail.demo.TaskThred@74a14482 rejected from java.util.concurrent.ThreadPoolExecutor@1540e19d[Running, pool size = 2, active threads = 2, queued tasks = 2, completed tasks = 0]
    at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(Unknown Source)

要出現(xiàn)這個異常只需將上邊 new ArrayBlockingQueue<>(4) 大小 4 改為 2泵琳,如下

ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 2, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(2));
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子获列,更是在濱河造成了極大的恐慌谷市,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件击孩,死亡現(xiàn)場離奇詭異迫悠,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)巩梢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進(jìn)店門创泄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人括蝠,你說我怎么就攤上這事鞠抑。” “怎么了忌警?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵搁拙,是天一觀的道長。 經(jīng)常有香客問我慨蓝,道長感混,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任礼烈,我火速辦了婚禮,結(jié)果婚禮上婆跑,老公的妹妹穿的比我還像新娘此熬。我一直安慰自己,他們只是感情好滑进,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布犀忱。 她就那樣靜靜地躺著,像睡著了一般扶关。 火紅的嫁衣襯著肌膚如雪阴汇。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天节槐,我揣著相機(jī)與錄音搀庶,去河邊找鬼。 笑死铜异,一個胖子當(dāng)著我的面吹牛哥倔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播揍庄,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼咆蒿,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起沃测,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤缭黔,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蒂破,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體馏谨,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年寞蚌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了田巴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,013評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡挟秤,死狀恐怖壹哺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情艘刚,我是刑警寧澤管宵,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站攀甚,受9級特大地震影響箩朴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜秋度,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一炸庞、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧荚斯,春花似錦埠居、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至兽泣,卻和暖如春绎橘,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背唠倦。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工称鳞, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人牵敷。 一個月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓胡岔,卻偏偏與公主長得像,于是被迫代替她去往敵國和親枷餐。 傳聞我的和親對象是個殘疾皇子靶瘸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評論 2 355