GCD相關(guān)總結(jié)

關(guān)鍵詞:異步執(zhí)行任務(wù)的技術(shù)巩搏、將應(yīng)用程序的線程管理用的代碼在系統(tǒng)級(jí)中實(shí)現(xiàn)、高效率暑诸。

舊的 API 實(shí)現(xiàn)
- (void)demoPerformSelector{
    [self performSelectorInBackground:@selector(doWork) withObject:nil];
}

- (void)doWork{
    NSLog(@"doWork........");
    [self performSelectorOnMainThread:@selector(doneWork) withObject:nil waitUntilDone:NO];
}

- (void)doneWork{
    NSLog(@"doneWork!");
}

使用 GCD 實(shí)現(xiàn)
dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"doWork........");
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"doneWork!");
        });
    });

1.Dispatch Queue 調(diào)度隊(duì)列

Dispatch Queue 先進(jìn)先出的屬性(FIFO) 執(zhí)行處理。有兩種 Dispatch Queue,一種是等待現(xiàn)在執(zhí)行中處理的 Serial Dispatch Queue(串行調(diào)度隊(duì)列)宜狐,另一種是不等待現(xiàn)在執(zhí)行中處理的 Concurrent Dispatch Queue(并行調(diào)度隊(duì)列)。
通過以下源碼蛇捌,比較這兩種 Dispatch Queue:

dispatch_async(queue,block0);
dispatch_async(queue,block1);
dispatch_async(queue,block2);
dispatch_async(queue,block3);
dispatch_async(queue,block4);
dispatch_async(queue,block5);

當(dāng) queue 為 Serial Dispatch Queue 時(shí)抚恒,因?yàn)橐鹊浆F(xiàn)在執(zhí)行中處理結(jié)束,所以首先執(zhí)行 block0络拌,block0執(zhí)行結(jié)束后俭驮,執(zhí)行 block1,如此重復(fù)春贸,同時(shí)執(zhí)行的處理數(shù)只能有1個(gè)混萝。即執(zhí)行該源代碼后,一定按照以下順序進(jìn)行處理萍恕。(block0逸嘀,block1,block2允粤,block3崭倘,block4,block5)类垫。
當(dāng) queue 為 Concurrent Dispatch Queue 時(shí)司光,因?yàn)椴挥玫却F(xiàn)在執(zhí)行中的處理結(jié)束,所以首先執(zhí)行 block0悉患,不管 block0 的執(zhí)行是否結(jié)束残家,都開始執(zhí)行后面的 block1,不管 block1執(zhí)行是否結(jié)束了售躁,都開始執(zhí)行后面的 block2坞淮,如此重復(fù)循環(huán)。
這樣雖然不用等待處理結(jié)束陪捷,可以并行執(zhí)行多個(gè)處理回窘,但并行執(zhí)行處理的數(shù)量取決于當(dāng)前系統(tǒng)的狀態(tài)。即 iOS 或 OS X 基于 Dispatch Queue 中的處理數(shù)揩局、CPU核數(shù)以及 CPU 負(fù)荷等當(dāng)前系統(tǒng)的狀態(tài)來決定 Concurrent Dispatch Queue 中并行執(zhí)行的處理數(shù)毫玖。所謂的“并行執(zhí)行”,就是使用多個(gè)線程同時(shí)執(zhí)行多個(gè)處理。

2.獲取 Dispatch Queue

使用 dispatch_queue_create 創(chuàng)建 Dispatch Queue

//創(chuàng)建 Serial Dispatch Queue
dispatch_queue_t mySerialDicpatchQueue = dispatch_queue_create("com.example.gcd.MySerialDispatchQueue", NULL);
//創(chuàng)建 Concurrent Dispatch Queue
dispatch_queue_t myConcurrentQueue = dispatch_queue_create("com.exmaple.gcd.MuConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);

需要注意的是 dispatch_queue_create函數(shù)可以創(chuàng)建任意多個(gè) Dispatch Queue付枫,當(dāng)生成多個(gè) Serial Dispatch Queue 時(shí)烹玉,雖然一個(gè) Seria Dispatch Queue 中同時(shí)只能執(zhí)行一個(gè)追加處理,但如果將處理分別追加到多個(gè) Serial Dispatch Queue 中阐滩,各個(gè) Serial Dispatch Queue 會(huì)分別執(zhí)行二打,即同時(shí)執(zhí)行多個(gè)處理。一旦生成 Serial Dispatch Queue 并追加處理掂榔,系統(tǒng)對(duì)于一個(gè) Serial Dispatch Queue 就只生成并使用一個(gè)線程继效。如果生成 N 個(gè) Serial Dispatch Queue,那么就生成 N 個(gè)線程装获。

Main Dispatch Queue 和 Global Dispatch Queue

Main Dispatch Queue瑞信,主線程隊(duì)列,是一個(gè) Serial Dispatch Queue

dispatch_queue_t mainQueue = dispatch_get_main_queue();

Global Dispatch Queue穴豫,全局隊(duì)列凡简,是 Concurrent Dispatch Queue,有四種優(yōu)先級(jí)High Priority精肃、Default Priority秤涩、Low PriorityBackground Priority司抱。

dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

3. dispatch_set_target_queue()設(shè)置參考隊(duì)列

dispatch_set_target_queue(dispatch_object_t object,
        dispatch_queue_t _Nullable queue);

該函數(shù)有兩種用法筐眷,第一種是設(shè)置 Dispatch Queue 的優(yōu)先級(jí)

第一個(gè)參數(shù)填需要更改優(yōu)先級(jí)的 Dispatch Queue,第二個(gè)參數(shù)填要與要指定的優(yōu)先級(jí)相同優(yōu)先級(jí)的 Global Dispatch Queue习柠。

dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("com.gcd.mySerialDispatchQueue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t globalQueueLowPriority = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);

dispatch_set_target_queue(mySerialDispatchQueue, globalQueueLowPriority);

第二種用法可以用來線程同步
當(dāng)我們想讓不同隊(duì)列中的任務(wù)同步的執(zhí)行時(shí)匀谣,我們可以創(chuàng)建一個(gè)串行隊(duì)列,然后將這些隊(duì)列的 target 指向新創(chuàng)建的隊(duì)列

    dispatch_queue_t serailQueue1 = dispatch_queue_create("com.gcd.serialQueue1", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t serailQueue2 = dispatch_queue_create("com.gcd.serialQueue2", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t concurrentQueue1 = dispatch_queue_create("com.gcd.concurrentQueue1", DISPATCH_QUEUE_CONCURRENT);
    dispatch_queue_t concurrentQueue2 = dispatch_queue_create("com.gcd.concurrentQueue2", DISPATCH_QUEUE_CONCURRENT);
    
    //創(chuàng)建目標(biāo)隊(duì)列(參考隊(duì)列)
    dispatch_queue_t targetQueue = dispatch_queue_create("com.gcd.targetQueue", DISPATCH_QUEUE_SERIAL);
    //設(shè)置參考
    dispatch_set_target_queue(serailQueue1, targetQueue);
    dispatch_set_target_queue(serailQueue2, targetQueue);
    dispatch_set_target_queue(concurrentQueue1, targetQueue);
    dispatch_set_target_queue(concurrentQueue2, targetQueue);

    NSLog(@"******start******");
    dispatch_async(serailQueue1, ^{
        NSLog(@"current Thread:%@ task1",[NSThread currentThread]);
        sleep(3);
        NSLog(@"task1 end");
    });
    dispatch_async(serailQueue2, ^{
        NSLog(@"current Thread:%@ task2",[NSThread currentThread]);
        sleep(2);
        NSLog(@"task2 end");
    });
    dispatch_async(concurrentQueue1, ^{
        NSLog(@"current Thread:%@ task3",[NSThread currentThread]);
        sleep(1);
        NSLog(@"task3 end");
    });
    dispatch_async(concurrentQueue2, ^{
        NSLog(@"current Thread:%@ task4",[NSThread currentThread]);
        NSLog(@"task4 end");
    });
    NSLog(@"******end******");

輸出結(jié)果:

******start******
******end******
current Thread:<NSThread: 0x600000468580>{number = 5, name = (null)} task1 
task1 end
current Thread:<NSThread: 0x600000468580>{number = 5, name = (null)} task2
task2 end
current Thread:<NSThread: 0x600000468580>{number = 5, name = (null)} task3
task3 end
current Thread:<NSThread: 0x600000468580>{number = 5, name = (null)} task4
task4 end

通過dispatch_set_target_queue()函數(shù)以及參考隊(duì)列targetQueue津畸,使得串行隊(duì)列serailQueue1,serailQueue2與并行隊(duì)列concurrentQueue1,concurrentQueue2同步振定。

4. dispatch_after()延時(shí)執(zhí)行(準(zhǔn)確的說是追加任務(wù))

dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3ull * NSEC_PER_SEC);
dispatch_after(time, dispatch_get_main_queue(), ^{
    NSLog(@"**********************");
});

注意:
dispatch_after()函數(shù)并不是在指定時(shí)間后執(zhí)行任務(wù)必怜,而是在指定時(shí)間追加任務(wù)到 Dispatch Queue 中肉拓。
示例中與3秒后用 dispatch_async()函數(shù)追加 block 中的任務(wù)到 Main Dispatch Queue 相同。
Main Dispatch Queue 在主線程的 RunLoop 中執(zhí)行梳庆,假設(shè)每隔 1/60秒執(zhí)行一次的 RunLoop暖途,block 最快在3s 后執(zhí)行,最慢在 3+1/60 秒后執(zhí)行膏执,并且在 Main Dispatch Queue 中有大量追加的任務(wù)或者主線程本身處理有延遲時(shí)驻售,時(shí)間會(huì)更長(zhǎng)。
dispatch_time_t 表示的是一個(gè)時(shí)刻更米,可以由 dispatch_time()函數(shù)或者 dispatch_walltime()函數(shù)獲得
dispatch_time()函數(shù) 能夠獲取從第一個(gè)參數(shù)指定的時(shí)間開始欺栗,到第二個(gè)參數(shù)指定的納秒(毫微秒)后的時(shí)間 常用于計(jì)算相對(duì)時(shí)間
dispatch_walltime()函數(shù)由 POSIX 中使用的 struct timespec 類型的時(shí)間得到 dispatch_time_t 類型的值,常用計(jì)算絕對(duì)時(shí)間

 //ull 數(shù)值字面量(unsigned long long) DISPATCH_TIME_NOW 表示現(xiàn)在的時(shí)間
 //獲取從現(xiàn)在開始1s 后的時(shí)間
 dispatch_time_t time1 = dispatch_time(DISPATCH_TIME_NOW, 1ull * NSEC_PER_SEC);
 //獲取從現(xiàn)在開始100毫秒后的時(shí)間
 dispatch_time_t time2 = dispatch_time(DISPATCH_TIME_NOW, 150ull * NSEC_PER_MSEC);
    // 通過 NSDate 對(duì)象獲取 dispatch_time_t 類型值
    dispatch_time_t getDispatchTimeByDate(NSDate *date){
    NSTimeInterval interval = [date timeIntervalSince1970];
    double second;
    double subsecond = modf(interval, &second);
    struct timespec time;
    time.tv_sec = second;
    time.tv_nsec = subsecond * NSEC_PER_SEC;
    dispatch_time_t milestone = dispatch_walltime(&time, 0);
    return milestone;
}

5. Dispatch Group

Dispatch Group可以用于在追加到 Dispatch Queue 中的多個(gè)任務(wù)全部結(jié)束后想執(zhí)行的結(jié)束任務(wù)的操作。

  • dispatch_group_create()創(chuàng)建 Dispatch Group
  • dispatch_group_async()追加任務(wù)到指定的 Dispatch Queue 中迟几,且指定任務(wù)屬于指定的 Dispatch Group
  • dispatch_group_notify()所有任務(wù)執(zhí)行完畢后再追加執(zhí)行的任務(wù)
  • dispatch_group_wati() 在指定的等待時(shí)間前(超時(shí)時(shí)間)消请,等待 group 中全部任務(wù)處理結(jié)束,會(huì)卡住當(dāng)前線程
    dispatch_queue_t serialQueue = dispatch_queue_create("com.gcd.serialQueue", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t conCurrentQueue = dispatch_queue_create("com.gcd.conCurrentQueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_t group = dispatch_group_create();
    
    NSLog(@"******start******");
    dispatch_group_async(group, serialQueue, ^{
        NSLog(@"current Thread:%@ task1",[NSThread currentThread]);
        sleep(3);
        NSLog(@"task1 end");
    });
    dispatch_group_async(group, conCurrentQueue, ^{
        NSLog(@"current Thread:%@ task2",[NSThread currentThread]);
        sleep(2);
        NSLog(@"task2 end");
    });
    dispatch_group_async(group, serialQueue, ^{
        NSLog(@"current Thread:%@ task3",[NSThread currentThread]);
        sleep(1);
        NSLog(@"task3 end");
    });
    dispatch_group_async(group, conCurrentQueue, ^{
        NSLog(@"current Thread:%@ task4",[NSThread currentThread]);
        NSLog(@"task4 end");
    });
    
    //第二個(gè)參數(shù)填超時(shí)時(shí)間 DISPATCH_TIME_FOREVER 表示永遠(yuǎn)等待
//    long result = dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    // 設(shè)置2秒的超時(shí)時(shí)間
    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 2ull * NSEC_PER_SEC);
    long result = dispatch_group_wait(group, time);
    if (result == 0) {
        NSLog(@"Group 中所有任務(wù)執(zhí)行完畢");
    }else{
        
        NSLog(@"Group 中任有任務(wù)執(zhí)行中");
    }
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"current Thread:%@ All END",[NSThread currentThread]);
    });
    NSLog(@"******end******");

6. dispatch_barrier_async

dispatch_barrier_async函數(shù)可以理解為一種分割任務(wù)的柵欄类腮,通過dispatch_barrier_async追加的任務(wù)同時(shí)只執(zhí)行一個(gè)

    dispatch_async(conCurrentQueue, read_block1);
    dispatch_async(conCurrentQueue, read_block2);
    dispatch_async(conCurrentQueue, read_block3);
    
    dispatch_barrier_async(conCurrentQueue, write_block4);

    dispatch_async(conCurrentQueue, read_block5);
    dispatch_async(conCurrentQueue, read_block6);
    dispatch_async(conCurrentQueue, read_block7);

示例中 block1臊泰,block2,block3 并行執(zhí)行蚜枢,都執(zhí)行完畢后會(huì)執(zhí)行 write_block4缸逃,然后block5,block6厂抽,block7再并行執(zhí)行需频。
使用 Concurrent Dispatch Queue 配合 dispatch_barrier_async 函數(shù)可以實(shí)現(xiàn)高效的數(shù)據(jù)庫訪問和文件訪問。

7. dispatch_sync

dispatch_sync同步追加任務(wù)到隊(duì)列中筷凤,不能開辟線程贺辰,且只有在追加的任務(wù)完成后才返回

dispatch_sync 函數(shù)引起死鎖問題

產(chǎn)生死鎖的條件是在串行隊(duì)列所在的線程中,使用 dispatch_sync 函數(shù)追加任務(wù)到該串行隊(duì)列中嵌施。

示例一

 //在主線程中調(diào)用以下代碼會(huì)產(chǎn)生死鎖
 dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@"死鎖~~");
            NSLog(@"current thread:%@",[NSThread currentThread]);
        });

示例二

 dispatch_queue_t serialDispatchQueue = dispatch_queue_create("com.gcd.serialDispatchQueue", NULL);
    dispatch_async(serialDispatchQueue, ^{
        NSLog(@"current thread:%@",[NSThread currentThread]);
        dispatch_sync(serialDispatchQueue, ^{
            NSLog(@"死鎖");
        });
    });

示例一:由于主線程所在的隊(duì)列 Main Dispatch Queue 為一個(gè)串行隊(duì)列饲化,所以在主線程中使用dispatch_sync函數(shù)同步追加任務(wù)到 Main Dispatch Queue 中會(huì)產(chǎn)生死鎖。
示例二:創(chuàng)建了串行隊(duì)列 serialDispatchQueue吗伤,使用dispatch_async異步追加任務(wù)到該隊(duì)列吃靠,此時(shí)該隊(duì)列中的任務(wù)都是在該隊(duì)列的線程上執(zhí)行,此時(shí)使用dispatch_sync函數(shù)再同步追加任務(wù)到該隊(duì)列中足淆,由于是在串行隊(duì)列所在的線程中同步追加任務(wù)巢块,所以產(chǎn)生了死鎖。

dispatch_sync 函數(shù)引起死鎖的原因

  • 調(diào)用dispatch_sync函數(shù)會(huì)立即阻塞調(diào)用時(shí)該函數(shù)所在的線程巧号,等待dispatch_sync函數(shù)返回
  • 由于追加任務(wù)的隊(duì)列為串行隊(duì)列所以族奢,采用 FIFO 的順序執(zhí)行任務(wù),很顯然我們追加的任務(wù)位于隊(duì)列后面丹鸿,現(xiàn)在不會(huì)立即執(zhí)行
  • 如果任務(wù)不執(zhí)行完越走,dispatch_sync函數(shù)不會(huì)返回,所以線程會(huì)一直被阻塞

8. dispatch_apply

dispatch_apply函數(shù)會(huì)按指定的次數(shù)將任務(wù) block 追加到指定的 Dispatch Queue 中靠欢,并等待全部處理執(zhí)行結(jié)束廊敌。

   dispatch_queue_t concurrentDispatchQueue = dispatch_queue_create("com.gcd.concurrentDispatchQueue", DISPATCH_QUEUE_CONCURRENT);
   dispatch_apply(5, concurrentDispatchQueue, ^(size_t index) {
        NSLog(@"%zu current thread:%@",index,[NSThread currentThread]);
    });
    NSLog(@"******end******");

執(zhí)行結(jié)果:0,2门怪,1骡澈,3,4掷空,5 end
因?yàn)槭窃?Concurrent Dispatch Queue 中執(zhí)行任務(wù)的肋殴,所以幾個(gè)任務(wù)是并行執(zhí)行囤锉。

注意: dispatch_apply函數(shù)會(huì)阻塞當(dāng)前線程,等待任務(wù)全部執(zhí)行完畢再返回护锤,所以在主線程中調(diào)用追加任務(wù)到 Main Dispatch Queue 會(huì)造成死鎖嚼锄。

9. dispatch_suspenddispatch_resume函數(shù)

dispatch_suspend函數(shù)用于掛起指定的 Dispatch Queue
dispatch_resume函數(shù)用于恢復(fù)指定的 Dispatch Queue
這些函數(shù)對(duì)已經(jīng)開始執(zhí)行的任務(wù)沒有影響,掛起后蔽豺,追加到 Dispatch Queue 中区丑,但尚未執(zhí)行的任務(wù)在此之后會(huì)暫停執(zhí)行(任務(wù)仍然可以繼續(xù)追加,但新追加的也會(huì)暫停執(zhí)行)修陡,而恢復(fù)則使得這些任務(wù)繼續(xù)執(zhí)行沧侥。

10. Dispatch Semaphore 信號(hào)量

Dispatch Semaphore 信號(hào)量在 GCD 常被用于進(jìn)行同步和控制并發(fā)。
信號(hào)量是一個(gè)整形值并且具有一個(gè)初始計(jì)數(shù)值魄鸦,并且支持兩個(gè)操作:信號(hào)通知和等待宴杀。當(dāng)一個(gè)信號(hào)量被信號(hào)通知,其計(jì)數(shù)會(huì)被加1拾因。當(dāng)在一個(gè)線程上設(shè)置一個(gè)信號(hào)量等待時(shí)旺罢,線程會(huì)被阻塞至超時(shí)時(shí)間(如果有必要的話可以設(shè)置為一直阻塞),只有當(dāng)計(jì)數(shù)器大于零绢记,計(jì)數(shù)才會(huì)被減1并且該線程恢復(fù)扁达。
信號(hào)量可以被用來作為線程鎖,也可以用來控制并發(fā)線程數(shù)蠢熄。

       //如果設(shè)置為10的話跪解,并發(fā)線程最多為10個(gè)
//    dispatch_semaphore_t sema = dispatch_semaphore_create(10);
    //如果設(shè)置為1的話,并發(fā)線程為1個(gè)签孔,可以保證數(shù)據(jù)安全
    dispatch_semaphore_t sema = dispatch_semaphore_create(1);
    dispatch_queue_t gloabQueue = dispatch_get_global_queue(0, 0);
    NSMutableArray *array = [NSMutableArray arrayWithCapacity:100];
    for (int i = 0; i < 100; i++) {
        dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
        dispatch_async(gloabQueue, ^{
            NSLog(@"thread%@ add %d",[NSThread currentThread] ,i);
            [array addObject:@(i)];
            dispatch_semaphore_signal(sema);
        });
    }

11. dispatch_once

dispatch_once函數(shù)是保證在應(yīng)用程序執(zhí)行中執(zhí)行一次指定處理的 API叉讥。
使用dispatch_once函數(shù)生成單利,即使在多線程情況下執(zhí)行饥追,也可保證百分百安全图仓。

    static dispatch_once_t pred;
    dispatch_once(&pred, ^{
        NSLog(@"只會(huì)執(zhí)行一次");
    });
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市但绕,隨后出現(xiàn)的幾起案子救崔,更是在濱河造成了極大的恐慌,老刑警劉巖壁熄,帶你破解...
    沈念sama閱讀 221,198評(píng)論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件帚豪,死亡現(xiàn)場(chǎng)離奇詭異碳竟,居然都是意外死亡草丧,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門莹桅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來昌执,“玉大人烛亦,你說我怎么就攤上這事《埃” “怎么了煤禽?”我有些...
    開封第一講書人閱讀 167,643評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)岖赋。 經(jīng)常有香客問我檬果,道長(zhǎng),這世上最難降的妖魔是什么唐断? 我笑而不...
    開封第一講書人閱讀 59,495評(píng)論 1 296
  • 正文 為了忘掉前任选脊,我火速辦了婚禮,結(jié)果婚禮上脸甘,老公的妹妹穿的比我還像新娘恳啥。我一直安慰自己,他們只是感情好丹诀,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評(píng)論 6 397
  • 文/花漫 我一把揭開白布钝的。 她就那樣靜靜地躺著,像睡著了一般铆遭。 火紅的嫁衣襯著肌膚如雪硝桩。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,156評(píng)論 1 308
  • 那天枚荣,我揣著相機(jī)與錄音亿柑,去河邊找鬼。 笑死棍弄,一個(gè)胖子當(dāng)著我的面吹牛望薄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播呼畸,決...
    沈念sama閱讀 40,743評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼痕支,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了蛮原?” 一聲冷哼從身側(cè)響起卧须,我...
    開封第一講書人閱讀 39,659評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎儒陨,沒想到半個(gè)月后花嘶,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,200評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蹦漠,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評(píng)論 3 340
  • 正文 我和宋清朗相戀三年椭员,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片笛园。...
    茶點(diǎn)故事閱讀 40,424評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡隘击,死狀恐怖侍芝,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情埋同,我是刑警寧澤州叠,帶...
    沈念sama閱讀 36,107評(píng)論 5 349
  • 正文 年R本政府宣布,位于F島的核電站凶赁,受9級(jí)特大地震影響咧栗,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜虱肄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評(píng)論 3 333
  • 文/蒙蒙 一楼熄、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧浩峡,春花似錦可岂、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至纸淮,卻和暖如春平斩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背咽块。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評(píng)論 1 271
  • 我被黑心中介騙來泰國打工绘面, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人侈沪。 一個(gè)月前我還...
    沈念sama閱讀 48,798評(píng)論 3 376
  • 正文 我出身青樓揭璃,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親亭罪。 傳聞我的和親對(duì)象是個(gè)殘疾皇子瘦馍,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評(píng)論 2 359

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