java內(nèi)存模型與線程

1. 緩存一致性

計算機并發(fā)執(zhí)行若干任務号涯,需要與內(nèi)存交互。計算機存儲設備處理速度與處理器處理速度有著量級的差距芜抒,所以現(xiàn)代計算機系統(tǒng)不得不加入一層讀寫速度盡可能接近處理器運算速度的“高速緩存”來處理內(nèi)存與處理器之間的緩沖:將運算需要使用的數(shù)據(jù)復制到緩存中徽诲,讓運算快速進行劝萤,運算結束后再從緩存同步到內(nèi)存中,這樣處理器無需等待緩慢的內(nèi)存讀寫了煞赢。

但是這樣引入了一個問題:緩存一致性抛计。多處理器系統(tǒng),每個系統(tǒng)有自己的高速緩存照筑,而又共享同一主內(nèi)存吹截。當多個處理器運算任務都涉及同一主內(nèi)存區(qū)域時瘦陈,將導致各自的緩存數(shù)據(jù)不一致,如果真的發(fā)生這種情況波俄,同步回主內(nèi)存時以誰的緩存數(shù)據(jù)為準呢晨逝?為了解決一致性的問題,需要各個處理器訪問緩存時遵循一些協(xié)議懦铺,在讀寫時根據(jù)協(xié)議進行操作捉貌,如MESI。

MESI緩存一致性協(xié)議
如果變量X是一個如valotile修飾的變量冬念,相當于在底層加了一個#Lock趁窃,此時會觸發(fā)MESI緩存一致性協(xié)議。

1.T1線程讀取了主內(nèi)存變量X刘急,將變量X標記為E狀態(tài)棚菊,同時會一直監(jiān)聽/嗅探bus其他線程是否有對變量X的操作。
2.如果此時線程T2也讀取了變量X叔汁,此時嗅探機制起作用统求,線程1與線程2會將變量X都編輯為S狀態(tài)。
3.如果線程T1修改了變量X据块,先鎖住該變量緩存行+將變量X標記為M+向bus發(fā)送消息码邻,同時線程T2會嗅探到bus消息中其他線程要修改變量X,這時線程T2會將變量X標記為I另假。需要重新讀取主存的變量X像屋。
4.線程T1修改完變量X后,將狀態(tài)標記為E边篮,并寫回主內(nèi)存中X新值己莺。

狀態(tài) 描述 監(jiān)聽任務
M 修改 (Modified) 該Cache line有效,數(shù)據(jù)被修改了戈轿,和內(nèi)存中的數(shù)據(jù)不一致凌受,數(shù)據(jù)只存在于本Cache中。 緩存行必須時刻監(jiān)聽所有試圖讀該緩存行相對就主存的操作思杯,這種操作必須在緩存將該緩存行寫回主存并將狀態(tài)變成S(共享)狀態(tài)之前被延遲執(zhí)行胜蛉。
E 獨享、互斥 (Exclusive) 該Cache line有效色乾,數(shù)據(jù)和內(nèi)存中的數(shù)據(jù)一致誊册,數(shù)據(jù)只存在于本Cache中。 緩存行也必須監(jiān)聽其它緩存讀主存中該緩存行的操作暖璧,一旦有這種操作案怯,該緩存行需要變成S(共享)狀態(tài)。
S 共享 (Shared) 該Cache line有效漆撞,數(shù)據(jù)和內(nèi)存中的數(shù)據(jù)一致殴泰,數(shù)據(jù)存在于很多Cache中于宙。 緩存行也必須監(jiān)聽其它緩存使該緩存行無效或者獨享該緩存行的請求,并將該緩存行變成無效(Invalid)悍汛。
I 無效 (Invalid) 該Cache line無效捞魁。

總線鎖與緩存一致性協(xié)議:如果是一個緩存行(緩存最小單位),則使用緩存一致性協(xié)議离咐,多行使用總線鎖谱俭。

2. java內(nèi)存模型(java memory model, JMM)

java虛擬機規(guī)范試圖定義一種java內(nèi)存模型來屏蔽掉各種硬件與操作系統(tǒng)的內(nèi)存訪問差異,以實現(xiàn)java程序在各種平臺下都能達到一致的內(nèi)存訪問效果宵蛀。

2.1 主內(nèi)存與工作內(nèi)存

java內(nèi)存模型主要目標是定義程序中各個變量的訪問規(guī)則昆著,其是一個抽象,即咋虛擬機中將變量存儲到內(nèi)存和從內(nèi)存取出變量這樣的底層細節(jié)术陶。此處的變量包括****實例對象凑懂,靜態(tài)字段和構成數(shù)組對象的元素,但不包括局部變量與方法參數(shù)梧宫。因為后者是線程私有的接谨,不會被共享,自然不會存在競爭問題塘匣。

java內(nèi)存模型規(guī)定了所有的變量存儲在主內(nèi)存中脓豪,對應硬件的主內(nèi)存。每條線程還有自己的工作內(nèi)存忌卤,對應硬件的CPU緩存扫夜、寄存器。線程對變量的所有操作(讀取驰徊,賦值等)必須在工作內(nèi)存中進行笤闯,而不能直接讀寫主內(nèi)存中的變量。不同的線程之間也無法直接訪問對方工作內(nèi)存中的變量棍厂,線程間變量值的傳遞均需要主內(nèi)存完成望侈。

java內(nèi)存模型與java內(nèi)存區(qū)域并不是一個層次的內(nèi)存劃分,基本上沒有聯(lián)系勋桶。如果非要對應的話,主內(nèi)存主要對應java堆中的對象實例數(shù)據(jù)部分侥猬,而工作內(nèi)存則對應虛擬機棧的部分區(qū)域例驹。

2.2 內(nèi)存見交互操作

關于主內(nèi)存與工作內(nèi)存之間具體的交互協(xié)議,即一個變量如何從主內(nèi)存拷貝到工作內(nèi)存退唠、如何從工作內(nèi)存同步回主內(nèi)存的實現(xiàn)細節(jié)鹃锈,java內(nèi)存模型定義了8種操作完成,以下每種操作都是原子的瞧预,不可再分的屎债。

double仅政,long特殊規(guī)則:虛允許虛擬機將沒有被volatile修飾的64位數(shù)據(jù)的讀寫劃分為兩次32位的操作,即虛允許虛擬機實現(xiàn)選擇可以不保證64位數(shù)據(jù)類型的load\store\read\write操作的原子性盆驹,這就是所謂的double和long的非原子性協(xié)定圆丹。但是目前各種平臺的商用虛擬機幾乎都選擇把64位數(shù)據(jù)的讀寫操作作為原子操作對待,因為編寫代碼時一般不需要把用到的long和double變量專門聲明為volatile躯喇。

(1)lock(鎖定):作用于主內(nèi)存的變量辫封,把一個變量標記為一條線程獨占狀態(tài)
(2)unlock(解鎖):作用于主內(nèi)存的變量,把一個處于鎖定狀態(tài)的變量釋放出來廉丽,釋放后的 變量才可以被其他線程鎖定
(3)read(讀取):作用于主內(nèi)存的變量倦微,把一個變量值從主內(nèi)存?zhèn)鬏數(shù)骄€程的工作內(nèi)存中, 以便隨后的load動作使用
(4)load(載入):作用于工作內(nèi)存的變量正压,它把read操作從主內(nèi)存中得到的變量值放入工作 內(nèi)存的變量副本中
(5)use(使用):作用于工作內(nèi)存的變量欣福,把工作內(nèi)存中的一個變量值傳遞給執(zhí)行引擎,每當虛擬機遇到一個需要變量的值的字節(jié)碼指令時將會執(zhí)行這個操作
(6)assign(賦值):作用于工作內(nèi)存的變量焦履,它把一個從執(zhí)行引擎接收到的值賦給工作內(nèi)存的變量拓劝,每當虛擬機遇到一個給變量賦值的字節(jié)碼指令時將會執(zhí)行這個操作
(7)store(存儲):作用于工作內(nèi)存的變量,把工作內(nèi)存中的一個變量的值傳送到主內(nèi)存中裁良, 以便隨后的write的操作
(8)write(寫入):作用于工作內(nèi)存的變量凿将,它把store操作從工作內(nèi)存中的一個變量的值傳送到主內(nèi)存的變量中

主內(nèi)存復制到工作內(nèi)存:read+load
工作內(nèi)存復制到主內(nèi)存:store+write

注:java內(nèi)存模型只要求上述兩個操作必須按順序執(zhí)行,而沒有保證是連續(xù)執(zhí)行价脾。即可能出現(xiàn)read a牧抵、read b、load b侨把、load a犀变。

規(guī)則:

  1. 不允許read和load、store和write操作單獨出現(xiàn)秋柄,即不允許一個變量從主內(nèi)存讀取了但工作內(nèi)存不接受获枝,或相反的情況出現(xiàn)
  2. 不允許一個線程丟棄他的最近的assign操作,即變量在工作內(nèi)存改變了之后必須把該變化同步回主內(nèi)存
  3. 不允許一個線程無原因地(沒有發(fā)生過任何assign操作)把數(shù)據(jù)從工作內(nèi)存同步回主內(nèi)存中
  4. 一個新的變量只能在主內(nèi)存中誕生骇笔,不允許在工作內(nèi)存中直接使用一個未被初始化(load或者assign)的變量省店。即就是對一個變量實施use和store操作之前,必須先自行assign和load操作笨触。
  5. 一個變量在同一時刻只允許一條線程對其進行l(wèi)ock操作懦傍,但lock操作可以被同一線程重復執(zhí)行多次,多次執(zhí)行l(wèi)ock后芦劣,只有執(zhí)行相同次數(shù)的unlock操作粗俱,變量才會被解鎖。lock和unlock必須成對出現(xiàn)虚吟。
  6. 如果對一個變量執(zhí)行l(wèi)ock操作寸认,將會清空工作內(nèi)存中此變量的值签财,在執(zhí)行引擎使用這個變量之前需要重新執(zhí)行l(wèi)oad或assign操作初始化變量的值。
  7. 如果一個變量事先沒有被lock操作鎖定偏塞,則不允許對它執(zhí)行unlock操作唱蒸;也不允許去unlock一個被其他線程鎖定的變量。
  8. 對一個變量執(zhí)行unlock操作之前烛愧,必須先把此變量同步到主內(nèi)存中(執(zhí)行store和write操作)

2.3 對于volatile型變量的特殊規(guī)則

vaolatile是java虛擬機提供的最輕量級的同步機制油宜。

特性1.保證此變量對所有線程的可見性。這里的可見性是指一條線程修改了這個變量的值怜姿,新值對于其他線程來說是可以立即得知的慎冤。普通變量的值在線程間傳遞均需要主內(nèi)存來完成。

(1)運算結果并不依賴于變量的當前值沧卢,或者能夠確保只有單一的線程修改變量的值
(2)變量不需要與其他的狀態(tài)變量共同參與不變約束蚁堤。

滿足以上兩點,volatile可保證原子性但狭。

特性2.禁止指令重排序優(yōu)化披诗。普通變量僅僅會保證在該方法的執(zhí)行過程中所有依賴賦值結果的地方都能獲取到正確的結果,而不能保證變量賦值操作的順序與程序代碼中的執(zhí)行順序一致(As-If-Serial)立磁。

指令重排
編譯器以及CPU為了優(yōu)化代碼或者執(zhí)行的效率而執(zhí)行的優(yōu)化操作
無論重排前還是重排后程序的執(zhí)行結果在單線程中并沒有改變呈队,因此這種重排優(yōu)化是允許的。
指令重排一般發(fā)生在編譯器和CPU運行時唱歧。
As-If-Serial:不管怎么重排序(編譯器和處理器為了提高并行度)宪摧,(單線程)程序的執(zhí)行結果不能被改變,多線程不遵守此原則颅崩。

內(nèi)存屏障
1.保證特定操作的執(zhí)行順序
2.保證某些變量的內(nèi)存可見性
通過插入內(nèi)存屏障禁止在內(nèi)存屏障前后的指令執(zhí)行重排序優(yōu)化几于,禁止指令重排。

內(nèi)存屏障插入規(guī)則

是否能重排序 第二個操作
第一個操作 普通讀/寫 volatile讀 volatile寫
普通讀/寫 NO
volatile讀 NO NO NO
volatile寫 NO NO

JMM保守策略內(nèi)存屏障插入規(guī)則
在每個volatile寫操作的前面插入一個StoreStore屏障沿后。
在每個volatile寫操作的后面插入一個StoreLoad屏障沿彭。
在每個volatile讀操作的后面插入一個LoadLoad屏障。
在每個volatile讀操作的后面插入一個LoadStore屏障尖滚。

2.4原子性喉刘、可見性、有序性

原子性:由java內(nèi)存模型直接保證的原子性變量操作包括read漆弄、load饱搏、assign、use置逻、store、write备绽,基本數(shù)據(jù)類型的訪問讀寫是具備原子性的券坞。大范圍的原子性保證鬓催,java內(nèi)存模型提供了lock、unlock來滿足恨锚,虛擬機提供了更高層次的字節(jié)碼指令monitorenter和monitorexit隱式對應宇驾,反映到java代碼就是同步塊-synchronized關鍵字。

可見性:一個線程修改了共享變量的值猴伶,其他線程能立即得知這個修改课舍。java內(nèi)存模型是通過在變量修改后將新值同步回主內(nèi)存,在變量讀取前從主內(nèi)存刷新變量值的這種依賴主內(nèi)存作為傳遞媒介的方式來實現(xiàn)可見性的他挎,無論是普通變量還是volatile變量都是如此筝尾,普通變量與volatile變量變量的區(qū)別是,volatile的特殊規(guī)則保證了新值能立即同步到主內(nèi)存办桨,以及每次使用前立即從主內(nèi)存刷新筹淫。因此,可以說volatile保證了多線程操作時變量的可見性呢撞,而普通變量則不能保證這一點损姜。對應上邊MESI一致性協(xié)議分析

synchronized和final也能實現(xiàn)可見性。同步塊的可見性是由“對一個變量執(zhí)行unlock操作之前殊霞,必須先把此變量同步回主內(nèi)存中(執(zhí)行store摧阅、write操作)”這條規(guī)則獲得的。

有序性:如果在本線程內(nèi)觀察绷蹲,所有操作都是有序的(串行As-If-Serial)棒卷;如果在一個線程觀察另一個線程,所有操作都是無序的(指令重排瘸右,工作內(nèi)存與主內(nèi)存同步延遲)娇跟。volatile有序性本身就包含了禁止指令重排的語義;synchronized有序性是由“一個變量在同一時刻只允許一條進程對其進行l(wèi)ock操作”保證的太颤。

2.5先行發(fā)生原則

先行發(fā)生是java內(nèi)存模型定義的兩項操作之間的偏序關系苞俘,如果操作A先行發(fā)生于操作B,其實就是發(fā)生在操作B之前龄章,操作A產(chǎn)生的影響能被操作B觀察到吃谣,“影響”包括修改內(nèi)存中共享變量的值,發(fā)送了消息做裙,調(diào)用了方法等岗憋。

天然先行發(fā)生關系:

1.線程次序規(guī)則:在一個線程內(nèi),按照程序代碼順序锚贱,書寫在前面的操作先行發(fā)生于書寫在后面的操作仔戈。準確地說,應該是控制流順序而不是程序代碼順序,因為要考慮分支监徘、循環(huán)等結構
2.管程鎖定規(guī)則:一個unlock操作先行發(fā)生于后面對同一個鎖的lock操作晋修。這里必須強調(diào)的是同一個鎖,而“后面”是指時間上的先后順序凰盔。
3.volatile變量規(guī)則:對一個volatile變量的寫操作先行發(fā)生于后面對這個變量的讀操作墓卦,這里的“后面”同樣是指時間上的先后順序。
4.線程啟動規(guī)則:Thread對象的start()方法先行發(fā)生于此線程的每一個動作户敬。
5.線程終止規(guī)則:線程中的所有操作都先行發(fā)生于對此線程的終止檢測落剪,我們可以通過Thread.join()方法結束、Thread.isAlive()的返回值等手段加測到線程已經(jīng)終止執(zhí)行尿庐。
6.線程中斷規(guī)則:對線程interrupt()方法的調(diào)用先發(fā)生于被中斷線程的代碼檢測到中斷事件的發(fā)生忠怖,可以通過Thread.interrupted()方法檢測到是否有中斷發(fā)生。
7.對象終結規(guī)則:一個對象的初始化完成(構造函數(shù)執(zhí)行結束)先行發(fā)生于它的finalize()方法的開始屁倔。
8.傳遞性:如果操作A先行發(fā)生于操作B脑又,操作B先行發(fā)生于操作C,那就可以得出操作A先行發(fā)生于操作C的結論锐借。

如果兩個操作之間的關系不在天然發(fā)生關系中问麸,就沒有順序保障,虛擬機可以對他們隨意的進行重排序钞翔。

3 java與線程

3.1 線程的實現(xiàn)

使用內(nèi)核線程實現(xiàn)严卖、使用用戶線程實現(xiàn)、使用用戶線程加輕量級進程混合實現(xiàn)

1.內(nèi)核線程實現(xiàn)

內(nèi)核線程(KTL)就是直接由操作系統(tǒng)內(nèi)核支持的線程布轿,這種線程由內(nèi)核完成線程切換哮笆,內(nèi)核通過操縱調(diào)度器對線程進行調(diào)度,并負責將線程的任務映射到各個處理器上
程序一般不會直接去使用內(nèi)核線程汰扭,而是去使用內(nèi)核線程的一種高級接口-輕量級進程(LWP)稠肘,輕量級進程就是我們通常意義上所講的進程,由于每個輕量級進程都由一個內(nèi)核線程支持萝毛,因此只有先支持內(nèi)核線程项阴,才能有輕量級進程。這種輕量級進程與內(nèi)核線程之間1:1的關系稱為一對一線程模型笆包。

輕量級進程局限性:
(1)基于內(nèi)核實現(xiàn)环揽,各種線程操作,如創(chuàng)建庵佣,析構及同步歉胶,都需要進行系統(tǒng)調(diào)用。而系統(tǒng)調(diào)用代價相對較高巴粪,需要在用戶態(tài)和內(nèi)核態(tài)來回切換
(2)每個輕量級進程都需要有一個內(nèi)核線程的支持通今,因此輕量級進程要消耗一定的內(nèi)核資源(如內(nèi)核線程的椫嗝空間),因此一個系統(tǒng)支持輕量級進程的數(shù)量時有限的衡创。

2.使用用戶線程實現(xiàn)

廣義講帝嗡,一個線程只要不是內(nèi)核線程,就可以認為是用戶線程(UT)璃氢。狹義上用戶線程指的是完全建立在用戶空間的線程庫上,系統(tǒng)內(nèi)核不能感知線程存在的實現(xiàn)狮辽。用戶線程的建立一也、同步、銷毀和調(diào)度完全在用戶態(tài)中完成喉脖,不需要內(nèi)核的幫助椰苟。部分高性能數(shù)據(jù)庫中的多線程是由用戶線程實現(xiàn)的。這種進程與用戶線程之間1:N的關系稱為一對多的線程模型树叽。

用戶線程優(yōu)勢:不需要系統(tǒng)內(nèi)核支持
用戶線程劣勢:沒有內(nèi)核的支持舆蝴,所有線程操作需要用戶程序自己處理。(1).要考慮線程創(chuàng)建题诵、切換洁仗、調(diào)度 (2).由于系統(tǒng)操作只把處理器資源分配到進程,哪諸如“阻塞處理”性锭,“多處理器系統(tǒng)如何將線程映射到其他處理器上”這些問題解決起來異常困難赠潦。

3.使用用戶線程加輕量級進程混合實現(xiàn)
用戶線程建立在用戶空間中,因此用戶線程的創(chuàng)建草冈、切換烤送、析構等操作依然廉價蟆豫,并且可以支持大規(guī)模的用戶線程并發(fā)。而操作系統(tǒng)提供支持的輕量級進程則作為用戶線程和內(nèi)核進程之間的橋梁,這樣可以使用內(nèi)核提供的線程調(diào)度功能及處理器映射好渠,并且用戶線程的系統(tǒng)調(diào)用要通過輕量級進程來完成,大大降低了整個進程被完全阻塞的風險终畅。這種混合模式中渴肉,用戶線程與輕量級進程的數(shù)量比是不定的,即N:M诅岩,多對多的線程模型讳苦。

4.java線程的實現(xiàn)
jdk12以前,用戶線程吩谦。
jdk12以后鸳谜,線程模型替換為基于操作系統(tǒng)原生線程模型來實現(xiàn)。windows和linux使用一對一線程模型式廷,一條java線程就映射到一條輕量級進程中(因為linux和windows系統(tǒng)提供的線程模型就是一對一的)咐扭。solaris同時支持一對一和多對多,可通過參數(shù)配置。

3.2 java線程調(diào)度

線程調(diào)度是指系統(tǒng)為線程分配處理器使用權的過程蝗肪,分為協(xié)同式調(diào)度和搶占式調(diào)度袜爪。

協(xié)同式:現(xiàn)成的執(zhí)行時間由線程本身控制,線程把自己的工作處理完了之后薛闪,主動通知系統(tǒng)切換到另一個線程上辛馆。好處:實現(xiàn)簡單,切換操作自己可知豁延,沒有線程同步問題昙篙。壞處:線程執(zhí)行時間不可控制,如果一個線程編寫有問題诱咏,一直不告知系統(tǒng)進行線程抓換苔可,程序會阻塞住。
搶占式:每個線程將由系統(tǒng)分配執(zhí)行時間袋狞,線程的切換不由線程本身來決定(java Thread.yield可以讓出執(zhí)行時間焚辅,但是線程本身還是沒辦法獲取執(zhí)行時間)。好處:線程執(zhí)行時間系統(tǒng)可控苟鸯,不會出現(xiàn)一個線程阻塞程序的問題同蜻,java使用的就是這種。

雖然java線程調(diào)度是系統(tǒng)自動完成的倔毙,但是可以建議系統(tǒng)給某些線程多分配一點執(zhí)行時間埃仪,另外的一些少點執(zhí)行時間,即可通過設置線程優(yōu)先級來完成陕赃。java一共有10個優(yōu)先級卵蛉,多個和線程同時處于Ready狀態(tài)時,優(yōu)先級越高越容易被系統(tǒng)選擇執(zhí)行么库。

不過優(yōu)先級并不完全靠譜傻丝,因為基于的系統(tǒng)原生線程實現(xiàn),所以取決于操作系統(tǒng)诉儒。1.操作系統(tǒng)的優(yōu)先級與java的優(yōu)先級級別并不一定可以一一對應葡缰。2.系統(tǒng)可能會自動改變,如windows既有優(yōu)先級推進器忱反,會識別特別勤奮的線程泛释,越過優(yōu)先級為它分配執(zhí)行時間。

3.3 狀態(tài)轉(zhuǎn)換

在任意時間點温算,一個線程有且只能由一種狀態(tài)怜校。

  1. 新建(NEW):創(chuàng)建后尚未啟動的線程
  2. 運行(RUNNABLE):Runable包括了操作系統(tǒng)線程狀態(tài)的Running和Ready,也就是處于此狀態(tài)的線程有可能正在執(zhí)行注竿,也可能在等待CPU為他分配執(zhí)行時間茄茁。
  3. 無限期等待(WAITING):處于該狀態(tài)的線程不會被分配CPU執(zhí)行時間魂贬,他們要等待被其他線程顯式的喚醒,以下方法會陷入無限期等待狀態(tài):

沒有設置Timeout參數(shù)的Object.wait()方法
沒有設置Timeout參數(shù)的Thread.join()方法
LockSupport.park()方法

  1. 限期等待(TIMED WAITING):處于該狀態(tài)的線程也不會被分配CPU執(zhí)行時間裙顽,不過無需等待被其他線程顯式的喚醒付燥,在一定時間后會由系統(tǒng)自動喚醒,以下方法會陷入限期等待狀態(tài):

Thread.sleep()方法 設置Timeout參數(shù)的Object.wait()方法
設置Timeout參數(shù)的Thread.join()方法
LockSupport.parkNanos()方法
LockSupport.parkUntil()方法

  1. 阻塞(BLOCKED):線程被阻塞了愈犹,阻塞狀態(tài)與等待狀態(tài)區(qū)別是:阻塞狀態(tài)在等待著獲取到一個排他鎖键科,這個事件將在另外一個線程放棄這個鎖的時候發(fā)生;而等待狀態(tài)則是在等待一段時間漩怎,或者喚醒動作的發(fā)生萝嘁。在程序等待進入同步區(qū)域的時候,線程進入這種狀態(tài)扬卷。
  2. 結束(TERMINATED):線程已經(jīng)執(zhí)行完畢。
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末酸钦,一起剝皮案震驚了整個濱河市怪得,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌卑硫,老刑警劉巖徒恋,帶你破解...
    沈念sama閱讀 222,627評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異欢伏,居然都是意外死亡入挣,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評論 3 399
  • 文/潘曉璐 我一進店門硝拧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來径筏,“玉大人,你說我怎么就攤上這事障陶∽烫瘢” “怎么了?”我有些...
    開封第一講書人閱讀 169,346評論 0 362
  • 文/不壞的土叔 我叫張陵抱究,是天一觀的道長恢氯。 經(jīng)常有香客問我,道長鼓寺,這世上最難降的妖魔是什么勋拟? 我笑而不...
    開封第一講書人閱讀 60,097評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮妈候,結果婚禮上敢靡,老公的妹妹穿的比我還像新娘。我一直安慰自己州丹,他們只是感情好醋安,可當我...
    茶點故事閱讀 69,100評論 6 398
  • 文/花漫 我一把揭開白布杂彭。 她就那樣靜靜地躺著,像睡著了一般吓揪。 火紅的嫁衣襯著肌膚如雪亲怠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,696評論 1 312
  • 那天柠辞,我揣著相機與錄音团秽,去河邊找鬼。 笑死叭首,一個胖子當著我的面吹牛习勤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播焙格,決...
    沈念sama閱讀 41,165評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼图毕,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了眷唉?” 一聲冷哼從身側響起予颤,我...
    開封第一講書人閱讀 40,108評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎冬阳,沒想到半個月后蛤虐,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,646評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡肝陪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,709評論 3 342
  • 正文 我和宋清朗相戀三年驳庭,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片氯窍。...
    茶點故事閱讀 40,861評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡饲常,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出荞驴,到底是詐尸還是另有隱情不皆,我是刑警寧澤,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布熊楼,位于F島的核電站霹娄,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏鲫骗。R本人自食惡果不足惜犬耻,卻給世界環(huán)境...
    茶點故事閱讀 42,196評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望执泰。 院中可真熱鬧枕磁,春花似錦、人聲如沸术吝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至沦寂,卻和暖如春学密,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背传藏。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評論 1 274
  • 我被黑心中介騙來泰國打工腻暮, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人毯侦。 一個月前我還...
    沈念sama閱讀 49,287評論 3 379
  • 正文 我出身青樓哭靖,卻偏偏與公主長得像,于是被迫代替她去往敵國和親侈离。 傳聞我的和親對象是個殘疾皇子试幽,可洞房花燭夜當晚...
    茶點故事閱讀 45,860評論 2 361

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