JDK成長(zhǎng)記15:從0分析你不知道的synchronized底層原理(上)

file

前幾節(jié)你應(yīng)該已經(jīng)了解和掌握了Thread社牲、ThreadLocal粪薛、Volatile這幾個(gè)并發(fā)基礎(chǔ)知識(shí)的底層原理。這一節(jié)搏恤,你可以跟我一起深入了解下synchronized關(guān)鍵字的底層原理和其涉及的基礎(chǔ)知識(shí)违寿。看完這篇成長(zhǎng)記熟空,你可以獲取到如下幾點(diǎn):

synchronized預(yù)備知識(shí):

  • 理解什么是CAS藤巢?
  • synchronized會(huì)形成幾種鎖的類(lèi)型
  • HotspotJVM虛擬機(jī)Java對(duì)象內(nèi)存中的布局結(jié)構(gòu)是什么,markword是鎖的關(guān)鍵字段息罗?
  • 操作系統(tǒng)中用戶(hù)態(tài)和內(nèi)核態(tài)的資源操作和進(jìn)程是什么意思掂咒?

synchronized核心流程及原理:

  • 從3個(gè)層面初步分析sychronized的核心流程和原理

好了,讓我們一起開(kāi)始吧迈喉!

HelloSychronized

<div class="output_wrapper" id="output_wrapper_id" style="width:fit-content;font-size: 16px; color: rgb(62, 62, 62); line-height: 1.6; word-spacing: 0px; letter-spacing: 0px; font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;"><h3 id="hdddd" style="width:fit-content;line-height: inherit; margin: 1.5em 0px; font-weight: bold; font-size: 1.3em; margin-bottom: 2em; margin-right: 5px; padding: 8px 15px; letter-spacing: 2px; background-image: linear-gradient(to right bottom, rgb(43,48,70), rgb(43,48,70)); background-color: rgb(63, 81, 181); color: rgb(255, 255, 255); border-left: 10px solid rgb(255,204,0); border-radius: 5px; text-shadow: rgb(102, 102, 102) 1px 1px 1px; box-shadow: rgb(102, 102, 102) 1px 1px 2px;"><span style="font-size: inherit; color: inherit; line-height: inherit; margin: 0px; padding: 0px;">HelloSychronized</span></h3></div>

我們來(lái)寫(xiě)一個(gè)多線程i++的程序绍刮,體驗(yàn)一下,多線程如果是并發(fā)的修改一個(gè)數(shù)據(jù)挨摸,會(huì)有什么樣的線程并發(fā)安全問(wèn)題孩革。

剛才說(shuō)過(guò)了,volatile得运,解決的對(duì)一個(gè)共享數(shù)據(jù)膝蜈,有人寫(xiě),有人讀澈圈,多個(gè)線程并發(fā)讀和寫(xiě)的可見(jiàn)性的問(wèn)題,而多個(gè)線程對(duì)一個(gè)共享數(shù)據(jù)并發(fā)的寫(xiě)帆啃,可能會(huì)導(dǎo)致數(shù)據(jù)出錯(cuò)瞬女,產(chǎn)生原子性的問(wèn)題。

volatile為什么不能保證原子性努潘? 從JMM內(nèi)存模型就可以看出來(lái)诽偷,多個(gè)線程同時(shí)修改一個(gè)變量,都是在自己本地內(nèi)存中修改疯坤,volatile只是保證一個(gè)線程修改报慕,另一個(gè)線程讀的時(shí)候,發(fā)起修改的線程是強(qiáng)制刷新數(shù)據(jù)主存压怠,過(guò)期其他線程的工作內(nèi)存的緩存眠冈,沒(méi)法做到多個(gè)線程在本地內(nèi)存同時(shí)寫(xiě)的時(shí)候,限制只能有一個(gè)線程修改,因?yàn)榫€程自己修改自己內(nèi)存的數(shù)據(jù)沒(méi)有發(fā)生競(jìng)爭(zhēng)關(guān)系蜗顽。而且之后會(huì)給各自寫(xiě)入主內(nèi)存布卡,當(dāng)然就保證不了只能有一個(gè)線程修改主內(nèi)存的數(shù)據(jù),做不到原子性了雇盖。

為了解決這個(gè)問(wèn)題忿等,可以使用syncrhonized給修改這個(gè)操作加一把鎖,一旦說(shuō)某個(gè)線程加了一把鎖之后崔挖,就會(huì)保證贸街,其他的線程沒(méi)法去讀取和修改這個(gè)變量的值了,同一時(shí)間狸相,只有一個(gè)線程可以讀這個(gè)數(shù)據(jù)以及修改這個(gè)數(shù)據(jù)薛匪,別的線程都會(huì)卡在嘗試獲取鎖那兒。這樣也就不會(huì)出現(xiàn)并發(fā)同時(shí)修改卷哩,數(shù)據(jù)出錯(cuò)蛋辈,原子性問(wèn)題了。

synchronized鎖一般有兩類(lèi)将谊,一種是對(duì)某個(gè)實(shí)例對(duì)象來(lái)加鎖冷溶,另外一種是對(duì)這個(gè)類(lèi)進(jìn)行加鎖。相信大家很熟悉了尊浓,這里用一個(gè)Hello synchronized的小例子逞频,舉一個(gè)簡(jiǎn)單對(duì)象加鎖的例子。

代碼如下:

  public class HelloSynchronized {
    public static void main(String[] args) {
      Object o = new Object();
      synchronized (o){
      }
    }
  }

對(duì)類(lèi)加鎖和對(duì)實(shí)例對(duì)象的更多例子這里就不舉例了栋齿,我們更多的是研究synchronized它的底層原理苗胀。基本的使用相信你一定可以自己學(xué)習(xí)到瓦堵。

在分析sychronized原理期間基协,需要不斷的補(bǔ)充一些基礎(chǔ)知識(shí)。

學(xué)習(xí)sychronized先決條件(Prerequisites)

<div class="output_wrapper" id="output_wrapper_id" style="width:fit-content;font-size: 16px; color: rgb(62, 62, 62); line-height: 1.6; word-spacing: 0px; letter-spacing: 0px; font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;"><h3 id="hdddd" style="width:fit-content;line-height: inherit; margin: 1.5em 0px; font-weight: bold; font-size: 1.3em; margin-bottom: 2em; margin-right: 5px; padding: 8px 15px; letter-spacing: 2px; background-image: linear-gradient(to right bottom, rgb(43,48,70), rgb(43,48,70)); background-color: rgb(63, 81, 181); color: rgb(255, 255, 255); border-left: 10px solid rgb(255,204,0); border-radius: 5px; text-shadow: rgb(102, 102, 102) 1px 1px 1px; box-shadow: rgb(102, 102, 102) 1px 1px 2px;"><span style="font-size: inherit; color: inherit; line-height: inherit; margin: 0px; padding: 0px;">學(xué)習(xí)sychronized先決條件(Prerequisites)</span></h3></div>

  • sychronized鎖的概念

在JDK 早期 sychronized 使用的時(shí)候菇用,直接創(chuàng)建的重量級(jí)鎖澜驮,性能很不好。

在之后JDK新的版本中惋鸥,sychronized優(yōu)化了鎖杂穷,分為了4種,無(wú)鎖態(tài)卦绣、偏向鎖耐量、自旋鎖(輕量鎖)、重量鎖滤港,會(huì)根據(jù)情況自動(dòng)升級(jí)鎖廊蜒。

這四種鎖分別表示什么意思呢?

無(wú)鎖態(tài)表示第一次對(duì)剛創(chuàng)建的對(duì)象或者類(lèi)加鎖時(shí)的狀態(tài)。我發(fā)現(xiàn)只有一個(gè)線程在操作代碼塊的資源劲藐,壓根不需要加鎖八堡。此時(shí)會(huì)處于無(wú)鎖態(tài)。

偏向鎖聘芜,類(lèi)似于貼標(biāo)簽兄渺,表示這個(gè)資源暫時(shí)屬于某個(gè)線程,偏向它所有了汰现。打個(gè)比方挂谍,就好比一個(gè)座位只能做一個(gè)人,你坐下后瞎饲,在座位上貼上了你自己的標(biāo)簽口叙。別人發(fā)現(xiàn)已經(jīng)有標(biāo)簽了,肯定就不會(huì)在坐了嗅战。

輕量鎖(自旋鎖):輕量鎖妄田,底層是CAS自旋的操作,所以也叫自旋鎖驮捍。這里簡(jiǎn)單普及下自旋CAS的操作流程疟呐,之后將Aotmic類(lèi)的時(shí)候會(huì)仔細(xì)講下。CAS自旋流程如下:

file

最后我們來(lái)聊下什么是重量級(jí)鎖东且?這又要牽扯另一個(gè)知識(shí)了启具。在Linux操作系統(tǒng)層面,由于需要限制不同的程序之間的訪問(wèn)能力, 防止他們獲取別的程序的內(nèi)存數(shù)據(jù), 或者獲取外圍設(shè)備的數(shù)據(jù), 并發(fā)送到網(wǎng)絡(luò), CPU劃分出兩個(gè)權(quán)限等級(jí)用戶(hù)態(tài)和內(nèi)核態(tài)珊泳。用于表示進(jìn)程運(yùn)行時(shí)所處狀態(tài)鲁冯。

你可以簡(jiǎn)單理解,一個(gè)程序啟動(dòng)后會(huì)有對(duì)應(yīng)的進(jìn)程色查,它們操作的資源分為兩種薯演,屬于用戶(hù)態(tài)的資源或者內(nèi)核態(tài)的資源。

用戶(hù)態(tài)是不能直接操作內(nèi)核態(tài)中資源的秧了,只能通知內(nèi)核態(tài)來(lái)操作跨扮。這個(gè)在硬件級(jí)別也有對(duì)應(yīng)的指令級(jí)別(比如Intel ring0-ring3級(jí)別的指令,ring0級(jí)別一般對(duì)應(yīng)的就是用戶(hù)態(tài)進(jìn)程可以操作的指令示惊,ring3對(duì)應(yīng)的是內(nèi)核態(tài)進(jìn)程可以發(fā)起的指令)好港。

如下圖所示:

file

這個(gè)和synchronized有什么關(guān)系呢愉镰?因?yàn)閟ynchronized加重量級(jí)鎖的操作米罚,是對(duì)硬件資源的鎖指令操作,所以肯定是需要處于內(nèi)核態(tài)的進(jìn)程才可以操作丈探,JVM的進(jìn)程只是處于用戶(hù)態(tài)的進(jìn)程录择,所以需要向操作系統(tǒng)申請(qǐng),這個(gè)過(guò)程肯定會(huì)很消耗資源的。

比如隘竭,synchronized的本質(zhì)是JVM用戶(hù)空間的一個(gè)進(jìn)程(處于用戶(hù)態(tài))向操作系統(tǒng)(內(nèi)核態(tài))發(fā)起一個(gè)lock的鎖指令操作 塘秦。

C++代碼如下:

  //Adding a lock prefix to an instruction on MP machine
  \#define LOCK_IF_MP(mp) "cmp $0, " #mp "; je 1f; local; 1 : "

如下圖右邊所示:

file
  • sychronized鎖狀態(tài)的記錄

了解了sychronized的鎖的幾種類(lèi)型后,怎么標(biāo)識(shí)是什么樣的synchronized鎖呢动看?這個(gè)就要聊到Java的對(duì)象在JVM的內(nèi)存中的結(jié)構(gòu)了尊剔。不同虛擬機(jī)結(jié)構(gòu)略有差別,這里講一下HotSpot虛擬機(jī)中的對(duì)象結(jié)構(gòu):

file

synchronized鎖狀態(tài)的信息就記錄在markword中菱皆。markword在64位的操作系統(tǒng)上须误,8字節(jié),64位大小的空間的區(qū)域仇轻。

不同的鎖的標(biāo)記在如下圖所示:

file

這個(gè)表你不用背下來(lái)京痢,你只要知道,synchronized的輕量鎖和重量鎖通過(guò)2位即可以區(qū)分出來(lái)篷店,偏向鎖和無(wú)鎖需要3位祭椰。

有了上面的基礎(chǔ)知識(shí)后,就可以開(kāi)始研究synchronized的底層原理了疲陕。

字節(jié)碼層面的synchronized

<div class="output_wrapper" id="output_wrapper_id" style="width:fit-content;font-size: 16px; color: rgb(62, 62, 62); line-height: 1.6; word-spacing: 0px; letter-spacing: 0px; font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;"><h3 id="hdddd" style="width:fit-content;line-height: inherit; margin: 1.5em 0px; font-weight: bold; font-size: 1.3em; margin-bottom: 2em; margin-right: 5px; padding: 8px 15px; letter-spacing: 2px; background-image: linear-gradient(to right bottom, rgb(43,48,70), rgb(43,48,70)); background-color: rgb(63, 81, 181); color: rgb(255, 255, 255); border-left: 10px solid rgb(255,204,0); border-radius: 5px; text-shadow: rgb(102, 102, 102) 1px 1px 1px; box-shadow: rgb(102, 102, 102) 1px 1px 2px;"><span style="font-size: inherit; color: inherit; line-height: inherit; margin: 0px; padding: 0px;">synchronized</span></h3></div>

sychronized在Java代碼層面就如上面Hello Synconized那個(gè)最簡(jiǎn)單的例子所示方淤,我們來(lái)看下它的字節(jié)碼層面是什么樣子的?

上面main方法的字節(jié)碼如下:

0 new #2 <java/lang/Object>
 3 dup
 4 invokespecial #1 <java/lang/Object.<init>>
 7 astore_1
 8 aload_1
 9 dup
 10 astore_2
 11 monitorenter
 12 aload_2
 13 monitorexit
 14 goto 22 (+8)
 17 astore_3
 18 aload_2
 19 monitorexit
 20 aload_3
 21 athrow
 22 return

new鸭轮、dup臣淤、invokespecial、 astore_1這些指令是學(xué)習(xí)volatile的時(shí)候你應(yīng)該很熟悉了窃爷。我這里需要關(guān)注的是另外 2個(gè)核心的JVM指令:monitorenter邑蒋、monitorexit

這個(gè)表示sychronized加鎖的同步代碼塊的進(jìn)入和退出按厘。為什么有兩個(gè)monitorexit呢医吊?一個(gè)是正常退出,一個(gè)拋出異常也會(huì)退出釋放鎖逮京。

JVM層面的synchronized

<div class="output_wrapper" id="output_wrapper_id" style="width:fit-content;font-size: 16px; color: rgb(62, 62, 62); line-height: 1.6; word-spacing: 0px; letter-spacing: 0px; font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;"><h3 id="hdddd" style="width:fit-content;line-height: inherit; margin: 1.5em 0px; font-weight: bold; font-size: 1.3em; margin-bottom: 2em; margin-right: 5px; padding: 8px 15px; letter-spacing: 2px; background-image: linear-gradient(to right bottom, rgb(43,48,70), rgb(43,48,70)); background-color: rgb(63, 81, 181); color: rgb(255, 255, 255); border-left: 10px solid rgb(255,204,0); border-radius: 5px; text-shadow: rgb(102, 102, 102) 1px 1px 1px; box-shadow: rgb(102, 102, 102) 1px 1px 2px;"><span style="font-size: inherit; color: inherit; line-height: inherit; margin: 0px; padding: 0px;">JVM層面的synchronized</span></h3></div>

那么卿堂,當(dāng) JVM的HotSpot實(shí)現(xiàn)中,當(dāng)遇到這兩個(gè)JVM指令懒棉,又是如何執(zhí)行的呢草描?讓我們來(lái)看一下。

在JVM HotSpot的C++代碼實(shí)際執(zhí)行過(guò)程中策严,執(zhí)行了一個(gè)InterpreterRuntime:: monitorenter方法穗慕,代碼如下:

  IRT_ENTRY_NO_ASYNC(void, InterpreterRuntime::monitorenter(JavaThread* thread, BasicObjectLock* elem))

  \#ifdef ASSERT
   thread->last_frame().interpreter_frame_verify_monitor(elem);
  \#endif

   if (PrintBiasedLockingStatistics) {
    Atomic::inc(BiasedLocking::slow_path_entry_count_addr());
   }

   Handle h_obj(thread, elem->obj());

  assert(Universe::heap()->is_in_reserved_or_null(h_obj()),
       "must be NULL or an object");
   if (UseBiasedLocking) {
    // Retry fast entry if bias is revoked to avoid unnecessary inflation
    ObjectSynchronizer::fast_enter(h_obj, elem->lock(), true, CHECK);
   } else {
    ObjectSynchronizer::slow_enter(h_obj, elem->lock(), CHECK);
   }

   assert(Universe::heap()->is_in_reserved_or_null(elem->obj()),

       "must be NULL or an object");

  \#ifdef ASSERT

   thread->last_frame().interpreter_frame_verify_monitor(elem);

  \#endif

  IRT_END

你可以看下上面的方法的脈絡(luò)(不懂C++也沒(méi)有關(guān)系,懂if-else就行)妻导。它的核心有兩個(gè)if逛绵。

第一個(gè)if根據(jù)變量名字PrintBiasedLockingStatistics可以判斷出應(yīng)該是打印偏向鎖的統(tǒng)計(jì)信息怀各,明顯不是最重要的。

第二個(gè)if同理术浪,UseBiasedLocking表示了是否使用了偏向鎖瓢对,如果是調(diào)用了ObjectSynchronizer::fast_enter否則

ObjectSynchronizer::slow_enter。

很明顯胰苏,第二個(gè)if中是synchronized加鎖的核心代碼硕蛹。我們還需要繼續(xù)看下它們的脈絡(luò)。

代碼如下:synchronizer.cpp

void ObjectSynchronizer::fast_enter(Handle obj, BasicLock* lock, bool attempt_rebias, TRAPS) {

    if (UseBiasedLocking) {
      if (!SafepointSynchronize::is_at_safepoint()) {
       BiasedLocking::Condition cond = BiasedLocking::revoke_and_rebias(obj, attempt_rebias, THREAD);

       if (cond == BiasedLocking::BIAS_REVOKED_AND_REBIASED) {
        return;
       }

      } else {
       assert(!attempt_rebias, "can not rebias toward VM thread");
       BiasedLocking::revoke_at_safepoint(obj);
      }
      assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
    }
  
    slow_enter (obj, lock, THREAD) ;

    }

可以看到fast_enter方法硕并,核心脈絡(luò)除了取消偏向和重新偏向的邏輯(從變量明和注釋可以看出來(lái)妓美,這里暫時(shí)不重要,先忽略)鲤孵,最后核心脈絡(luò)還是調(diào)用了slow_enter方法壶栋。讓我們來(lái)看下:

void ObjectSynchronizer::slow_enter(Handle obj, BasicLock* lock, TRAPS) {

   markOop mark = obj->mark();
   assert(!mark->has_bias_pattern(), "should not see bias pattern here"); 

   if (mark->is_neutral()) {
    // Anticipate successful CAS -- the ST of the displaced mark must
    // be visible <= the ST performed by the CAS.
    lock->set_displaced_header(mark);
    if (mark == (markOop) Atomic::cmpxchg_ptr(lock, obj()->mark_addr(), mark)) {
     TEVENT (slow_enter: release stacklock) ;
     return ;
    }
    // Fall through to inflate() ...
   } else

   if (mark->has_locker() && THREAD->is_lock_owned((address)mark->locker())) {
    assert(lock != mark->locker(), "must not re-lock the same lock");
    assert(lock != (BasicLock*)obj->mark(), "don't relock with same BasicLock");
    lock->set_displaced_header(NULL);
    return;
   }


  \#if 0
   // The following optimization isn't particularly useful.
  if (mark->has_monitor() && mark->monitor()->is_entered(THREAD)) {
    lock->set_displaced_header (NULL) ;
    return ;
   }
  \#endif   

   // The object header will never be displaced to this lock,
   // so it does not matter what the value is, except that it
   // must be non-zero to avoid looking like a re-entrant lock,
   // and must not look locked either.
   lock->set_displaced_header(markOopDesc::unused_mark());
   ObjectSynchronizer::inflate(THREAD, obj())->enter(THREAD);

  }

上面這一段是sychronized加鎖,核心中的核心普监,可以發(fā)現(xiàn)很多有意思的地方:

1) 從注釋可以看出贵试,鎖會(huì)有膨脹過(guò)程,對(duì)象頭會(huì)記錄鎖的相關(guān)信息凯正。

2) Atomic::cmpxchg_ptr體現(xiàn)了ompare and exchange (CAS)操作毙玻,是輕量級(jí)鎖。

3) mark->has_locker() && THREAD->is_lock_owned((address)mark->locker()體現(xiàn)了synchronized是可重入鎖

4) 最后的ObjectSynchronizer::inflate意思為膨脹為重量級(jí)鎖廊散。

C++的代碼有很多細(xì)節(jié)和知識(shí)桑滩,你開(kāi)始學(xué)習(xí)的時(shí)候不要想著全部搞清楚,一定要有之前學(xué)到的思想允睹,先脈絡(luò)后細(xì)節(jié)运准。搞清楚脈絡(luò)再說(shuō)研究細(xì)節(jié)的部分。

所以缭受,通過(guò)初步看過(guò)synchronized的HotSpot C++代碼實(shí)現(xiàn)胁澳,重點(diǎn)的脈絡(luò)就是鎖升級(jí)的過(guò)程和原理,接下來(lái)重點(diǎn)分析一下這個(gè)過(guò)程米者。

synchronized鎖升級(jí)的過(guò)程

<div class="output_wrapper" id="output_wrapper_id" style="width:fit-content;font-size: 16px; color: rgb(62, 62, 62); line-height: 1.6; word-spacing: 0px; letter-spacing: 0px; font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;"><h3 id="hdddd" style="width:fit-content;line-height: inherit; margin: 1.5em 0px; font-weight: bold; font-size: 1.3em; margin-bottom: 2em; margin-right: 5px; padding: 8px 15px; letter-spacing: 2px; background-image: linear-gradient(to right bottom, rgb(43,48,70), rgb(43,48,70)); background-color: rgb(63, 81, 181); color: rgb(255, 255, 255); border-left: 10px solid rgb(255,204,0); border-radius: 5px; text-shadow: rgb(102, 102, 102) 1px 1px 1px; box-shadow: rgb(102, 102, 102) 1px 1px 2px;"><span style="font-size: inherit; color: inherit; line-height: inherit; margin: 0px; padding: 0px;">synchronized鎖升級(jí)的過(guò)程</span></h3></div>

前面通過(guò)從字節(jié)碼層面到JVM層面初步了解了synchronized的實(shí)現(xiàn)韭畸,結(jié)合之前說(shuō)的sychronized的鎖的幾種類(lèi)型。最終可以分析出來(lái)synchronized鎖會(huì)有一個(gè)升級(jí)的過(guò)程蔓搞。過(guò)程如下圖所示:

file

這個(gè)圖非常重要胰丁,大家一定要牢記住。下一節(jié)會(huì)花費(fèi)整整一節(jié)來(lái)講在這個(gè)圖喂分。

本文由博客一文多發(fā)平臺(tái) OpenWrite 發(fā)布锦庸!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市妻顶,隨后出現(xiàn)的幾起案子酸员,更是在濱河造成了極大的恐慌,老刑警劉巖讳嘱,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件幔嗦,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡沥潭,警方通過(guò)查閱死者的電腦和手機(jī)邀泉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)钝鸽,“玉大人汇恤,你說(shuō)我怎么就攤上這事“吻。” “怎么了因谎?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)颜懊。 經(jīng)常有香客問(wèn)我财岔,道長(zhǎng),這世上最難降的妖魔是什么河爹? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任匠璧,我火速辦了婚禮,結(jié)果婚禮上咸这,老公的妹妹穿的比我還像新娘夷恍。我一直安慰自己,他們只是感情好媳维,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布酿雪。 她就那樣靜靜地躺著,像睡著了一般侄刽。 火紅的嫁衣襯著肌膚如雪执虹。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,301評(píng)論 1 301
  • 那天唠梨,我揣著相機(jī)與錄音袋励,去河邊找鬼。 笑死当叭,一個(gè)胖子當(dāng)著我的面吹牛茬故,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蚁鳖,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼磺芭,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了醉箕?” 一聲冷哼從身側(cè)響起钾腺,我...
    開(kāi)封第一講書(shū)人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤徙垫,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后放棒,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體姻报,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年间螟,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吴旋。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡厢破,死狀恐怖荣瑟,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情摩泪,我是刑警寧澤笆焰,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站见坑,受9級(jí)特大地震影響仙辟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鳄梅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一叠国、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧戴尸,春花似錦粟焊、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至挎峦,卻和暖如春香追,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背坦胶。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工透典, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人顿苇。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓峭咒,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親纪岁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子凑队,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354

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