Android進階之路——線程機制

? ? 今天leo主要總結線程方面的,分為以下幾個知識點:

? 認識線程

? 線程的基本用法

? 線程同步

? 子線程更新UI

? 線程間通信機制

? ? Android是單線程模型,我們創(chuàng)建的Service、Activity以及Broadcast均是在一個主線程處理,這里我們可以理解為UI線程。

? ? 但是在操作一些耗時操作時,比如I/O讀寫的大文件讀寫,數(shù)據(jù)庫操作以及網(wǎng)絡下載需要很長時間,為了不阻塞用戶界面,出現(xiàn)ANR的響應提示窗口,這個時候我們考慮使用Thread線程來解決。

? 進程與線程

? ? 線程是指進程內(nèi)的一個執(zhí)行單元,也是進程內(nèi)的可調(diào)度實體,與進程的區(qū)別:

(1)地址空間: 進程內(nèi)的一個執(zhí)行單元;進程至少有一個線程,它們共享進程的地址空間;而進程有自己獨立的地址空間;

(2)資源擁有: 進程是資源分配和擁有的單位,同一個進程內(nèi)的線程共享進程的資源;

(3)線程是處理器調(diào)度的基本單位,但進程不是;

(4)二者均可并發(fā)執(zhí)行。

? 實現(xiàn)?

? ? ? 繼承java.lang.Thread類

? ? ? 實現(xiàn)Runnable接口

? 啟動

? ? Thread類代表線程類,它的兩個最主要的方法是:

? ? ? run()--包含線程運行時所執(zhí)行的代碼

? ? ? Start()--用于啟動線程

? 通信

? ? Handler機制,它是Runnable和Activity交互的橋梁,在run方法中發(fā)送Message,在Handler里,通過不同的Message執(zhí)行不同的任務。

? 簡介

? ? 當使用多個線程來訪問同一個數(shù)據(jù)時,非常容易出現(xiàn)線程安全問題(比如多個線程都在操作同一數(shù)據(jù)導致數(shù)據(jù)不一致),所以我們用同步機制來解決這些問題。

? 實現(xiàn)方法

? ? ? 同步代碼塊:synchronized(同一個數(shù)據(jù)){} 同 ? ? ? 一個數(shù)據(jù):就是N條線程同時訪問一個數(shù)據(jù)。

? ? ? 同步方法:public synchronized 數(shù)據(jù)返回類 ? ? ? 型 方法名(){}

? 子線程更新UI的四種方法

? ? 1. handle.post(Runnable r)

? ? 2. handle.handleMessage(Message msg)

? ? 3. runOnUiThread(Runnable r)

? ? 4. View.post(Runnable r)

? 用于線程間通訊的類

? ? 1.?Handler :在android里負責發(fā)送和處理消息,通過它可以實現(xiàn)其他線程與Main線程之間的消息通訊。

? ? 2. Looper:負責管理線程的消息隊列和消息循環(huán)?。

? ? 3. Message??:線程間通訊的消息載體。兩個碼頭之間運輸貨物,Message充當集裝箱的功能,里面可以存放任何你想要傳遞的消息。

? ? 4. MessageQueue:消息隊列,先進先出,它的作用是保存有待線程處理的消息。

Android多線程機制

一、使用線程

? ? 1. 任何耗時的處理過程都會降低用戶界面的響應速度,甚至導致用戶界面失去響應,當用戶界面失去響應超過5秒鐘,Android系統(tǒng)會允許用戶強行關閉應用程序。

? ? 2. 較好的解決方法是將耗時的處理過程轉移到子線程上,這樣可以避免負責界面更新的主線程無法處理界面事件,從而避免用戶界面長時間失去響應。

? ? 3. 線程是獨立的程序單元,多個線程可以并行工作。

? ? 4. 在多處理器系統(tǒng)中,每個中央處理器(CPU)單獨運行一個線程,因此線程是并行工作的。

? ? 5.? 在單處理器系統(tǒng)中,處理器會給每個線程一小段時間,在這個時間內(nèi)線程是被執(zhí)行的,然后處理器執(zhí)行下一個線程,這樣就產(chǎn)生了線程并行運行的假象。

? ? 6. 無論線程是否真的并行工作,在宏觀上可以認為子線程是獨立于主線程,且能與主線程并行工作的程序單元。

? ? 7. Android中的線程是基于Java定義的線程,其內(nèi)部結構如圖所示:

? ? 8. 一個應用程序中可能會包含多個線程(Thread),每個線程中都有一個run()方法,run()方法內(nèi)部的程序執(zhí)行完畢后,所在的線程就自動結束。

? ? 9. 每個線程都有一個消息隊列,用于不同的線程之間傳遞消息。在run()方法內(nèi)部,如果不主動去讀取消息隊列中的消息,這些消息就是一些無用的消息,因為它們沒有被處理。

? ? 10. 在Android系統(tǒng)中,讀取消息和處理消息是兩個步驟,并由兩個不同的部分完成,先讀取消息,然后才能處理消息。

? ? 11. 無論是本線程的還是其它線程,都不能直接處理消息隊列中的消息,而是需要通過在線程內(nèi)部定義一個Handler類對象來處理消息隊列。一個Thread只能包含一個Handler對象。在實際應用中,讀取消息隊列一般需要循環(huán)執(zhí)行,即不斷地從消息隊列中獲取消息并進行相應處理,這就又需要一個Looper對象。

? ? 12. Looper對象用于循環(huán)讀取消息隊列的值,并回調(diào)Handler對象中定義的消息處理函數(shù),同時,Looper對象還可以將讀取的消息從隊列中移除,執(zhí)行完一次消息處理后,再循環(huán)從消息隊列中讀取下一個消息,直到Looper對象調(diào)用stop()方法退出循環(huán)。如果消息隊列中沒有消息,Looper對象則會等待,線程不會退出。

? ? 13. 為了更方便地從線程中使用Looper功能,Android又定義了一個HandlerThread類,該類基于Thread,并且內(nèi)部已經(jīng)添加了Looper功能,使用者只需重寫其onLooperPrepared ()方法,添加具體應用代碼即可。Android中一個Activity就是一個線程,多個Activity之間的切換是在同一個線程中。

二、Android中Activity的調(diào)用流程

? ? 1. 以上偽代碼中,while(1)循環(huán)用于指定該Thread一直執(zhí)行,永不退出,直到被操作系統(tǒng)殺掉。

? ? 2. if(hasHandler())語句判斷該Thread中是否定義了Handler對象,該Handler對象是由應用程序定義的(也可不定義)。

? ? 3. 如果有該對象,那么就會讀取Thread中消息隊列的值,并做一定的處理。執(zhí)行完一個消息后,接著需要執(zhí)行Activity中的用戶界面響應,例如是否有按鍵按下、觸摸屏是否按下等。 處理完一次用戶消息響應后,則繼續(xù)循環(huán)讀取Thread中消息隊列的值。

三、MessageQueue、Looper、Handler調(diào)用關系

? ? 1. 在以上這個大循環(huán)中,Handler對象對應的就是Handler.handleMessage()部分完成的功能,Looper對象對應的就是整個while(1)循環(huán)控制和MessageQueue.getMessage()完成的功能。

? ? 2. Looper對象負責從線程的消息隊列中循環(huán)讀取消息值,再將這些消息傳遞給Handler對象,Handler對象中定義的消息處理函數(shù)會根據(jù)消息類型再調(diào)用Thread中定義的其它函數(shù)。如果Thread中沒有Looper對象,那么Thread的執(zhí)行體就無法讀取消息隊列;如果Thread中沒有Handler對象,則不會處理任何消息。

? ? 3. 一般情況下, Handler和Looper是同時使用的,要么同時有,要么同時沒有。

Android多線程定義

一、線程定義

? ? 1. Android中定義線程的方法與Java相同,可以使用兩種方法:一種是Thread類,另一種是Runnable接口。

? ? 2. Thread是一個類,根據(jù)Java繼承風格,一個類只能有一個父類,繼承了Thread的子類不能再繼承其它類,這是一個缺陷。于是,出現(xiàn)了Runnable,其作用和Thread相同,都是啟動另一個線程,不同的是,Runnable是一個接口(interface),因此可以同時實現(xiàn)多個接口。

? ? 3. Android中使用Thread與Java基本相同,所不同的是,Android拋棄了Java線程中一些不安全的做法。比如:終止一個Thread,在Java中可以調(diào)用線程名字.stop()、線程名字.destroy()等;而在Android中,這些方法都沒有實現(xiàn),即不能使用。

? ? 4. 新建一個Thread對象,需要實現(xiàn)兩個方法:

? ? ? 第一個是定義構造方法。在Android程序中,新建的線程多為Activity、Service等程序片斷服 ? ? ? 務,而在線程的內(nèi)部執(zhí)行過程中,很多時候都需要使用應用程序內(nèi)部的Context對象,因此, ? ? ? 在實際應用中,線程的構造方法往往會傳遞應用程序的Context對象,從而在線程的內(nèi)部可以 ? ? ? 調(diào)用Context相關的系統(tǒng)服務。當然,這不是必須的。

? ? ?第二個是run()方法。該方法是Thread對象中必須實現(xiàn)的方法,用于完成具體的任務。啟動線 ? ? ? 程時,不能直接調(diào)用線程名字.run()方法,而是調(diào)用線程名字.start()方法啟動,start()方法是 ? ? ? ? Thread內(nèi)部使用的,該方法包含初始化線程的工作,然后回調(diào)run()方法,這些對應用程序都 ? ? ? ? 是不可見的。

? ? 5. 停止線程時,不能調(diào)用線程名字.destroy()方法或者線程名字.stop()方法。run()方法執(zhí)行完畢后,線程默認會自動停止。因此,如果需要線程循環(huán)執(zhí)行run()方法內(nèi)部的代碼,可以在線程內(nèi)部增加一個狀態(tài)變量,run()方法內(nèi)部通過檢查該狀態(tài)變量,決定是否繼續(xù)執(zhí)行;同時可在線程外設置該狀態(tài)變量的值,從而終止該線程。

二、線程定義thread

? ? 1. 線程定義Thread,繼承Thread類,并重寫run()方法。在run()中放置代碼的主體部分。

? ? 2. 以上代碼包括3個基本方法:Thread1()為構造方法,用于保存調(diào)用者的Context對象,供以后可能使用;run()方法內(nèi)部是應用代碼;setToStop()用于設置全局變量mRunState的值,run()內(nèi)部循環(huán)執(zhí)行時會判斷該值,決定是否退出run()方法,即終止該線程。

? ? 3. 要在Activity啟動Thread1,首先需要定義一個Thread1對象,并使用構造方法將Activity的Context對象傳遞給Thread1,然后調(diào)用線程的start()方法啟動Thread1線程。要終止Thread的運行,可調(diào)用自定義的Thread1的setToStop()方法。

? ? 4. 以上代碼中,id值為action_stop的按鈕,用于停止Thread1的運行。這是Android系統(tǒng)建議的啟動線程和退出線程的方法。

三、線程定義Runnable

? ? 1. Runnable的作用和Thread基本相同,都是用于定義一個線程,但兩者本質(zhì)上有重要區(qū)別。

? ? 2. 第一:Runnable只是一個接口(interface),其內(nèi)部沒有定義任何已實現(xiàn)的方法。因此,要使用與線程有關的方法,只能使用Thread的靜態(tài)方法,比如:不能直接調(diào)用sleep(),而要調(diào)用Thread.sleep()方法。

? ? 3. 第二:定義一個Thread對象,就意味著創(chuàng)建了一個新線程,而定義一個Runnable對象,只是定義了一個可以當作線程運行的代碼對象,并沒有創(chuàng)建新線程。因此,如果調(diào)用Runnable對象的run()方法,僅相當于把Runnable對象當作普通類對象進行調(diào)用,并沒有啟動一個新線程,Runnable對象和調(diào)用者在同一個線程中運行。

? ? 4. 如果要創(chuàng)建一個新線程,則還需要將Runnable對象傳入Thread的構造方法,從而創(chuàng)建一個新線程,新線程的執(zhí)行碼就是Runnable所定義的。

? ? 5. 第三:Runnable對象經(jīng)常被當作參數(shù)傳遞給一些與線程有關的方法,用于啟動一個新的線程。

? ? 6. 實現(xiàn)Java的Runnable接口,并重載run()方法。在run()中放置代碼的主體部分

? ? 7. 創(chuàng)建Thread對象,并將上面實現(xiàn)的Runnable對象作為參數(shù)傳遞給Thread對象

? ? ① Thread的構造函數(shù)中,第1個參數(shù)用來表示線程組。

? ? ② 第2個參數(shù)是需要執(zhí)行的Runnable對象。

? ? ③ 第3個參數(shù)是線程的名稱。

? ? 8. 調(diào)用start()方法啟動線程。直接用workThread.start();

? ? 9. 線程在run()方法返回后,線程就自動終止了;不推薦使用調(diào)用stop()方法在外部終止線程。

? ? 10. 最好的方法是通知線程自行終止,一般調(diào)用interrupt()方法通告線程準備終止,線程會釋放它正在使用的資源,在完成所有的清理工作后自行關閉。方法是workThread.interrupt();

? ? ① interrupt()方法并不能直接終止線程,僅是改變了線程內(nèi)部的一個布爾字段,run()方法能夠檢測到這個布爾字段,從而知道何時應該釋放資源和終止線程

? ? ② 在run()方法的代碼,一般通過Thread.interrupted()方法查詢線程是否被中斷

? ? 11. 下面的代碼是以1秒為間隔循環(huán)檢測斷線程是否被中斷

? ? ① 第4行代碼使線程休眠1000毫秒。

? ? ② 當線程在休眠過程中被中斷,則會產(chǎn)生InterruptedException 。

? ? ③ 在中斷的線程上調(diào)用sleep()方法,同樣會產(chǎn)生InterruptedException。

? ? 12. Thread.interrupted()方法功能

? ? ① 判斷線程是否應被中斷。

? ? ② 通過捕獲InterruptedException判斷線程是否應被中斷,并且在捕獲到InterruptedException后,安全終止線程。

Handler

一、使用Handler

? ? 1. Handler用于處理線程中的消息隊列。當Looper對象從消息隊列中獲取消息后,會把消息派發(fā)給Handler對象。一個線程中只能有一個Handler對象,可以通過該對象向所在線程發(fā)送消息。因此,只要擁有其它線程中Handler對象的引用,就可以向其發(fā)送消息;除了給別的線程發(fā)送消息外,還可以給本線程發(fā)送消息。

? ? 2. Handler一般有兩種用途:

? ? ① 實現(xiàn)一個定時任務。這個有點類似于Windows中的定時器功能,可以通過Handler對象向所在線程發(fā)送一個延時消息。當消息指定的時間到達后,通過Handler對象的消息處理方法完成指定任務。

? ? ② 在線程間傳遞數(shù)據(jù)。

? ? 3. Handler完成定時任務:

? ? ① 在一個Activity內(nèi)部,經(jīng)常需要做一些定時器的功能,比如周期性更新某個視圖的內(nèi)容、在指定時間后結束某個操作等。

? ? ② 完成定時任務,可以通過Handler對象的延遲發(fā)送消息方法來實現(xiàn)。

? ? ③ 在介紹發(fā)送消息之前,需要先了解一下消息Message的數(shù)據(jù)結構。Message是一個描述消息的數(shù)據(jù)結構類,Message包含很多成員變量和方法,但對于簡單的消息處理,一般僅需了解3項,分別是:⑴ int what 這是用戶自定義的一個整型值,用于區(qū)分消息類型。⑵ int arg1 這是額外消息參數(shù)。⑶ int arg2 同arg1。

? ? 對于需要包含更多數(shù)據(jù)的消息,可以使用message.setData()和getData()方法。setData()方法用于把一個Bundle類數(shù)據(jù)對象加入到Message中,而getData()則是取出該Bundle數(shù)據(jù)。Bundle數(shù)據(jù)類型就是包含“鍵值對”數(shù)據(jù)的類型。

? ? 4. Handler發(fā)送消息的方式:

? ? ① 一類是postXXX()方法,該方法用于把一個Runnable對象發(fā)送到消息隊列。從而當消息被處理時,能夠執(zhí)行Runnable對象;

? ? ② 另一類是sendXXX()方法,該方法用于發(fā)送一個Message類型的消息到消息隊列,當消息被處理時,系統(tǒng)會調(diào)用Handler對象定義的handleMessage()方法處理該消息。

? ? 5. 實現(xiàn)定時任務則主要使用sendXXX()類,該類具體包含如下方法:

? ? ① sendEmptyMessage(int what),空消息是指該消息僅包含what值。

? ? ② sendEmptyMessageAtTime(int what, long uptimeMilis),在指定時間點發(fā)送空消息,uptimeMilis是指從本次開機開始運行的時間點,不包含系統(tǒng)休眠的時間,單位為毫秒。參照SystemClock類。

? ? ③ sendEmptyMessageDelayed(int what, long delayMillis),在指定時間后發(fā)送空消息,指定的時間以毫秒為單位。

? ? ④ sendMessage(Message),發(fā)送Message指定的消息。

? ? ⑤ sendMessageAtTime(Message,long),在指定時間點發(fā)送該消息。

? ? ⑥ sendMessageDelayed(Message, long),在指定的時間后發(fā)送該消息。

? ? 實現(xiàn)定時任務時,一般使用sendMessageAtDelayed()或者sendEmptyMessageAtDelayed()方法,即在指定的時間后發(fā)送消息。當收到該消息后,系統(tǒng)會調(diào)用Handler對象實現(xiàn)的消息處理接口handleMessage(),handleMessage()的參數(shù)是Message對象,可以通過Message的相關方法獲得Message的具體值,并根據(jù)其消息完成不同的任務。

二、Handler定時案例

? ? 1. handleMessage用于處理Activity所在線程接收到的消息,此處是把當前時間顯示在文本框中。obtainMessage()方法用于從全局的消息池中獲得一個已有的Message對象,系統(tǒng)為了加速線程間的消息傳遞,創(chuàng)建了一些全局的消息對象供各線程使用,這些全局消息對象稱為全局消息池,使用該方法比重新創(chuàng)建一個消息對象的效率高。該方法的第一個參數(shù)用于指定初始化返回消息的what值。sendMessageDelayed()方法用于在1000毫秒后發(fā)送what值為100的消息,即在顯示完當前時間后的1秒,再發(fā)送一次消息,從而可以每過1秒更新一次文本框的時間。此處使用100代表該消息類型。

? ? 2. 需要注意的是:在應用程序運行時,當用戶按Back鍵返回后,盡管Activity進入了暫?;蛘咄V沟臓顟B(tài),但是消息的發(fā)送會依然在后臺執(zhí)行,因此,程序員需要根據(jù)情況決定是否要停止消息發(fā)送。例如可以在onPause()方法內(nèi)將消息隊列中的消息移除,并在onResume()方法中重新開始消息發(fā)送。removeMessage(100)方法用于移除消息隊列中what值為100的全部消息。

? ? 3. Handler完成線程間傳遞數(shù)據(jù)。

? ? ① 使用Handler對象不但可以給本線程發(fā)送消息,還可以給其它線程發(fā)送消息,前提是需要獲取其它線程中的Handler對象。

? ? ② 線程之間傳遞數(shù)據(jù)在GUI應用中十分廣泛,比如后臺線程正在執(zhí)行具體的數(shù)據(jù)處理,前臺界面需要顯示出處理的進度,典型的就是進度對話框。在這種應用中,前臺線程(一般是指Activity)創(chuàng)建一個后臺線程,并把前臺線程的Handler對象傳遞給后臺線程,后臺線程就可以通過該Handler對象向前臺線程發(fā)送消息,報告后臺數(shù)據(jù)處理的進度。

Looper

? ? 1. Thread在默認情況下,只要run()方法執(zhí)行完畢,線程就結束。簡單控制線程不主動退出的方法是:在run()方法內(nèi)部加一個while()循環(huán),這的確也能解決一些問題,對于那些不需要接收消息而言,基本上夠用了。

? ? 2. 但在另一些情況下,新建的線程需要接收消息并處理,因此,在新線程中,除了需要添加一個Handler對象外,還需要從線程的消息隊列中取出消息,并負責分發(fā)消息,這就需要Looper了。

? ? 3. 事實上,Activity內(nèi)部就有一個Looper,只是Activity是一個特殊的Thread,操作系統(tǒng)已經(jīng)將其封裝了而已。

? Looper往往和Handler同時使用

? ? 4. Looper.prepare()用于給該線程創(chuàng)建一個Looper對象;Looper.loop()用于開始執(zhí)行Looper對象,所謂的執(zhí)行就是讓Looper對象開始讀取線程的消息隊列,并派發(fā)消息到Handler對象的handleMessage()方法。

? ? 5. 請注意以上的someOtherFunction()方法,run()方法中,該方法只能被執(zhí)行一次,執(zhí)行完該方法后,開始執(zhí)行Looper.loop()方法,系統(tǒng)便進入了Looper對象的世界里,以后就只會執(zhí)行handleMessage方法了。

? ? 6. 從LogCat的輸出結果來看,someOtherFunction()在線程啟動后執(zhí)行一次。而Thread每收到一次what值為100的消息,method1()就會被執(zhí)行一次;當thread收到what值為200的消息后,調(diào)用getLooper().quit()方法,Looper對象就停止運行,run()方法會執(zhí)行完畢,該線程結束。

? ? 7. looperTest()方法中,開始時先創(chuàng)建后臺線程并啟動,然后調(diào)用線程的自定義方法getHandler()獲得后臺線程的Handler對象。注意此處使用do/while語句,線程在啟動后其內(nèi)部的Handler對象不會馬上就緒,因此這里需要等待。

? ? 8. 接著讓兩個按鈕按下時分別發(fā)送what值為100和200的Message,用于執(zhí)行method1()方法和looper退出操作。

? ? HandlerThread類是一種內(nèi)部包含了Looper對象的Thread子類。該類是為了簡化Looper的操作,使用時只需要重寫onLooperPrepared()方法,在其中添加一個Handler對象即可。其作用與在Thread中加入Looper對象和Handler對象是完全一樣的。onLooperPrepared()被調(diào)用的時機類似于在Thread中執(zhí)行完Looper.prepared()方法。

? ? 線程是獨立的程序單元,多個線程可以并行工作,每個線程都有一個消息隊列,用于不同的線程之間傳遞消息。無論是本線程的還是其它線程,都不能直接處理消息隊列中的消息,而是需要通過在線程內(nèi)部定義一個Handler類對象來處理消息隊列。

? ? leo這里給大家強調(diào)下一個Thread只能包含一個Handler對象。在實際應用中,讀取消息隊列一般需要循環(huán)執(zhí)行,即不斷地從消息隊列中獲取消息并進行相應處理,這就又需要一個Looper對象。今天就leo就給大家總結到這了,希望對同是Android開發(fā)者的你們有用,如有什么指正建議,歡迎提出并聯(lián)系!

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

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