iOS - GCD

GCD
隊列

  • 串行隊列
  • 并行隊列
  • 全局隊列
  • 主隊列

幾個容易混淆的概念
dispatch_barrier_async柵欄函數
dispatch_group_t隊列組
dispatch_semaphore_t信號量
dispatch_apply 快速迭代
dispatch_suspend和dispatch_resume
例:

GCD:

GCD全稱 Grand Central Dispatch,我們通俗的翻譯叫牛逼的中心調度。

隊列

先說下GCD中的隊列 dispatch_queue_t

串行隊列: 同步執行,在當前線程執行
并行隊列: 可由多個線程異步執行,但任務的取出還是FIFO的

    //創建隊列
    //參數1: 隊列名
    //參數2: 隊列類型  DISPATCH_QUEUE_SERIAL |  NULL   串行隊列,
                     DISPATCH_QUEUE_CONCURRENT       并發隊列
    dispatch_queue_t sky_queue = dispatch_queue_create("隊列名字", NULL);

全局隊列: 顧名思義就是全局隊列,由系統創建,屬于并行隊列

    //全局隊列
    /*
    參數1 : iOS8以前是優先級, iOS8以后是服務質量
    iOS8以前
    *  - DISPATCH_QUEUE_PRIORITY_HIGH          高優先級 2
    *  - DISPATCH_QUEUE_PRIORITY_DEFAULT:      默認的優先級 0
    *  - DISPATCH_QUEUE_PRIORITY_LOW:          低優先級 -2
    *  - DISPATCH_QUEUE_PRIORITY_BACKGROUND:
    
    iOS8以后
    *  - QOS_CLASS_USER_INTERACTIVE  0x21 用戶交互(用戶迫切想執行任務)
    *  - QOS_CLASS_USER_INITIATED    0x19 用戶需要
    *  - QOS_CLASS_DEFAULT           0x15 默認
    *  - QOS_CLASS_UTILITY           0x11 工具(低優先級, 蘋果推薦將耗時操作放到這種類型的隊列中)
    *  - QOS_CLASS_BACKGROUND        0x09 后臺
    *  - QOS_CLASS_UNSPECIFIED       0x00 沒有設置
     
    參數2: 沒用過一般傳 0
    */
    //例子
    dispatch_queue_t sky_global_queue = dispatch_get_global_queue(0, 0);

主隊列: 主隊列屬于串行隊列. 運行在主線程(UI線程)

    //主隊列
    dispatch_queue_t sky_main_queue = dispatch_get_main_queue();

幾個容易混淆的概念

  1. **串行隊列,同步執行: ** 在當前線程上順序執行任務,并不會開啟新線程.
  1. 串行隊列,異步執行: 在不是主線程的另一個線程上順序執行任務.(因為是異步執行,如果多線程的話不能保證順序執行,所以是一個線程。)
  2. 并發隊列,同步執行 : 在當前線程上順序執行任務,并不會開啟新線程. (同串行隊列同步執行)
  3. 并發隊列,異步執行: 給每一個任務開啟一個線程去執行(因為隊列中的所有任務都是異步的)分別執行每個任務.每個任務都是從頭開始的.哪個任務先結束由任務本身決定,但是系統都會給每一個任務一個單獨的線程去執行。

看看代碼:


//串行 同步
- (void)sky_syncSerial
{
    //同步+串行 不會開始新線程.   等到同步函數調用完成之后才會執行后面的代碼
    dispatch_queue_t sky_sync_serial_queue = dispatch_queue_create("com.sky.queue", DISPATCH_QUEUE_SERIAL);// DISPATCH_QUEUE_SERIAL == NULL
    
    dispatch_sync(sky_sync_serial_queue, ^{
        NSLog(@"1 = %@",[NSThread currentThread]);
    });
    
    dispatch_sync(sky_sync_serial_queue, ^{
        NSLog(@"2 = %@",[NSThread currentThread]);
    });
    
    dispatch_sync(sky_sync_serial_queue, ^{
        NSLog(@"3 = %@",[NSThread currentThread]);
    });

    NSLog(@"4 ");
    
    /* 
     運行結果:
     2017-01-26 16:16:40.424 GCDNotes[93061:9398100] 1 = <NSThread: 0x608000070100>{number = 1, name = main}
     2017-01-26 16:16:40.424 GCDNotes[93061:9398100] 2 = <NSThread: 0x608000070100>{number = 1, name = main}
     2017-01-26 16:16:40.424 GCDNotes[93061:9398100] 3 = <NSThread: 0x608000070100>{number = 1, name = main}
     2017-01-26 16:16:40.425 GCDNotes[93061:9398100] 4
     */
}

//串行 異步
- (void)sky_asyncSerial
{
   //在不是主線程的另一個線程順序執行任務. 因為是異步所以開啟新線程. 因為是串行所以是一個線程.
    dispatch_queue_t sky_global_queue = dispatch_queue_create("com.sky.queue", DISPATCH_QUEUE_SERIAL);
    
    dispatch_async(sky_global_queue, ^{
        NSLog(@"1 = %@",[NSThread currentThread]);
    });
    
    dispatch_async(sky_global_queue, ^{
        NSLog(@"2 = %@",[NSThread currentThread]);
    });
    
    dispatch_async(sky_global_queue, ^{
        NSLog(@"3 = %@",[NSThread currentThread]);
    });
    
    NSLog(@"4 ");
    /*
     運行結果:
     2017-01-26 18:56:19.132 GCDNotes[93256:9704465] 4
     2017-01-26 18:56:19.132 GCDNotes[93256:9704622] 1 = <NSThread: 0x60800026a500>{number = 5, name = (null)}
     2017-01-26 18:56:19.133 GCDNotes[93256:9704622] 2 = <NSThread: 0x60800026a500>{number = 5, name = (null)}
     2017-01-26 18:56:19.133 GCDNotes[93256:9704622] 3 = <NSThread: 0x60800026a500>{number = 5, name = (null)}
     */
}

//并發 同步
- (void)sky_syncConCurrent
{
    //同步 + 并發 : 在同一個線程里面.但不是主線程,如果同步在主線程里面會造成死鎖.
    //原因: 主隊列,如果主線程正在執行代碼,就不調度任務;同步執行:一直執行第一個任務直到結束。兩者互相等待造成死鎖
    //錯誤代碼示例:
    /*
    dispatch_queue_t sky_main_queue = dispatch_get_main_queue();
    dispatch_sync(sky_main_queue, ^{
        //發送錯誤,不會走下面的代碼 ~
        NSLog(@"erroe = %@",sky_main_queue);
    });
    */
    
    dispatch_queue_t sky_sync_Concurrent_queue = dispatch_queue_create("com.sky.queue", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_sync(sky_sync_Concurrent_queue, ^{
        NSLog(@"1 = %@",[NSThread currentThread]);
    });
    
    dispatch_sync(sky_sync_Concurrent_queue, ^{
        NSLog(@"2 = %@",[NSThread currentThread]);
    });
    
    dispatch_sync(sky_sync_Concurrent_queue, ^{
        NSLog(@"3 = %@",[NSThread currentThread]);
    });
    
    NSLog(@"4 ");
    
    /*
     運行結果:
     2017-01-26 19:01:34.868 GCDNotes[93272:9727007] 1 = <NSThread: 0x60000006a000>{number = 1, name = main}
     2017-01-26 19:01:34.869 GCDNotes[93272:9727007] 2 = <NSThread: 0x60000006a000>{number = 1, name = main}
     2017-01-26 19:01:34.869 GCDNotes[93272:9727007] 3 = <NSThread: 0x60000006a000>{number = 1, name = main}
     2017-01-26 19:01:34.869 GCDNotes[93272:9727007] 4
     */
}

//并發 異步
- (void)sky_asyncConCurrent
{
    //開啟新線程. 有多少任務開啟多少線程.(如果任務完成,其它的任務就會使用已經完成的.沒有完成就會繼續開啟線程)
    dispatch_queue_t sky_async_concurrent_queue = dispatch_queue_create("com.sky.queue", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(sky_async_concurrent_queue, ^{
       NSLog(@"1 = %@",[NSThread currentThread]);
    });

    dispatch_async(sky_async_concurrent_queue, ^{
        NSLog(@"2 = %@",[NSThread currentThread]);
    });

    dispatch_async(sky_async_concurrent_queue, ^{
        NSLog(@"3 = %@",[NSThread currentThread]);
    });
    
    dispatch_async(sky_async_concurrent_queue, ^{
        NSLog(@"4 = %@",[NSThread currentThread]);
    });
    
    dispatch_async(sky_async_concurrent_queue, ^{
        NSLog(@"5 = %@",[NSThread currentThread]);
    });
    
    dispatch_async(sky_async_concurrent_queue, ^{
        NSLog(@"6 = %@",[NSThread currentThread]);
    });

    NSLog(@"7");
    
    /*
     運行結果:
     2017-01-26 19:07:04.372 GCDNotes[93315:9751108] 3 = <NSThread: 0x6000002638c0>{number = 5, name = (null)}
     2017-01-26 19:07:04.372 GCDNotes[93315:9751058] 7
     2017-01-26 19:07:04.372 GCDNotes[93315:9751129] 2 = <NSThread: 0x60000007a600>{number = 4, name = (null)}
     2017-01-26 19:07:04.372 GCDNotes[93315:9751107] 1 = <NSThread: 0x608000074940>{number = 3, name = (null)}
     2017-01-26 19:07:04.372 GCDNotes[93315:9751110] 4 = <NSThread: 0x600000264300>{number = 6, name = (null)}
     2017-01-26 19:07:04.372 GCDNotes[93315:9751394] 5 = <NSThread: 0x600000264380>{number = 7, name = (null)}
     2017-01-26 19:07:04.372 GCDNotes[93315:9751108] 6 = <NSThread: 0x6000002638c0>{number = 5, name = (null)}
     */
}

dispatch_barrier_async柵欄函數

  • barrier_async只有前面的任務執行并完成后才會執行. 如果后面還有任務要等到barrier_async執行完成之后才會繼續執行.
  • 必須使用自定義的隊列.否則即使加上也和全局隊列效果一樣,也就是在全局隊列中barrier_async會和其它普通的任務一樣.不會等到他之前的所有任務執行完成之后再執行.
  • dispatch_barrier_sync會在主線程中執行任務。
    dispatch_queue_t sky_queue = dispatch_queue_create("com.sky.queue", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(sky_queue, ^{
        NSLog(@"1 = %@",[NSThread currentThread]);
    });
    
    dispatch_async(sky_queue, ^{
        NSLog(@"2 = %@",[NSThread currentThread]);
    });
    
    dispatch_barrier_async(sky_queue, ^{
        NSLog(@"barrier  %@ ",[NSThread currentThread]);
    });
    
    dispatch_async(sky_queue, ^{
        NSLog(@"3 = %@",[NSThread currentThread]);
    });
    
    dispatch_async(sky_queue, ^{
        NSLog(@"4 = %@",[NSThread currentThread]);
    });
 
    dispatch_async(sky_queue, ^{
        NSLog(@"5 = %@",[NSThread currentThread]);
    });
    /**
     運行結果:
     2017-01-26 19:42:09.012 GCDNotes[93364:9892792] 2 = <NSThread: 0x60800026d1c0>{number = 4, name = (null)}
     2017-01-26 19:42:09.012 GCDNotes[93364:9892793] 1 = <NSThread: 0x600000076b40>{number = 3, name = (null)}
     2017-01-26 19:42:09.012 GCDNotes[93364:9892793] barrier  <NSThread: 0x600000076b40>{number = 3, name = (null)}
     2017-01-26 19:42:09.013 GCDNotes[93364:9892792] 3 = <NSThread: 0x60800026d1c0>{number = 4, name = (null)}
     2017-01-26 19:42:09.013 GCDNotes[93364:9892795] 4 = <NSThread: 0x608000276180>{number = 5, name = (null)}
     2017-01-26 19:42:09.013 GCDNotes[93364:9892793] 5 = <NSThread: 0x600000076b40>{number = 3, name = (null)}
     */

dispatch_group_t隊列組

  • 使用場景: 異步執行2個操作,等都執行完成之后,回到主線程繼續執行.(比如倆圖片下載完后合并成一個,或倆網絡請求完成之后去刷新列表等~(柵欄函數也可以 ))
  • 設置阻塞組(超時)任務一定時間. dispatch_group_wait(group, DISPATCH_TIME_FOREVER);第一個參數是需要阻塞的組,第二個是阻塞的時間.
  • dispatch_group_notify 當group關聯的block執行完畢后,就調用這個block

系統管理隊列組和手動管理隊列組. 兩個是等價的. 手動的enter和leave必須成對使用.

//系統管理
dispatch_group_async(group, queue, ^{
      //...
 });
//手動管理
dispatch_group_enter(group);
    dispatch_async(queue, ^{
        // ...
        dispatch_group_leave(group);
    });
    //線程隊列組
    dispatch_queue_t sky_queue = dispatch_queue_create("com.sky.queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_t sky_group = dispatch_group_create();
    
    //線程組的用法和原理:可以給一個任務組設置一個阻塞(超時)時間,如
      果給一個任務組的前兩個任務設置一個超時時間那么如果這前兩個任務
      提前執行結束了,也就是在設定的阻塞時間內完成了任務,那么這個阻塞
      就會放行下面的任務去執行任務,如果超過了超時時間那么這個阻塞也
      會放行,讓下面的任務可以執行.阻塞時間并不能殺死任務,也就是說如果
      你設定了阻塞(超時)時間,阻塞時間前的任務在阻塞放行前并沒有執行完
      成,然后任務就被放行了,系統繼續往下執行,但是這時候阻塞時間前的任
      務也會執行完成如果你不手動殺死它的話.
    //dispatch_group_wait(sky_group, 3); //第一個參數 阻塞的組 第二個
      參數 阻塞時間
    
    dispatch_group_async(sky_group, sky_queue, ^{
        NSLog(@" 1 %@ ",[NSThread currentThread]);
    });
    
    dispatch_group_async(sky_group, sky_queue, ^{
        NSLog(@" 2 %@ ",[NSThread currentThread]);
    });
    
    dispatch_group_async(sky_group, sky_queue, ^{
        [NSThread sleepForTimeInterval:3];//等待三秒
        NSLog(@" 3 %@ ",[NSThread currentThread]);
    });

    dispatch_group_async(sky_group, sky_queue, ^{
        NSLog(@" 4 %@ ",[NSThread currentThread]);
    });

       //回到主線程
    dispatch_group_notify(sky_group, sky_queue, ^{
        //監測方法在最后一個任務執行的線程中執行
        NSLog(@"回到主線程了 ~ %@" , [NSThread currentThread]);
    });
    
    /**
     運行結果:
     2017-01-26 20:26:27.768 GCDNotes[93449:10087233]  1 <NSThread: 0x60000026b6c0>{number = 4, name = (null)}
     2017-01-26 20:26:27.768 GCDNotes[93449:10087235]  2 <NSThread: 0x600000260f40>{number = 3, name = (null)}
     2017-01-26 20:26:27.768 GCDNotes[93449:10087330]  4 <NSThread: 0x600000271cc0>{number = 5, name = (null)}
     2017-01-26 20:26:30.769 GCDNotes[93449:10087232]  3 <NSThread: 0x608000260f80>{number = 6, name = (null)}
     2017-01-26 20:26:30.770 GCDNotes[93449:10087232] 回到主線程了 ~ <NSThread: 0x608000260f80>{number = 6, name = (null)}
     */

dispatch_semaphore_t信號量

信號量是用于控制并發數量的,所以只用在全局隊列和并行隊列中.

  1. 創建信號量,可以設置信號量的資源數。0表示沒有資源,調用dispatch_semaphore_wait會立即等待。
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
  1. 等待信號,可以設置超時參數。該函數返回0表示得到通知,非0表示超時。
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
  2. 通知信號,如果等待線程被喚醒則返回非0,否則返回0。
    dispatch_semaphore_signal(semaphore);
    //創建隊列組
    dispatch_group_t sky_group = dispatch_group_create();
    //創建信號為3的信號量
    dispatch_semaphore_t sky_semaphore = dispatch_semaphore_create(3);
    
    dispatch_queue_t sky_global = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    for (int i = 0 ; i < 10 ; i ++)
    {
        //設置等待信號 DISPATCH_TIME_FOREVER(永遠) | DISPATCH_TIME_NOW(現在)
        dispatch_semaphore_wait(sky_semaphore, DISPATCH_TIME_FOREVER);
        
        //
        dispatch_group_async(sky_group, sky_global, ^{
            NSLog(@"i = %d : %@",i , [NSThread currentThread]);
            [NSThread sleepForTimeInterval:1];
            //設置通知信號
            dispatch_semaphore_signal(sky_semaphore);
        });
    }
    //通知主線程
    dispatch_group_notify(sky_group, sky_global, ^{
        NSLog(@"xxxxoooo");
    });
    /*
     運行結果:
     2017-01-26 21:10:53.006 GCDNotes[93525:10184012] i = 2 : <NSThread: 0x608000460fc0>{number = 5, name = (null)}
     2017-01-26 21:10:53.006 GCDNotes[93525:10184037] i = 0 : <NSThread: 0x60800026a040>{number = 3, name = (null)}
     2017-01-26 21:10:53.006 GCDNotes[93525:10184011] i = 1 : <NSThread: 0x608000279440>{number = 4, name = (null)}
     2017-01-26 21:10:54.009 GCDNotes[93525:10184037] i = 4 : <NSThread: 0x60800026a040>{number = 3, name = (null)}
     2017-01-26 21:10:54.009 GCDNotes[93525:10184012] i = 3 : <NSThread: 0x608000460fc0>{number = 5, name = (null)}
     2017-01-26 21:10:54.009 GCDNotes[93525:10184011] i = 5 : <NSThread: 0x608000279440>{number = 4, name = (null)}
     2017-01-26 21:10:55.015 GCDNotes[93525:10184037] i = 8 : <NSThread: 0x60800026a040>{number = 3, name = (null)}
     2017-01-26 21:10:55.015 GCDNotes[93525:10184012] i = 6 : <NSThread: 0x608000460fc0>{number = 5, name = (null)}
     2017-01-26 21:10:55.015 GCDNotes[93525:10184011] i = 7 : <NSThread: 0x608000279440>{number = 4, name = (null)}
     2017-01-26 21:10:56.020 GCDNotes[93525:10184037] i = 9 : <NSThread: 0x60800026a040>{number = 3, name = (null)}
     2017-01-26 21:10:57.023 GCDNotes[93525:10184037] xxxxoooo
     */
    //結果分析: 來自: http://www.lxweimin.com/p/ac11fe7ef78c
    /*
     首先這里面創建了一個組,這個組放在這里只是告訴你可以這么用,它不會影響信號量的功能.
     這里創建了一個并發為3的信號量然而for循環是10個任務,那么理論
     上10個任務會創建十個線程去執行,但是你信號量為3所以只能創建3
     個線程去執行前面10個任務,然后等待前3個任務執行完成了騰出來新
     的線程再去執行等待執行的.所以下面的線程 number 最大是4,當然這
     前提是你設置的超時時間大于任務執行完的時間.如果設置超時時間是
     0.1秒的話,任務等超時了還是會開啟另外的線程去執行任務,這樣就
     達不到控制并發量的要求了.
     */
    //理解信號量: 來自: http://www.lxweimin.com/p/ac11fe7ef78c
    /*
     一般可以用停車來比喻:
     停車場剩余4個車位,那么即使同時來了四輛車也能停的下。如果此
     時來了五輛車,那么就有一輛需要等待。信號量的值就相當于剩余車位
     的數目,dispatch_semaphore_wait函數就相當于來了一輛車,
     dispatch_semaphore_signal就相當于走了一輛車。停車位的剩余數目
     在初始化的時候就已經指明了(dispatch_semaphore_create(long 
     value)),調用一次dispatch_semaphore_signal,剩余的車位就增加
     一個;調用一次dispatch_semaphore_wait剩余車位就減少一個;當剩
     余車位為0時,再來車(即調用dispatch_semaphore_wait)就只能等
     待。有可能同時有幾輛車等待一個停車位。有些車主沒有耐心,給自己
     設定了一段等待時間,這段時間內等不到停車位就走了,如果等到了就
     開進去停車。而有些車主就像把車停在這,所以就一直等下去。
     */

dispatch_apply 快速迭代

可以給定指定的次數將block追加到指定的Dispatch Queue中,并且等待全部結束處理執行。

    dispatch_queue_t sky_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
    NSArray *array = @[@"北京",@"我愛你",@"濟南大學的遺憾",@"在濟南大學的操場望天空",@"濟南大學的食堂",@"夢游濟南大學"];
    //參數1: 要遍歷的次數
    //參數2: 在那個線程中
    //參數3: 回調
    dispatch_apply(array.count, sky_queue, ^(size_t index) {
        NSLog(@"%@",array[index]);
    });
    
    NSLog(@"xxxooo");
    /*
     運行結果:
     2017-01-26 21:48:46.007 GCDNotes[93665:10365139] 在濟南大學的操場望天空
     2017-01-26 21:48:46.007 GCDNotes[93665:10365141] 我愛你
     2017-01-26 21:48:46.007 GCDNotes[93665:10365138] 濟南大學的遺憾
     2017-01-26 21:48:46.007 GCDNotes[93665:10364896] 北京
     2017-01-26 21:48:46.007 GCDNotes[93665:10365139] 濟南大學的食堂
     2017-01-26 21:48:46.007 GCDNotes[93665:10365141] 夢游濟南大學
     2017-01-26 21:48:46.007 GCDNotes[93665:10364896] xxxooo
     */
     //無序.

dispatch_suspend和dispatch_resume

NSOperationQueue有暫停(suspend)和恢復(resume)。其實GCD中的隊列也有類似的功能。用法也非常簡單:
dispatch_suspend(queue)//暫停某個隊列
dispatch_resume(queue) //恢復某個隊列
這些函數不會影響到隊列中已經執行的任務,隊列暫停后,已經添加到隊列中但還沒有執行的任務不會執行,直到隊列被恢復。

例:

  1. 多線程中下載圖片,回到主線程刷新UI
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
       
        //多線程執行 ~
        NSURL *imageUrl = [NSURL URLWithString:@"http://b.hiphotos.baidu.com/image/pic/item/6a63f6246b600c33fe5527171e4c510fd8f9a1c5.jpg"];
        NSData *imageData = [NSData dataWithContentsOfURL:imageUrl];
        UIImage *image = [UIImage imageWithData:imageData];
        
        /*
         注意:
         如果想等UI更新完畢再執行后面的代碼, 那么使用同步函數
         如果不想等UI更新完畢就需要執行后面的代碼, 那么使用異步函數
         */
        dispatch_sync(dispatch_get_main_queue(), ^{
            //同步回到主線程刷新ui
            self.imageView.image = image;
        });
        
    });
  1. GCD 延遲
     //延遲1秒
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
        //這里傳入全局隊列會在子線程中執行block,如果傳入主隊列就會在主線程中執行block
        // ...
    });
  1. 一次執行(一般用來實現單列和全局就調用一次代碼的地方比如:時間計算那塊.特別是在復雜的列表頁面每次都去計算時間格式很消耗性能.加上這個滑動就會流暢很多.)
    //一次執行
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
    });

如果書寫有誤 望指出 ~

推薦:

多線程技術內幕
iOS多線程-從不會到熟練使用

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,197評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,415評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,104評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,884評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,647評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,130評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,208評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,366評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,887評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,737評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,939評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,478評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,174評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,586評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,827評論 1 283
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,608評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,914評論 2 372

推薦閱讀更多精彩內容