線程等待申钩、喚醒次绘、休眠和中斷(5)

前言

本章內(nèi)容涉及wait()、notify()撒遣、notifyAll()邮偎、sleep()、join()义黎、interrupt()和對應(yīng)的超時方法禾进。

Object中的相關(guān)方法介紹

package java.lang;

public class Object {
    //喚醒此對象監(jiān)視器等待的單個線程,被喚醒線程進(jìn)入就緒狀態(tài)
    public final native void notify();
    //喚醒此對象監(jiān)視器等待的所有線程轩缤,被喚醒線程進(jìn)入就緒狀態(tài)
    public final native void notifyAll();
    //讓當(dāng)前線程進(jìn)入等待(阻塞)狀態(tài)命迈,超時會被喚醒
    public final native void wait(long timeout) throws InterruptedException;
    //納秒大于零,毫秒數(shù)加1火的。如果有需求壶愤,直接把毫秒數(shù)加1調(diào)用上一個方法即可
    public final void wait(long timeout, int nanos) throws InterruptedException {
        if (timeout < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException(
                                "nanosecond timeout value out of range");
        }

        if (nanos > 0) {
            timeout++;
        }

        wait(timeout);
    }
    //讓當(dāng)前線程進(jìn)入無限期等待(阻塞)狀態(tài)
    public final void wait() throws InterruptedException {
        wait(0);
    }
    ...
}

注釋中已經(jīng)大致說明了方法用途。

wait()馏鹤、notify()

線程的等待與喚醒為什么在Object中而不在線程Thread中征椒,需要強(qiáng)調(diào)的是,這里說的線程等待是指讓線程等待在某一個對象的監(jiān)視器上(用Object.wait()表示)湃累,等待時會釋放持有該對象的同步鎖勃救,依賴于synchronized關(guān)鍵字使用(否則報(bào)監(jiān)視器狀態(tài)異常IllegalMonitorStateException)。同樣治力,線程喚醒也是指喚醒等待在某一個對象監(jiān)視器上的線程(用Object.notify()表示)蒙秒,也依賴于synchronized關(guān)鍵字。說到這里宵统,前面提出的問題已經(jīng)基本回答完了晕讲,說白了,線程的等待與喚醒都是基于某一對象的監(jiān)視器马澈,而線程本身只是其中的一種而已瓢省。代碼示例:

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author HXJ
 * @date 2018/7/20
 */
public class WaitNotify {
    public static void main(String[] args) {
        final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //用于等待喚醒的對象
        final Object waitAndNotify = new Object();
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(format.format(new Date()) + " " + Thread.currentThread().getName() + " notify線程開始運(yùn)行!...");
                //thread-notify線程在main線程等待釋放同步鎖之前阻塞在waitAndNotify對象的監(jiān)視器上
                synchronized (waitAndNotify) {
                    System.out.println(format.format(new Date()) + " " + Thread.currentThread().getName() + " 喚醒主線程痊班!");
                    //喚醒在waitAndNotify對象監(jiān)視器上等待的main線程
                    waitAndNotify.notify();
                    System.out.println(format.format(new Date()) + " " + Thread.currentThread().getName() + " 已喚醒主線程勤婚!");
                }
            }
        }, "thread-notify");

        synchronized (waitAndNotify) {
            System.out.println(format.format(new Date()) + " " + Thread.currentThread().getName() + " start notify線程");
            thread.start();
            try {
                //主線程休眠兩秒是為了表現(xiàn)thread-notify線程的阻塞等待
                Thread.sleep(2 * 1000);
                System.out.println(format.format(new Date()) + " " + Thread.currentThread().getName() + " 主線程!wait()");
                //讓線程等待在waitAndNotify對象的監(jiān)視器上,并釋放同步鎖
                waitAndNotify.wait();
            } catch (InterruptedException e) {
            }
            System.out.println(format.format(new Date()) + " " + Thread.currentThread().getName() + " 主線程涤伐!繼續(xù)運(yùn)行...");
        }

    }
}

運(yùn)行結(jié)果:

2018-07-20 17:53:06 main start notify線程
2018-07-20 17:53:06 thread-notify notify線程開始運(yùn)行雾鬼!...
2018-07-20 17:53:08 main 主線程!wait()
2018-07-20 17:53:08 thread-notify 喚醒主線程载弄!
2018-07-20 17:53:08 thread-notify 已喚醒主線程懒豹!
2018-07-20 17:53:08 main 主線程!繼續(xù)運(yùn)行...

運(yùn)行結(jié)果說明:
從代碼中可以看出豆村,主線程main先創(chuàng)建了一個用于等待液兽、喚醒的對象waitAndNotify,然后再創(chuàng)建線程thread-notify掌动,線程thread-notify的運(yùn)行邏輯用于喚醒等待線程四啰。接著主線程main獲取waitAndNotify對象同步鎖,啟動線程thread-notify粗恢;由于waitAndNotify同步鎖已經(jīng)被main線程持有柑晒,且休眠兩秒,所以線程thread-notify阻塞等待waitAndNotify對象同步鎖眷射,直到main線程休眠結(jié)束后調(diào)用wait()等待在waitAndNotify對象監(jiān)視器上并釋放同步鎖匙赞;接著線程thread-notify取得同步鎖佛掖,喚醒等待在waitAndNotify監(jiān)視器上的main線程,main線程繼續(xù)運(yùn)行至結(jié)束涌庭。

wait(long timeout)芥被、notifyAll()

前邊介紹完wait()和notify()后,這兩個函數(shù)已經(jīng)很簡單了坐榆,通過Object源碼發(fā)現(xiàn)wait()也是通過調(diào)用wait(long timeout)實(shí)現(xiàn)的拴魄,參數(shù)為0意思是無限期等待,直到被喚醒席镀。如果參數(shù)大于0匹中,假如參數(shù)是500,意思是等待500毫秒豪诲,等待期間如果線程未被喚醒顶捷,則500毫秒后自動喚醒。notify()是喚醒一個等待線程屎篱,而notifyAll()是喚醒所以等待的線程焊切。用法與notify()一致。

Thread中的sleep(long millis)芳室、join()专肪、interrupt()

sleep(long millis)

java.lang.Thread

    /**
     * 線程休眠,定義拋出中斷異常
     */
    public static native void sleep(long millis) throws InterruptedException;

線程休眠堪侯,Thread中的靜態(tài)方法嚎尤,用法比較簡單,上文代碼示例中已經(jīng)出現(xiàn)過伍宦,Thread.sleep(毫秒數(shù))即讓當(dāng)前運(yùn)行的線程進(jìn)入TIMED_WAITING (sleeping)阻塞狀態(tài)芽死,調(diào)用完成,當(dāng)前線程進(jìn)入休眠狀態(tài)次洼,直到休眠設(shè)置的毫秒數(shù)后由系統(tǒng)喚醒关贵。需要注意的是線程與同步鎖沒有關(guān)系,所以不會存在等待釋放同步鎖一說卖毁,它可以隨意的嵌入方法代碼的任何地方進(jìn)行調(diào)用揖曾。上文代碼片段:

try {
    //主線程休眠兩秒是為了表現(xiàn)thread-notify線程的阻塞等待
    Thread.sleep(2 * 1000);
    System.out.println(format.format(new Date()) + " " + Thread.currentThread().getName() + " 主線程!wait()");
    //讓線程等待在waitAndNotify對象的監(jiān)視器上,并釋放同步鎖
    waitAndNotify.wait();
} catch (InterruptedException e) {
}
jion()

jion()線程間等待亥啦,實(shí)際上是通過Object.wait()實(shí)現(xiàn)的炭剪。
java.lang.Thread

    /**
     * 等待這個線程運(yùn)行結(jié)束
     */
    public final void join() throws InterruptedException {
        join(0);
    }

    /**
     * 大于等于500000納秒或納秒大于0且毫秒等于零時,毫秒加一
     */
    public final synchronized void join(long millis, int nanos)
    throws InterruptedException {

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException(
                                "nanosecond timeout value out of range");
        }

        if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
            millis++;
        }

        join(millis);
    }

    /**
     * 等待指定的毫秒數(shù)后翔脱,如果被等待的線程還沒結(jié)束會超時自動喚醒奴拦,放棄等待
     * 注意synchronized關(guān)鍵字,說明獲取的是這個線程實(shí)例對象的同步鎖届吁,等待在這個線程實(shí)例的監(jiān)視器上
     */
    public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            //參數(shù)為0错妖,如果this線程實(shí)例(非當(dāng)前執(zhí)行調(diào)用線程)還活著绿鸣,則等待無限期等待,直到被等待線程運(yùn)行結(jié)束
            while (isAlive()) {
                wait(0);
            }
        } else {
            //超時等待暂氯,等待當(dāng)前線程實(shí)例運(yùn)行結(jié)束或超時后系統(tǒng)喚醒
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

從代碼中可以看出來潮模,join()方法是讓調(diào)用它的線程進(jìn)行等待,等待在某一個線程實(shí)例的監(jiān)視器上株旷,說白了就是調(diào)用哪個線程實(shí)例的join()方法再登,就是等待該線程運(yùn)行結(jié)束尔邓,或是等待超時后等待的線程繼續(xù)運(yùn)行晾剖。不知道大家有沒有發(fā)現(xiàn),Thread中的join()方法中的wait()并沒有對應(yīng)的notify()梯嗽,被等待的線程運(yùn)行結(jié)束后是怎么喚醒等待它的線程呢齿尽?其實(shí)線程運(yùn)行結(jié)束退出時,jvm會執(zhí)行退出線程的本地退出exit方法灯节,執(zhí)行退出邏輯循头。Thread.cpp中相應(yīng)代碼:

static void ensure_join(JavaThread* thread) {
  // We do not need to grap the Threads_lock, since we are operating on ourself.
  Handle threadObj(thread, thread->threadObj());
  assert(threadObj.not_null(), "java thread object must exist");
  ObjectLocker lock(threadObj, thread);
  // Ignore pending exception (ThreadDeath), since we are exiting anyway
  thread->clear_pending_exception();
  // Thread is exiting. So set thread_status field in  java.lang.Thread class to TERMINATED.
  java_lang_Thread::set_thread_status(threadObj(), java_lang_Thread::TERMINATED);
  // Clear the native thread instance - this makes isAlive return false and allows the join()
  // to complete once we've done the notify_all below
  java_lang_Thread::set_thread(threadObj(), NULL);

  //此處為喚醒等待在此線程監(jiān)視器上的所有線程
  lock.notify_all(thread);

  // Ignore pending exception (ThreadDeath), since we are exiting anyway
  thread->clear_pending_exception();
}


// 線程退出函數(shù)
void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
  ...

  // Notify waiters on thread object. This has to be done after exit() is called
  // on the thread (if the thread is the last thread in a daemon ThreadGroup the
  // group should have the destroyed bit set before waiters are notified).
  //這里從命名可以看出,線程退出確保處理join相關(guān)邏輯
  ensure_join(this);
  
  ...
    
  // Remove from list of active threads list, 
  //and notify VM thread if we are the last non-daemon thread
  Threads::remove(this);
}

代碼中可以看出炎疆,線程退出邏輯中有喚醒所有等待線程的相關(guān)邏輯卡骂。
主線程等待子線程 代碼示例:

public class ThreadJoin {
    public static void main(String[] args) throws InterruptedException {
        final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 2; i++) {
                    try {
                        System.out.println(format.format(new Date()) + " " + Thread.currentThread().getName() + " 運(yùn)行中...");
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                    }
                }
                System.out.println(format.format(new Date()) + " " + Thread.currentThread().getName() + " 運(yùn)行結(jié)束");
            }
        }, "thread-sub");
        //啟動子線程
        thread.start();
        System.out.println(format.format(new Date()) + " " + Thread.currentThread().getName() + " 等待子線程運(yùn)行結(jié)束...");
        //等待子線程運(yùn)行結(jié)束,即主線程等待在子線程實(shí)例的監(jiān)視器上
        thread.join();
        System.out.println(format.format(new Date()) + " " + Thread.currentThread().getName() + " 繼續(xù)運(yùn)行...");
    }
}

運(yùn)行結(jié)果:

2018-07-24 16:38:56 main 等待子線程運(yùn)行結(jié)束...
2018-07-24 16:38:56 thread-sub 運(yùn)行中...
2018-07-24 16:38:57 thread-sub 運(yùn)行中...
2018-07-24 16:38:58 thread-sub 運(yùn)行結(jié)束
2018-07-24 16:38:58 main 繼續(xù)運(yùn)行...

從結(jié)果可以看出形入,主線程會等待子線程運(yùn)行結(jié)束后才會繼續(xù)運(yùn)行全跨。從實(shí)例代碼中看,可能你會疑問亿遂,main執(zhí)行子線程thread.join()調(diào)用浓若,為什么進(jìn)行等待的是main而不是thread-sub子線程呢?我們再回頭看join(long millis)源碼蛇数,源碼中isAlive()方法在本示例代碼中是判斷thread-sub子線程如果還沒有運(yùn)行結(jié)束挪钓,在正在運(yùn)行的main主線程調(diào)用wait(0)或wait(delay)進(jìn)行等待。再次強(qiáng)調(diào)耳舅,wait()作用是讓當(dāng)前線程等待碌上,也就是讓main主線程等待在thread-sub子線程對象的監(jiān)視器上,thread-sub子線程運(yùn)行結(jié)束后再喚醒等待在自己監(jiān)視器上的所有線程浦徊。
最后提個問題绍赛,如果是讓主線程等待多個子線程呢?有怎么實(shí)現(xiàn)...

interrupt()

在《Core Java》中有這樣一句話:“沒有任何語言方面的需求要求一個被中斷的程序應(yīng)該終止辑畦。中斷一個線程只是為了引起該線程的注意吗蚌,被中斷線程可以決定如何應(yīng)對中斷 ”
一個現(xiàn)在未正常結(jié)束之前纯出,被強(qiáng)制終止是很危險(xiǎn)的事情蚯妇,比如終止了一個持有鎖的線程敷燎,那么有可能所有等待鎖的線程都將永久阻塞。Thread中的Thread.suspend線程掛起, Thread.stop線程止等方法都被標(biāo)記Deprecated棄用了箩言。
但有時候我們確實(shí)有必要終止某一個線程硬贯,該怎么做呢,優(yōu)雅的方式便是線程中斷陨收,這里要強(qiáng)調(diào)的是饭豹,線程中斷并非線程終止,而是要給該線程發(fā)一個中斷信號讓它自己決定如何處理务漩,調(diào)用某個線程interrupt()方法拄衰,會設(shè)置該線程的中斷狀態(tài)標(biāo)識來通知它被中斷了。運(yùn)行中的線程只是設(shè)置了中斷狀態(tài)饵骨,isInterrupted()返回true;對于阻塞中的線程翘悉,收到中斷信號后會產(chǎn)生一個中斷異常InterruptedException,同時清除中斷狀態(tài)重新復(fù)位為false居触,打破阻塞狀態(tài)妖混,相當(dāng)于喚醒阻塞(通過wait()、sleep()轮洋、InterruptibleChannel I/O操作制市、Selector阻塞)線程。并非所有阻塞狀態(tài)的線程都能對中斷有響應(yīng)弊予,如中斷信號并不能使BLOCKED (on object monitor)狀態(tài)的死鎖線程恢復(fù)運(yùn)行祥楣。且看源碼:
java源碼比較簡單:

    /**
     * Interrupts this thread.
     */
    public void interrupt() {
        if (this != Thread.currentThread())
            checkAccess();

        synchronized (blockerLock) {
            Interruptible b = blocker;
            if (b != null) {
                interrupt0();           // Just to set the interrupt flag
                b.interrupt(this);
                return;
            }
        }
        interrupt0();
    }

本地方法c++源碼:

thread.cpp
void Thread::interrupt(Thread* thread) {
  trace("interrupt", thread);
  debug_only(check_for_dangling_thread_pointer(thread);)
  os::interrupt(thread);
}
//windows實(shí)現(xiàn),其他系統(tǒng)應(yīng)該是一樣的邏輯
os_windows.cpp
void os::interrupt(Thread* thread) {
  assert(!thread->is_Java_thread() || Thread::current() == thread || Threads_lock->owned_by_self(),
         "possibility of dangling Thread pointer");

  OSThread* osthread = thread->osthread();
   //設(shè)置中斷標(biāo)識
  osthread->set_interrupted(true);
  // More than one thread can get here with the same value of osthread,
  // resulting in multiple notifications.  We do, however, want the store
  // to interrupted() to be visible to other threads before we post
  // the interrupt event.
  OrderAccess::release();
  SetEvent(osthread->interrupt_event());
  // For JSR166:  unpark after setting status
  //設(shè)置中斷標(biāo)識后unpark()喚醒線程
  if (thread->is_Java_thread())
    ((JavaThread*)thread)->parker()->unpark();

  ParkEvent * ev = thread->_ParkEvent ;
  if (ev != NULL) ev->unpark() ;

}

源碼中有兩行關(guān)鍵的代碼
osthread->set_interrupted(true); 設(shè)置中斷標(biāo)識
if (thread->is_Java_thread()) ((JavaThread*)thread)->parker()->unpark(); //喚醒阻塞線程
java中調(diào)用interrupt()方法后块促,并不能中斷一個正在運(yùn)行的線程荣堰。實(shí)際上是設(shè)置了線程的中斷標(biāo)志位,在線程阻塞的地方(如調(diào)用sleep竭翠、wait振坚、join等地方)拋出一個異常InterruptedException,并且中斷狀態(tài)也將被清除斋扰,重新復(fù)位為false渡八,這樣線程就得以退出阻塞的狀態(tài)。
經(jīng)典代碼示例:

  public void run() {
      try {
          ....
          while (!Thread.currentThread().isInterrupted() && more work to do){
              // do more work;
          }
      } catch (InterruptedException e) {
          // thread was interrupted during sleep or wait
      } finally {
          // cleanup, if required
      }
  }

代碼中传货,線程不停的檢查自身的中斷狀態(tài)作為while循環(huán)的條件屎鳍,當(dāng)線程的Thread.interrupt方法被其他線程調(diào)用,中斷狀態(tài)被設(shè)置為true時问裕,退出循環(huán)正常結(jié)束運(yùn)行逮壁。這說明,interrupt中斷只是線程退出邏輯的一部分粮宛,前提是線程需要通過isInterrupted()檢查自己的中斷狀態(tài)窥淆。

中斷阻塞狀態(tài)

對于阻塞狀態(tài)(常見的通過wiat卖宠、sleep等方法進(jìn)行阻塞,這些能拋出InterruptedException異常)的線程忧饭,中斷信號會產(chǎn)生一個中斷異常扛伍,使線程從阻塞狀態(tài)中恢復(fù)運(yùn)行,換句話說就是阻塞被中斷了词裤,線程被喚醒了刺洒。拋出InterruptedException中斷異常后,線程中斷狀態(tài)復(fù)位false吼砂。中斷異常也是線程退出邏輯的一部分逆航。

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author HXJ
 * @date 2018/7/26
 */
public class ThreadInterrupt {
    public static void main(String[] args) {
        final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                //檢查自身中斷狀態(tài)
                while (!Thread.currentThread().isInterrupted()) {
                    try {
                        System.out.println(format.format(new Date()) + " " + Thread.currentThread().getName() + " sleep ...");
                        Thread.sleep(10 * 1000);
                        System.out.println(format.format(new Date()) + " " + Thread.currentThread().getName() + " sleep 結(jié)束");
                    } catch (InterruptedException e) {
                        //InterruptedException中斷異常會復(fù)位中斷狀態(tài)為false
                        System.out.println(format.format(new Date()) + " " + Thread.currentThread().getName() + " 產(chǎn)生中斷異常!");
                    }
                }
            }
        });
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                //檢查自身中斷狀態(tài)
                while (!Thread.currentThread().isInterrupted()) {
                    try {
                        System.out.println(format.format(new Date()) + " " + Thread.currentThread().getName() + " sleep ...");
                        Thread.sleep(10 * 1000);
                        System.out.println(format.format(new Date()) + " " + Thread.currentThread().getName() + " sleep 結(jié)束");
                    } catch (InterruptedException e) {
                        System.out.println(format.format(new Date()) + " " + Thread.currentThread().getName() + " 產(chǎn)生中斷異常帅刊!");
                        //InterruptedException中斷異常會復(fù)位中斷狀態(tài)為false纸泡,所以需要重新設(shè)置中斷狀態(tài)
                        Thread.currentThread().interrupt();
                    }
                }
                System.out.println(format.format(new Date()) + " " + Thread.currentThread().getName() + " 正常退出漂问!");
            }
        });
        System.out.println(format.format(new Date()) + " " + Thread.currentThread().getName() + " 啟動子線程赖瞒!");
        thread.start();
        thread1.start();
        try {
            Thread.sleep(2000);
            System.out.println(format.format(new Date()) + " " + Thread.currentThread().getName() + " sleep 2s 結(jié)束,中斷阻塞子線程蚤假!");
            thread.interrupt();
            thread1.interrupt();
            thread.join();
            thread1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

運(yùn)行結(jié)果:

2018-07-26 14:59:44 main 啟動子線程栏饮!
2018-07-26 14:59:44 Thread-0 sleep ...
2018-07-26 14:59:44 Thread-1 sleep ...
2018-07-26 14:59:46 main sleep 2s 結(jié)束,中斷阻塞子線程磷仰!
2018-07-26 14:59:46 Thread-1 產(chǎn)生中斷異常袍嬉!
2018-07-26 14:59:46 Thread-0 產(chǎn)生中斷異常!
2018-07-26 14:59:46 Thread-1 正常退出灶平!
2018-07-26 14:59:46 Thread-0 sleep ...
2018-07-26 14:59:56 Thread-0 sleep 結(jié)束
2018-07-26 14:59:56 Thread-0 sleep ...

結(jié)果說明伺通,主線程啟動thread、thread1兩個子線程后逢享,開始休眠罐监;兩個子線程啟動后也進(jìn)入長達(dá)10s的休眠狀態(tài);主線程2s后休眠結(jié)束瞒爬,分別中斷了休眠阻塞狀態(tài)的兩個子線程弓柱,兩個子線程產(chǎn)生中斷異常恢復(fù)運(yùn)行侧但,提前結(jié)束休眠狀態(tài)矢空。由于產(chǎn)生中斷異常后中斷狀態(tài)復(fù)位,所以Thread-0子線程的while條件isInterrupted()仍滿足條件繼續(xù)執(zhí)行禀横;而Thread-1在中斷狀態(tài)復(fù)位后interrupt()重新設(shè)置中斷狀態(tài)屁药,while條件不滿足,線程正常退出柏锄。產(chǎn)生中斷異常后酿箭,也可以通過break直接退出循環(huán)體立莉。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市七问,隨后出現(xiàn)的幾起案子蜓耻,更是在濱河造成了極大的恐慌,老刑警劉巖械巡,帶你破解...
    沈念sama閱讀 216,997評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件刹淌,死亡現(xiàn)場離奇詭異,居然都是意外死亡讥耗,警方通過查閱死者的電腦和手機(jī)有勾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來古程,“玉大人蔼卡,你說我怎么就攤上這事≌跄ィ” “怎么了雇逞?”我有些...
    開封第一講書人閱讀 163,359評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長茁裙。 經(jīng)常有香客問我塘砸,道長,這世上最難降的妖魔是什么晤锥? 我笑而不...
    開封第一講書人閱讀 58,309評論 1 292
  • 正文 為了忘掉前任掉蔬,我火速辦了婚禮,結(jié)果婚禮上矾瘾,老公的妹妹穿的比我還像新娘女轿。我一直安慰自己,他們只是感情好壕翩,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評論 6 390
  • 文/花漫 我一把揭開白布蛉迹。 她就那樣靜靜地躺著,像睡著了一般戈泼。 火紅的嫁衣襯著肌膚如雪婿禽。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,258評論 1 300
  • 那天大猛,我揣著相機(jī)與錄音扭倾,去河邊找鬼。 笑死挽绩,一個胖子當(dāng)著我的面吹牛膛壹,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,122評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼模聋,長吁一口氣:“原來是場噩夢啊……” “哼肩民!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起链方,我...
    開封第一講書人閱讀 38,970評論 0 275
  • 序言:老撾萬榮一對情侶失蹤持痰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后祟蚀,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體工窍,經(jīng)...
    沈念sama閱讀 45,403評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評論 3 334
  • 正文 我和宋清朗相戀三年前酿,在試婚紗的時候發(fā)現(xiàn)自己被綠了患雏。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,769評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡罢维,死狀恐怖淹仑,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情肺孵,我是刑警寧澤匀借,帶...
    沈念sama閱讀 35,464評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站悬槽,受9級特大地震影響怀吻,放射性物質(zhì)發(fā)生泄漏瞬浓。R本人自食惡果不足惜初婆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望猿棉。 院中可真熱鬧磅叛,春花似錦、人聲如沸萨赁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽杖爽。三九已至敲董,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間慰安,已是汗流浹背腋寨。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留化焕,地道東北人萄窜。 一個月前我還...
    沈念sama閱讀 47,831評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親查刻。 傳聞我的和親對象是個殘疾皇子键兜,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評論 2 354

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

  • 本文主要講了java中多線程的使用方法、線程同步穗泵、線程數(shù)據(jù)傳遞普气、線程狀態(tài)及相應(yīng)的一些線程函數(shù)用法、概述等佃延。 首先講...
    李欣陽閱讀 2,454評論 1 15
  • Java多線程學(xué)習(xí) [-] 一擴(kuò)展javalangThread類 二實(shí)現(xiàn)javalangRunnable接口 三T...
    影馳閱讀 2,957評論 1 18
  • 寫在前面的話: 這篇博客是我從這里“轉(zhuǎn)載”的棋电,為什么轉(zhuǎn)載兩個字加“”呢?因?yàn)檫@絕不是簡單的復(fù)制粘貼苇侵,我花了五六個小...
    SmartSean閱讀 4,730評論 12 45
  • 當(dāng)夏日的風(fēng)拂過我的臉龐赶盔,當(dāng)我看見耀眼的陽光,當(dāng)我懷著浮萍一般的心榆浓,當(dāng)我還在等你于未。 等你,成為了我每日期待的事情...
    喬百合閱讀 246評論 0 0
  • 在前面的回憶中,更多的談的都是父母的影響萍鲸,其實(shí)闷叉,家里還有一個重要成員,那就是我的弟弟脊阴。 弟弟比我小兩歲握侧。聽爸爸媽媽...
    macaho閱讀 200評論 0 0