OC 多線程:NSThread卸例,GCD称杨,NSOperation

OC 常用的多線程實現(xiàn)方法有:

  • NSThread
  • GCD
  • NSOperation

下面逐一總結(jié)一下。

NSThread

NSThread是官方提供的筷转,面向?qū)ο蟮膭?chuàng)建多線程的方法姑原。

NSThread可以隨時查看當(dāng)前代碼所在的線程。比如:

NSLog(@"%@", [NSThread currentThread]);
// <NSThread: 0x6000007f0000>{number = 1, name = main}

NSThread可以使用類方法快速創(chuàng)建子線程呜舒,但是得不到子線程對象锭汛,線程自動開啟。比如:

[NSThread detachNewThreadWithBlock:^{
  NSLog(@"%@", [NSThread currentThread]);
  // <NSThread: 0x60000288a9c0>{number = 7, name = (null)}
}];

NSThread可以使用對象方法創(chuàng)建子線程,能夠得到子線程對象唤殴,需要調(diào)用start方法手動開啟子線程般婆。

self.thread = [[NSThread alloc] initWithBlock: ^{
  NSLog(@"%@", [NSThread currentThread]);
  // <NSThread: 0x60000031d980>{number = 7, name = my thread}
}];
self.thread.name = @"my thread";
[self.thread start];

NSThread可以結(jié)束子線程、可以隨時查看線程的狀態(tài)(正在執(zhí)行朵逝、被取消蔚袍、結(jié)束)。

self.thread = [[NSThread alloc] initWithBlock: ^{
  NSLog(@"當(dāng)前線程%@", [NSThread currentThread]);
  NSLog(@"isExecuting=%d", self.thread.isExecuting);
  NSLog(@"isCancelled=%d", self.thread.isCancelled);
  NSLog(@"isFinished=%d", self.thread.isFinished);
  for (int i = 0; i < 100; i++) {
    NSLog(@"i = %d", i);
    if (i == 6) {
      NSLog(@"結(jié)束線程%@", [NSThread currentThread]);
      //結(jié)束線程
      [NSThread exit];
      NSLog(@"這行代碼不會打印的");
    }
  }
}];

self.thread.name = @"my thread";

[self.thread start];

[NSThread sleepForTimeInterval:2];

NSLog(@"isExecuting=%d", self.thread.isExecuting);
NSLog(@"isCancelled=%d", self.thread.isCancelled);
NSLog(@"isFinished=%d", self.thread.isFinished);

// 當(dāng)前線程<NSThread: 0x6000003ed740>{number = 7, name = my thread}
// isExecuting=1
// isCancelled=0
// isFinished=0
// i = 0
// i = 1
// i = 2
// i = 3
// i = 4
// i = 5
// i = 6
// 結(jié)束線程<NSThread: 0x6000003ed740>{number = 7, name = my thread}
// isExecuting=0
// isCancelled=0
// isFinished=1

我們可以看到配名,exit方法可以終止線程的執(zhí)行啤咽,執(zhí)行exit方法可以把isExecuting從1設(shè)為0,把isFinished從0設(shè)為1渠脉,而isCancelled不受影響闰蚕,這說明cancel只是一個屬性,并不能真正的取消當(dāng)前線程连舍。

GCD

GCD(Grand Central Dispatch)是蘋果官方開發(fā)的解決多線程的一種方案没陡。GCD引入了兩個核心概念,任務(wù)隊列索赏,來抽象多線程的創(chuàng)建和調(diào)用盼玄。理解任務(wù)和隊列是正確使用GCD的關(guān)鍵。

任務(wù)又分為同步任務(wù)(sync)和異步任務(wù)(async)

  • 同步任務(wù):把任務(wù)添加到當(dāng)前線程中潜腻,不開啟新的線程埃儿,在任務(wù)完成之前阻塞當(dāng)前線程,都是串行執(zhí)行任務(wù)
  • 異步任務(wù):可以開啟新的線程融涣,任務(wù)可以添加到新的線程中童番,不阻塞當(dāng)前線程

隊列又分為串行隊列(serial)和并發(fā)隊列(concurrent)

  • 串行隊列:在一個線程中,一個接一個的完成任務(wù)威鹿,先進先出(FIFO)
  • 并發(fā)隊列:在一個或多個線程中剃斧,并發(fā)的完成任務(wù)(后添加的任務(wù)不用等待前添加的任務(wù)先完成)

基于以上分類,我們可以得出一些推論:

  • 并發(fā)隊列只有在異步任務(wù)中才有效忽你,因為在同步任務(wù)中幼东,不能開啟新線程,并發(fā)隊列還是只能一個接一個的完成科雳,這就相當(dāng)于串行隊列

開發(fā)中常用的隊列有四種根蟹,分別是:

  • 自定義串行隊列:當(dāng)前線程中建立的串行隊列,在當(dāng)前線程中糟秘,dispatch_queue_create("CXqueue", DISPATCH_QUEUE_SERIAL);
  • 自定義并發(fā)隊列:當(dāng)前線程中建立的并發(fā)隊列简逮,因為是并發(fā),所以可以在任意線程尿赚,dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
  • 全局隊列:全局中的并發(fā)隊列散庶,因為是并發(fā)蕉堰,所以可以在任意線程,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  • 主隊列:主線程中的主隊列督赤,是串行隊列嘁灯,dispatch_get_main_queue()

這里可以看出,自定義并發(fā)隊列和全局隊列的作用很相似躲舌。

下面討論一下不同任務(wù)和隊列和組合:

  • 同步任務(wù)+自定義串行隊列
  • 同步任務(wù)+自定義并發(fā)隊列
  • 異步任務(wù)+自定義串行隊列
  • 異步任務(wù)+自定義并發(fā)隊列
  • 同步任務(wù)+主隊列
  • 異步任務(wù)+主隊列
  • 同步任務(wù)+全局隊列
  • 異步任務(wù)+全局隊列

同步任務(wù)+自定義串行隊列

dispatch_queue_t q = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);

NSLog(@"開始");
dispatch_sync(q, ^{
  NSLog(@"任務(wù)一");
  NSLog(@"當(dāng)前線程:%@",[NSThread currentThread]);
});
dispatch_sync(q, ^{
  [NSThread sleepForTimeInterval:2.0];
  NSLog(@"任務(wù)二丑婿,睡了2秒");
  NSLog(@"當(dāng)前線程:%@",[NSThread currentThread]);
});
dispatch_sync(q, ^{
  NSLog(@"任務(wù)三");
  NSLog(@"當(dāng)前線程:%@",[NSThread currentThread]);
});
NSLog(@"結(jié)束");

// 開始
// 任務(wù)一
// 當(dāng)前線程:<NSThread: 0x6000039dc100>{number = 1, name = main}
// 任務(wù)二,睡了2秒
// 當(dāng)前線程:<NSThread: 0x6000039dc100>{number = 1, name = main}
// 任務(wù)三
// 當(dāng)前線程:<NSThread: 0x6000039dc100>{number = 1, name = main}
// 結(jié)束

可以看到没卸,任務(wù)一羹奉,二,三约计,一個接一個的完成了诀拭,而且都在線程1中(主線程main)。

同步任務(wù)+自定義并行隊列

dispatch_queue_t q = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);

NSLog(@"開始");
dispatch_sync(q, ^{
    NSLog(@"任務(wù)一");
    NSLog(@"當(dāng)前線程:%@",[NSThread currentThread]);
});
dispatch_sync(q, ^{
    [NSThread sleepForTimeInterval:2.0];
    NSLog(@"任務(wù)二煤蚌,睡了2秒");
    NSLog(@"當(dāng)前線程:%@",[NSThread currentThread]);
});
dispatch_sync(q, ^{
    NSLog(@"任務(wù)三");
    NSLog(@"當(dāng)前線程:%@",[NSThread currentThread]);
});
NSLog(@"結(jié)束");

// 開始
// 任務(wù)一
// 當(dāng)前線程:<NSThread: 0x600000380980>{number = 1, name = main}
// 任務(wù)二耕挨,睡了2秒
// 當(dāng)前線程:<NSThread: 0x600000380980>{number = 1, name = main}
// 任務(wù)三
// 當(dāng)前線程:<NSThread: 0x600000380980>{number = 1, name = main}
// 結(jié)束

可以看到,任務(wù)一尉桩,二筒占,三,一個接一個的完成了蜘犁,而且都在線程1中翰苫,這說明并發(fā)隊列在同步任務(wù)中相當(dāng)于串行隊列。

異步任務(wù)+自定義串行隊列

dispatch_queue_t q = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);

NSLog(@"當(dāng)前線程:%@", [NSThread currentThread]);

NSLog(@"開始");
dispatch_async(q, ^{
    NSLog(@"任務(wù)一");
    NSLog(@"當(dāng)前線程:%@",[NSThread currentThread]);
});
dispatch_async(q, ^{
    [NSThread sleepForTimeInterval:2.0];
    NSLog(@"任務(wù)二这橙,睡了2秒");
    NSLog(@"當(dāng)前線程:%@",[NSThread currentThread]);
});
dispatch_async(q, ^{
    NSLog(@"任務(wù)三");
    NSLog(@"當(dāng)前線程:%@",[NSThread currentThread]);
});
NSLog(@"結(jié)束");

// 當(dāng)前線程:<NSThread: 0x60000357c000>{number = 1, name = main}
// 開始
// 結(jié)束
// 任務(wù)一
// 當(dāng)前線程:<NSThread: 0x600003545c40>{number = 6, name = (null)}
// 任務(wù)二奏窑,睡了2秒
// 當(dāng)前線程:<NSThread: 0x600003545c40>{number = 6, name = (null)}
// 任務(wù)三
// 當(dāng)前線程:<NSThread: 0x600003545c40>{number = 6, name = (null)}

可以看到,任務(wù)一屈扎,二埃唯,三是一個接一個完成,的確是串行的助隧,但他們都被放到了線程6去執(zhí)行了筑凫,這是因為異步任務(wù)的原因,還是就是打印開始之后并村,馬上就是打印結(jié)束,這說明異步任務(wù)的創(chuàng)建需要時間滓技,異步任務(wù)開始前哩牍,主線程已經(jīng)完成打印了

異步任務(wù)+自定義并行隊列

dispatch_queue_t q = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);

NSLog(@"當(dāng)前線程:%@", [NSThread currentThread]);

NSLog(@"開始");
dispatch_async(q, ^{
    NSLog(@"任務(wù)一");
    NSLog(@"當(dāng)前線程:%@",[NSThread currentThread]);
});
dispatch_async(q, ^{
    [NSThread sleepForTimeInterval:2.0];
    NSLog(@"任務(wù)二,睡了2秒");
    NSLog(@"當(dāng)前線程:%@",[NSThread currentThread]);
});
dispatch_async(q, ^{
    NSLog(@"任務(wù)三");
    NSLog(@"當(dāng)前線程:%@",[NSThread currentThread]);
});
NSLog(@"結(jié)束");

// 當(dāng)前線程:<NSThread: 0x600003cd8300>{number = 1, name = main}
// 開始
// 結(jié)束
// 任務(wù)一
// 任務(wù)三
// 當(dāng)前線程:<NSThread: 0x600003cea3c0>{number = 3, name = (null)}
// 當(dāng)前線程:<NSThread: 0x600003cc0e40>{number = 6, name = (null)}
// 任務(wù)二令漂,睡了2秒
// 當(dāng)前線程:<NSThread: 0x600003cff880>{number = 5, name = (null)}

可以看到膝昆,任務(wù)一丸边,二,三并放到了三個不同的線程中去執(zhí)行荚孵,并且執(zhí)行的時候是并發(fā)的(不是一個接一個的完成)

同步任務(wù)+主隊列(重點來了)

dispatch_queue_t q = dispatch_get_main_queue();

NSLog(@"當(dāng)前線程:%@", [NSThread currentThread]);

NSLog(@"開始");
dispatch_sync(q, ^{  // Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
    NSLog(@"任務(wù)一");
    NSLog(@"當(dāng)前線程:%@",[NSThread currentThread]);
});
dispatch_sync(q, ^{
    [NSThread sleepForTimeInterval:2.0];
    NSLog(@"任務(wù)二妹窖,睡了2秒");
    NSLog(@"當(dāng)前線程:%@",[NSThread currentThread]);
});
dispatch_sync(q, ^{
    NSLog(@"任務(wù)三");
    NSLog(@"當(dāng)前線程:%@",[NSThread currentThread]);
});
NSLog(@"結(jié)束");

奔潰了,原因是發(fā)生了死鎖收叶,為什么呢骄呼?

我們就拿任務(wù)一進行分析。

因為在主線程中判没,dispatch_sync也是一個任務(wù)蜓萄,因為阻塞線程,現(xiàn)在被添加到了主隊列澄峰,dispatch_sync中的任務(wù)(任務(wù)一)也添加到了主隊列嫉沽,任務(wù)一完成后dispatch_sync才能返回(完成),而按照串行隊列的定義俏竞,dispatch_sync完成后绸硕,任務(wù)一才能執(zhí)行,因此魂毁,dispatch_sync與任務(wù)一之間創(chuàng)造了死鎖玻佩。

同樣都是串行隊列,為什么主隊列會死鎖漱牵,而自定義串行隊列不會呢夺蛇?

因為如果是自定義串行隊列,dispatch_sync中的任務(wù)(任務(wù)一)被添加到自定義的隊列中酣胀,這樣任務(wù)一在自定義串行隊列中刁赦,不用等待dispatch_sync完成才開始執(zhí)行,自己就執(zhí)行了闻镶,dispatch_sync等任務(wù)一完成后甚脉,就返回了,所以沒有造成死鎖铆农。

異步任務(wù)+主隊列

dispatch_queue_t q = dispatch_get_main_queue();

NSLog(@"當(dāng)前線程:%@", [NSThread currentThread]);

NSLog(@"開始");
dispatch_async(q, ^{
    NSLog(@"任務(wù)一");
    NSLog(@"當(dāng)前線程:%@",[NSThread currentThread]);
});
dispatch_async(q, ^{
    [NSThread sleepForTimeInterval:2.0];
    NSLog(@"任務(wù)二牺氨,睡了2秒");
    NSLog(@"當(dāng)前線程:%@",[NSThread currentThread]);
});
dispatch_async(q, ^{
    NSLog(@"任務(wù)三");
    NSLog(@"當(dāng)前線程:%@",[NSThread currentThread]);
});
NSLog(@"結(jié)束");

// 當(dāng)前線程:<NSThread: 0x6000017e8900>{number = 1, name = main}
// 開始
// 結(jié)束
// 任務(wù)一
// 當(dāng)前線程:<NSThread: 0x6000017e8900>{number = 1, name = main}
// 任務(wù)二,睡了2秒
// 當(dāng)前線程:<NSThread: 0x6000017e8900>{number = 1, name = main}
// 任務(wù)三
// 當(dāng)前線程:<NSThread: 0x6000017e8900>{number = 1, name = main}

可以看到墩剖,因為是同步任務(wù)猴凹,任務(wù)一,二岭皂,三還是按照串行的方式執(zhí)行的郊霎,而且都在主線程中執(zhí)行,因為dispatch_async不阻塞當(dāng)前線程(不用等待里面的任務(wù)完成之后才返回)爷绘,所以不造成死鎖书劝,同時我們注意到进倍,異步任務(wù)沒有開啟新的線程,這和異步任務(wù)+自定義串行隊列有區(qū)別购对。

同步任務(wù)+全局隊列

與同步任務(wù)+自定義并行隊列結(jié)果一樣

異步任務(wù)+全局隊列

與異步任務(wù)+自定義并行隊列結(jié)果一樣

總結(jié):

  • GCD的使用步驟:

    1. 創(chuàng)建或者獲取隊列(串行猾昆、并發(fā),主隊列骡苞,全局隊列)
    2. 創(chuàng)建任務(wù)(同步垂蜗、異步)
    3. 把任務(wù)放在隊列中執(zhí)行
  • 同步任務(wù)+自定義串行隊列:不開啟新線程,串行執(zhí)行

  • 同步任務(wù)+自定義并發(fā)隊列:不開啟新線程烙如,串行執(zhí)行

  • 異步任務(wù)+自定義串行隊列:開啟新線程么抗,串行執(zhí)行

  • 異步任務(wù)+自定義并發(fā)隊列:開啟新線程,并行執(zhí)行

  • 同步任務(wù)+主隊列:死鎖

  • 異步任務(wù)+主隊列:不開啟新線程亚铁,串行執(zhí)行

  • 同步任務(wù)+全局隊列:開啟新線程蝇刀,串行執(zhí)行

  • 異步任務(wù)+全局隊列:開啟新線程,并行執(zhí)行

NSOperation

NSOperation的使用和GCD類似徘溢,也是三步:

  • 將任務(wù)封裝到NSOperation對象中
  • NSOperation對象添加到NSOperationQueue
  • 系統(tǒng)將NSOperationQueue中的NSOperation中的任務(wù)取出來放到一條新線程中執(zhí)行吞琐。

NSOperation是一個抽象類,不具備封裝操作的能力然爆,必須使用它的子類站粟,他的子類有:NSInvocationOperation, NSBlockOperation, 或者自定義子類。

NSInvocationOperation可以直接start任務(wù)(在主線程):

- (void)viewDidLoad {
    [super viewDidLoad];
    NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(test) object:nil];
    [operation start];
}

- (void)test {
    NSLog(@"----任務(wù)開始----");
    NSLog(@"當(dāng)前線程:%@", [NSThread currentThread]);
}

// ----任務(wù)開始----
// 當(dāng)前線程:<NSThread: 0x600002f2c3c0>{number = 1, name = main}

NSBlockOperation可以直接start任務(wù)(在主線程)曾雕,還可以追加任務(wù)奴烙,追加的任務(wù)在子線程(是并行的):

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // NSBlockOperation
    NSBlockOperation * operation = [NSBlockOperation blockOperationWithBlock:^{
        // 要執(zhí)行的操作,目前是主線程
        NSLog(@"NSBlockOperation 創(chuàng)建剖张,當(dāng)前線程:%@",[NSThread currentThread]);
    }];
    // 追加任務(wù)切诀,在子線程中執(zhí)行
    [operation addExecutionBlock:^{
        NSLog(@"追加任務(wù)一");
        [self test];
    }];
    [operation addExecutionBlock:^{
        NSLog(@"追加任務(wù)二, %@",[NSThread currentThread]);
    }];
    [operation start];

}

- (void)test {
    NSLog(@"----任務(wù)開始----");
    NSLog(@"當(dāng)前線程:%@", [NSThread currentThread]);
}

// 追加任務(wù)一
// NSBlockOperation 創(chuàng)建,當(dāng)前線程:<NSThread: 0x600003af4380>{number = 1, name = main}
// 追加任務(wù)二, <NSThread: 0x600003aeaa40>{number = 3, name = (null)}
// ----任務(wù)開始----
// 當(dāng)前線程:<NSThread: 0x600003aa9000>{number = 6, name = (null)}

自定義子類:

@interface BZOperation : NSOperation
@end

@implementation BZOperation
-(void) main {
    NSLog(@"我是自定義NSOperation搔弄,當(dāng)前線程:%@", [NSThread currentThread]);
}
@end

BZOperation * operation = [[BZOperation alloc] init];
[operation start];

// 我是自定義NSOperation幅虑,當(dāng)前線程:<NSThread: 0x600002a64440>{number = 1, name = main}

下面總結(jié)NSOperationQueue

NSOperationQueue相當(dāng)于GCD中的隊列,將NSOperation加入到NSOperationQueue后顾犹,就自動執(zhí)行NSOperation中的任務(wù)了倒庵,不需要執(zhí)行start方法。

主要有兩種隊列:

  • 主隊列:在主隊列中的任務(wù)都在主線程中執(zhí)行炫刷。
  • 非主隊列:非主隊列中的任務(wù)可以在其他線程中執(zhí)行擎宝。

添加NSOperationNSOperationQueue的方法主要有兩種:

-(void)addOperation:(NSOperation *)op;
-(void)addOperationWithBlock:(void (^)(void))block;

下面我們嘗試一下不同的組合:

主隊列+NSBlockOperation

//1.創(chuàng)建主隊列
NSOperationQueue *q1 = [NSOperationQueue mainQueue];
//2.創(chuàng)建任務(wù)
NSBlockOperation *p1 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"任務(wù)一,當(dāng)前線程:%@", [NSThread currentThread]);
    [NSThread sleepForTimeInterval:2.0];
    NSLog(@"任務(wù)一結(jié)束");
}];
NSBlockOperation *p2 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"任務(wù)二浑玛,當(dāng)前線程:%@", [NSThread currentThread]);
    [NSThread sleepForTimeInterval:2.0];
    NSLog(@"任務(wù)二結(jié)束");
}];

NSBlockOperation *p3 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"任務(wù)三认臊,當(dāng)前線程:%@", [NSThread currentThread]);
    [NSThread sleepForTimeInterval:2.0];
    NSLog(@"任務(wù)三結(jié)束");
}];

//3.把任務(wù)添加到隊列
[q1 addOperation:p1];
[q1 addOperation:p2];
[q1 addOperation:p3];

// 任務(wù)一,當(dāng)前線程:<NSThread: 0x60000118c000>{number = 1, name = main}
// 任務(wù)一結(jié)束
// 任務(wù)二锄奢,當(dāng)前線程:<NSThread: 0x60000118c000>{number = 1, name = main}
// 任務(wù)二結(jié)束
// 任務(wù)三失晴,當(dāng)前線程:<NSThread: 0x60000118c000>{number = 1, name = main}
// 任務(wù)三結(jié)束

可以看出,任務(wù)全都在主線程中串行執(zhí)行的拘央。

非主隊列+NSBlockOperation

//1.創(chuàng)建非主隊列
NSOperationQueue *q1 = [[NSOperationQueue alloc] init];
//2.創(chuàng)建任務(wù)
NSBlockOperation *p1 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"任務(wù)一涂屁,當(dāng)前線程:%@", [NSThread currentThread]);
    [NSThread sleepForTimeInterval:2.0];
    NSLog(@"任務(wù)一結(jié)束");
}];
NSBlockOperation *p2 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"任務(wù)二,當(dāng)前線程:%@", [NSThread currentThread]);
    [NSThread sleepForTimeInterval:2.0];
    NSLog(@"任務(wù)二結(jié)束");
}];

NSBlockOperation *p3 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"任務(wù)三灰伟,當(dāng)前線程:%@", [NSThread currentThread]);
    [NSThread sleepForTimeInterval:2.0];
    NSLog(@"任務(wù)三結(jié)束");
}];

//3.把任務(wù)添加到隊列
[q1 addOperation:p1];
[q1 addOperation:p2];
[q1 addOperation:p3];

// 任務(wù)三拆又,當(dāng)前線程:<NSThread: 0x600001a66d80>{number = 6, name = (null)}
// 任務(wù)二,當(dāng)前線程:<NSThread: 0x600001a55800>{number = 4, name = (null)}
// 任務(wù)一栏账,當(dāng)前線程:<NSThread: 0x600001a5e000>{number = 3, name = (null)}
// 任務(wù)二結(jié)束
// 任務(wù)一結(jié)束
// 任務(wù)三結(jié)束

可以看到帖族,任務(wù)是在不同線程中,并發(fā)完成的挡爵。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末竖般,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子茶鹃,更是在濱河造成了極大的恐慌涣雕,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件闭翩,死亡現(xiàn)場離奇詭異挣郭,居然都是意外死亡,警方通過查閱死者的電腦和手機疗韵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門兑障,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蕉汪,你說我怎么就攤上這事流译。” “怎么了肤无?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵先蒋,是天一觀的道長。 經(jīng)常有香客問我宛渐,道長竞漾,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任窥翩,我火速辦了婚禮业岁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘寇蚊。我一直安慰自己笔时,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布仗岸。 她就那樣靜靜地躺著允耿,像睡著了一般借笙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上较锡,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天业稼,我揣著相機與錄音,去河邊找鬼蚂蕴。 笑死低散,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的骡楼。 我是一名探鬼主播熔号,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼鸟整!你這毒婦竟也來了引镊?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤吃嘿,失蹤者是張志新(化名)和其女友劉穎祠乃,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體兑燥,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡亮瓷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了降瞳。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嘱支。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖挣饥,靈堂內(nèi)的尸體忽然破棺而出除师,到底是詐尸還是另有隱情,我是刑警寧澤扔枫,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布汛聚,位于F島的核電站,受9級特大地震影響短荐,放射性物質(zhì)發(fā)生泄漏倚舀。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一忍宋、第九天 我趴在偏房一處隱蔽的房頂上張望痕貌。 院中可真熱鬧,春花似錦糠排、人聲如沸舵稠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽哺徊。三九已至室琢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間唉工,已是汗流浹背预皇。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工痊土, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人父能。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓宽菜,卻偏偏與公主長得像谣膳,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子铅乡,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,435評論 2 359

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