Java多線程

一草慧、sychronized介紹

????并發(fā)時(shí)桶蛔,多個線程需要操作同一個資源,容易導(dǎo)致錯誤數(shù)據(jù)的產(chǎn)生漫谷,為了解決這個問題仔雷,當(dāng)存在多個線程操作共享數(shù)據(jù)時(shí),需要保證同一時(shí)刻只有一個線程在操作共享數(shù)據(jù)舔示,其他線程必須等到該線程處理完數(shù)據(jù)后再進(jìn)行碟婆。

? ? java中sychronized關(guān)鍵字可以保證同一時(shí)刻只有一個線程可以執(zhí)行某個方法或者代碼塊,同時(shí)sychronized可保證一個線程的變化被其他線程看到(保證可見性)惕稻。

二竖共、sychronized 應(yīng)用方式

? ? 1、作用于實(shí)例方法俺祠,當(dāng)前實(shí)例加鎖肘迎,進(jìn)入同步代碼塊時(shí)需要獲得當(dāng)前實(shí)例的鎖;

? ? 2锻煌、作用于靜態(tài)方法,當(dāng)前類加鎖姻蚓,進(jìn)去同步代碼前需要獲取當(dāng)前類的鎖宋梧;

? ? 3、作用于代碼塊狰挡,這需要指定加鎖對象捂龄,對所給的指定對象加鎖,進(jìn)入同步代碼塊前要獲得指定對象的鎖加叁;

三倦沧、sychronized底層原理

? ? java虛擬機(jī)中的同步Synchronization基于進(jìn)入和退出管程Monitor對象實(shí)現(xiàn)。在java中它匕,sychronized可以修飾同步方法展融,同步方法不是由monitorenter和moniterexit指令來實(shí)現(xiàn)同步,而是由方法調(diào)用指令讀取運(yùn)行時(shí)常量池中的ACC_SYNCHRONIZED標(biāo)注來隱式調(diào)用的豫柬。

?java對象頭與monitor

? ? 在java中告希,對象在內(nèi)存中的布局分為三塊區(qū)域,對象頭烧给,實(shí)例數(shù)據(jù)和填充數(shù)據(jù)燕偶。


java對象

1、對象頭

? ? HotSpot虛擬機(jī)的對象頭包括markword和klass础嫡,數(shù)組長度指么;

? ? markword用于存儲對象自身的運(yùn)行時(shí)數(shù)據(jù),如哈希碼(HashCode)、GC分代年齡伯诬、鎖狀態(tài)標(biāo)志晚唇、線程持有的鎖、偏向線程ID姑廉、偏向時(shí)間戳等缺亮,這部分?jǐn)?shù)據(jù)的長度在32位和64位的虛擬機(jī)(未開啟壓縮指針)中分別為32bit和64bit,官方稱它為MarkWord桥言。

? ? 對象頭的另外一部分是klass類型指針萌踱,即對象指向它的類元數(shù)據(jù)的指針,虛擬機(jī)通過這個指針來確定這個對象是哪個類的實(shí)例号阿。

? ? 數(shù)組長度并鸵,如果對象是一個數(shù)組, 那在對象頭中還必須有一塊數(shù)據(jù)用于記錄數(shù)組長度。

2扔涧、實(shí)例數(shù)據(jù)

? ? 實(shí)例數(shù)據(jù)部分是對象真正存儲的有效信息园担,也是在程序代碼中所定義的各種類型的字段內(nèi)容。無論是從父類繼承下來的枯夜,還是在子類中定義的弯汰,都需要記錄起來。

3湖雹、對象填充

? ??對齊填充并不是必然存在的咏闪,也沒有特別的含義,它僅僅起著占位符的作用摔吏。由于HotSpot VM的自動內(nèi)存管理系統(tǒng)要求對象起始地址必須是8字節(jié)的整數(shù)倍鸽嫂,換句話說,就是對象的大小必須是8字節(jié)的整數(shù)倍征讲。而對象頭部分正好是8字節(jié)的倍數(shù)(1倍或者2倍)据某,因此,當(dāng)對象實(shí)例數(shù)據(jù)部分沒有對齊時(shí)诗箍,就需要通過對齊填充來補(bǔ)全癣籽。


hotSpot虛擬機(jī)中的markword結(jié)構(gòu)

????重量級鎖就是sychronized的對象鎖,鎖標(biāo)識為10滤祖,其中指針指向的是monitor對象的起始地址才避。每個對象都存在著一個monitor與之關(guān)聯(lián),對象與其monitor之間的關(guān)系有存在多重實(shí)現(xiàn)方式氨距,如monitor可以與對象一起創(chuàng)建銷毀或線程試圖獲取對象鎖時(shí)自動生成桑逝,但當(dāng)一個monitor被某個線程持有后,它便處于鎖定狀態(tài)俏让。

? ? 在java虛擬機(jī)中(hotSpot)楞遏,monitor是由ObjectMonitor實(shí)現(xiàn)的茬暇;


ObjectMonitor對象

? ? ObjectMonitor中有兩個隊(duì)列,_WaitSet和_EntryList寡喝,用來保存ObjectWaiter列表糙俗,每個等待鎖的線程都會封裝成ObjectWaiter對象,_owner指向持有ObjectMonitor對象的線程预鬓,當(dāng)多個線程同時(shí)訪問同一段同步代碼時(shí)巧骚,首先會進(jìn)入_EntryList集合,當(dāng)線程獲取到對象的monitor后進(jìn)入_Owner區(qū)域并把monitor中的_owner變量設(shè)置為當(dāng)前線程格二,同時(shí)monitor的計(jì)數(shù)器_count加1劈彪,若先寫調(diào)用wait()方法,將釋放當(dāng)前持有的monitor,_owner變量恢復(fù)為null顶猜,count自減1沧奴,同時(shí)該線程進(jìn)入_waitSet集合等待被喚醒。若當(dāng)前線程執(zhí)行完畢也將釋放monitor长窄,并復(fù)位變量的值滔吠,以便于其他線程獲取monitor鎖。


監(jiān)視器

? ? monitor對象存在每個java對象的對象頭中(存儲的指針的指向),synchronized鎖便是用過這種方式獲取鎖的挠日,這也是為什么java的任意對象都可以作為鎖的原因疮绷,同時(shí)也是notify/notifyAll/wait方法存在object方法中的原因。

同步方法的實(shí)現(xiàn)原理


同步方法

同步代碼塊的實(shí)現(xiàn)原理


同步代碼塊

? ? 同步代碼塊是使用monitorenter和moniterexist指令實(shí)現(xiàn)的嚣潜,會在同步塊的區(qū)域通過監(jiān)聽器對象去獲取鎖和釋放鎖冬骚。

? ? 同步方法和靜態(tài)同步方法是依賴在方法修飾符ACC_SYNCHRONIZED實(shí)現(xiàn),當(dāng)方法調(diào)用時(shí)郑原,調(diào)用指令將會檢查方法的ACC_SYNCHRONIZED訪問標(biāo)志是否被設(shè)置,如果設(shè)置了夜涕,執(zhí)行時(shí)將先獲取monitor犯犁,獲取成功夠才能執(zhí)行方法體,方法執(zhí)行完成后再釋放monitor女器,在方法執(zhí)行期間酸役,其他任何線程都無法在獲得同一個monitor對象。

四驾胆、多線程面試

1涣澡、雙重校驗(yàn)鎖的單例模式


單例模式

? ? volatile修飾singleton很有必要,voliatile防止了指令重排丧诺,singleton =new Singleton();其實(shí)分為了三步:

? ? 1.為singleton分配空間入桂;2.初始化singleton;3.將singleton指向分配的內(nèi)存地址驳阎;

? ? 由于jvm有指令重排的特性抗愁,執(zhí)行順序可能變成1->3->2馁蒂,指令重排在單線程下可能沒有問題,但是在多線程下可能會導(dǎo)致一個線程獲得還沒有初始化的實(shí)例蜘腌。

2沫屡、JDK1.6后的sychronized關(guān)鍵字底層做了哪些優(yōu)化?

? ? 引入了偏向鎖撮珠、輕量級鎖沮脖、自旋鎖、適應(yīng)性自旋鎖芯急、鎖消除勺届、鎖粗化等技術(shù)減少所操作的開銷。

? ? 鎖主要存在四種狀態(tài)志于,無鎖狀態(tài)涮因,偏向鎖狀態(tài),輕量級鎖狀態(tài)伺绽,重量級鎖狀態(tài)养泡,鎖可以升級不能降級,這種策略是為了提高獲得鎖和釋放鎖的效率奈应。

3澜掩、sychronized和ReenTrantLock的區(qū)別

? ? 兩者都是可重入鎖:自己可以再次獲取自己的內(nèi)部鎖,此時(shí)鎖的計(jì)數(shù)器count加1就行杖挣,多以要等到鎖的計(jì)數(shù)器降為0才能釋放鎖肩榕。

? ? sychronized依賴于jvm底層,ReenTrantLock依賴于API惩妇。

? ? ReenTrantLock比sychronized增加了一些高級功能:等待可中斷株汉,可實(shí)現(xiàn)公平鎖,可實(shí)現(xiàn)選擇性通知:

? ? (1)ReenTrantLock使用lock.lockInterruptibly()來實(shí)現(xiàn)等待可中斷功能歌殃,也就是說正在等待的線程可以選擇放棄等待乔妈;

? ? (2)ReenTrantLock 可以指定公平鎖還是非公平鎖,而sychronized只能是非公平鎖氓皱,公平鎖就是先等待的線程先獲得鎖路召;實(shí)現(xiàn)方式是在ReentrantLock(boolean fair)構(gòu)造方法來制定是否是公平的。

? ? (3)sychronized和wait(),notify(),notifyAll()方法結(jié)合可以實(shí)現(xiàn)等待通知機(jī)制波材,ReenTrantLock類也可以實(shí)現(xiàn)股淡,需要使用Condition接口和newCondition()方法。Condition具有很好的靈活性廷区,可以在一個Lock對象中可以創(chuàng)建多個Condition實(shí)例(對象監(jiān)視器),線程對象可以注冊在指定的Condition中唯灵,從而可以選擇性的進(jìn)行線程通知,在調(diào)度線程上更加靈活隙轻。在使用notify()/notifyAll()方法進(jìn)行通知時(shí)早敬,被通知的線程是由JVM選擇的忌傻,用ReenTrantLock類結(jié)合Condition實(shí)例可以實(shí)現(xiàn)選擇性通知。而sychronized關(guān)鍵字就相當(dāng)于整個Lock對象中只有一個Condition搞监,多有的線程都注冊在它一個身上水孩。如果執(zhí)行notifyAll()放的話就會通知所有處于等待狀態(tài)的線程,而Condition的singalAll()方法只會喚醒注冊在該Condition實(shí)例中的所有等待對象琐驴。

? ? 性能上已經(jīng)不是選擇標(biāo)準(zhǔn):在高并發(fā)下俘种,ReenTrantLock的效率比sychronized的效率高一些;

3绝淡、volatile關(guān)鍵字

? ? 在現(xiàn)在的java模型下宙刘,線程可以把變量保存在本地內(nèi)存(比如寄存器)中,而不是直接在主內(nèi)存中進(jìn)行讀寫牢酵,這就可能造成一個線程在主內(nèi)存中修改了一個變量的值悬包,而另外一個線程還繼續(xù)使用它在寄存器中的變量的拷貝,造成數(shù)據(jù)不一致馍乙。


? ? 這個問題可以用volatile關(guān)鍵字解決布近,將變量聲明為volatile,這就指示JVM這個變量不穩(wěn)定丝格,每次使用它都去主內(nèi)存讀取撑瞧。

? ? volatile關(guān)鍵字就是保證變量的可見性和防止指令的重排序。

4显蝌、sychronized和volatile的區(qū)別

? ? sychronized關(guān)鍵字可以修飾方法预伺,變量和代碼塊定拟,而volatile只能修飾變量首启;

????volatile是sychronized的輕量級實(shí)現(xiàn)尘分,所以性能比sychronized好咕村;但是JDK1.6后優(yōu)化了鎖,sychronized性能得到了提升懒鉴,在實(shí)際任務(wù)中使用sychronized的時(shí)候更加多一些徘跪。

? ? 多線程訪問volatile變量不會發(fā)生阻塞讳推,而訪問sychronized關(guān)鍵字會方式阻塞艾船。

? ? volatile關(guān)鍵字能保證數(shù)據(jù)的可見性葵腹,但是不能保證數(shù)據(jù)的原子性高每,sychronized保證了可見性和原子性屿岂。

? ? volatile主要保證變量在線程間的可見性,而sychronized主要保證數(shù)據(jù)在多線程間的的同步性鲸匿。

5爷怀、線程池

? ? 線程池提供了一種限制和管理資源,每個線程池還維護(hù)了一些基本統(tǒng)計(jì)信息带欢,比如線程的數(shù)量运授。

? ? 線程池的優(yōu)點(diǎn):

? ? 降低資源消耗烤惊,通過重復(fù)利用已創(chuàng)建的線程降低線程的創(chuàng)建和銷毀的消耗。

? ? 提高響應(yīng)速度:當(dāng)任務(wù)到達(dá)時(shí)吁朦,不需要等到創(chuàng)建線程就可以立即執(zhí)行柒室。

? ? 提高線程的可管理性,線程是稀缺資源逗宜,如果無限制的創(chuàng)建雄右,不僅會消耗系統(tǒng)資源,還會降低系統(tǒng)的穩(wěn)定性纺讲,使用線程池可以進(jìn)行統(tǒng)一的分配擂仍,調(diào)優(yōu)和監(jiān)控。

6熬甚、實(shí)現(xiàn)Runnable和Callable接口的區(qū)別

? ? 如果想讓線程池執(zhí)行任務(wù)的話需要實(shí)現(xiàn)Runnable或者Callable接口逢渔,兩個接口都可以被ThreadPoolExcutor和ScheduledPoolExcutor執(zhí)行。但是Runnable接口不會返回結(jié)果乡括,而Callable接口可以返回結(jié)果肃廓。

????工具類Executors可以實(shí)現(xiàn)Runnable對象和Callable對象之間的相互轉(zhuǎn)換。(Executors.callable(Runnable task)或Executors.callable(Runnable task粟判,Object resule))亿昏。

7、執(zhí)行execute()方法和submit()方法的區(qū)別

? ? execute()方法用于提交不需要返回值的任務(wù)档礁,所以午飯判斷任務(wù)是否被線程池執(zhí)行成功與否角钩;

? ? submit()方法用于提交需要返回值的任務(wù),線程池會返回一個future類型的對象呻澜,通過這個對象來判斷任務(wù)是否執(zhí)行成功递礼。并且可以通過future的get()方法來獲取返回值,get()方法會阻塞當(dāng)前線程直到任務(wù)完成羹幸,而使用get(long timeout脊髓,TimeUnit unit)方法則會阻塞當(dāng)前線程一段時(shí)間后立即返回,這時(shí)候有可能任務(wù)沒有執(zhí)行完栅受。

8将硝、創(chuàng)建線程池

? ? 一般不建議使用Excutors去創(chuàng)建,而是通過ThreadPoolExcutor的方式屏镊,這樣的處理方式更加明確線程池的運(yùn)行規(guī)則依疼,規(guī)避資源耗盡的風(fēng)險(xiǎn)。



ThreadPoolExcutorsAPI說明

一般通過構(gòu)造方法可以創(chuàng)建


構(gòu)造方法創(chuàng)建

使用Excutors返回線程池對象存在問題:

FixThreadPool和SingleThreadExutor:允許請求的隊(duì)列長度為Integer.MAX_VALUE而芥,可能堆積的請求過多律罢,導(dǎo)致OOM,

CachedThreadPool和ScheduledThreadPool:允許創(chuàng)建的現(xiàn)場數(shù)量為Integer.MAX_VALUE,可能導(dǎo)致大量的線程被創(chuàng)建棍丐,導(dǎo)致OOM误辑。

通過Executor的工具類Excutors實(shí)現(xiàn):


使用工具類創(chuàng)建

9沧踏、Atomic原子類

? ? Atomic是指一個操作不可中斷,一旦開始巾钉,就不會被其他線程干擾翘狱。Atomic原子類就是具有原子/原子操作特性的類。

? ? 并發(fā)包java.util.concurrent的原子類都存放在java.util.concurrent.atomic下:


原子類

? ? 主要分為四類:

? ? 基本類型:AtomicBoolean砰苍,AtomicInteger盒蟆,AtomicLong

? ? 數(shù)組類型:AtomicIntegerArray,AtomicLongArray师骗,AtomicReferenceArray

? ? 引用類型:AtomicReference历等,AtomicStampedRerence,AtomicMarkableReference?

? ? 對象屬性修改類型:AtomicIntegerFieldUpdater辟癌,AtomicLongFieldUpdater寒屯,AtomicLongFieldUpdater

? ? AtomicInteger的方法:


AtomicInteger API

? ? AtomicInteger類主要是利用CAS +volatile和native方法來保證原子操作,從而避免sychronized的高開銷黍少,執(zhí)行效率大為提升寡夹。


atomicInteger源碼

????CAS的原理是拿期望的值和原本的一個值作比較,如果相同則更新成新的值厂置。UnSafe 類的 objectFieldOffset() 方法是一個本地方法菩掏,這個方法是用來拿到“原來的值”的內(nèi)存地址,返回值是 valueOffset昵济。另外 value 是一個volatile變量智绸,在內(nèi)存中可見,因此 JVM 可以保證任何時(shí)刻任何線程總能拿到該變量的最新值访忿。

10瞧栗、使用CAS實(shí)現(xiàn)單例模式


cas實(shí)現(xiàn)單例模式

? ? 這個實(shí)現(xiàn)里面有一個循環(huán),是基于忙等待的算法海铆,依賴底層硬件的實(shí)現(xiàn)迹恐,相當(dāng)于鎖它沒有線程切換和阻塞額外消耗,可以支持較大的并行度卧斟。

? ? CAS的一個重要缺點(diǎn)是殴边,如果忙等待一直執(zhí)行不成功,會對CPU造成較大的執(zhí)行開銷珍语。如果多個線程同時(shí)執(zhí)行到singleton = new Singleton()的時(shí)候锤岸,會創(chuàng)建大量的Singleton對象,很可能會造成內(nèi)存溢出廊酣,所以不建議使用這種能耻。

11赏枚、AQS

????AQS是一個用來構(gòu)建鎖和同步器的框架亡驰,使用AQS能簡單且高效地構(gòu)造出應(yīng)用廣泛的大量的同步器晓猛,比如我們提到的ReentrantLock,Semaphore凡辱,其他的諸如ReentrantReadWriteLock戒职,SynchronousQueue,F(xiàn)utureTask等等皆是基于AQS的透乾。當(dāng)然洪燥,我們自己也能利用AQS非常輕松容易地構(gòu)造出符合我們自己需求的同步器。

12乳乌、happen-before規(guī)則

? ? 有些指令是可以重排的捧韵,有些指令是不可以重排的。規(guī)則如下:

? ? 程序順序規(guī)則:一個線程內(nèi)保證語義的串行性汉操,比如第二條語句依賴第一條語句執(zhí)行的結(jié)果再来,那么就不能執(zhí)行第二條再執(zhí)行第一條。

? ? volatile原則:volatile防止了指令重排磷瘤,volatile變量的寫先于讀芒篷,這保證了volatile變量的可見性。

? ? 鎖規(guī)則:先解鎖采缚,后續(xù)步驟再加鎖针炉,加鎖不能重排到解鎖之前,這樣加鎖行為無法獲得多扳抽。

? ? 傳遞性:A先于B篡帕,B先于C,則A先于C贸呢。

? ? 線程的start()先于它的每個動作赂苗。

? ? 線程的所有操作先于線程的終結(jié)。

? ? 線程的中斷先于中斷線程的代碼贮尉。

? ? 對象的構(gòu)造函數(shù)執(zhí)行拌滋、結(jié)束先于finalize()方法。

13猜谚、ReadWritLock

(1)Java并發(fā)庫中ReetrantReadWriteLock實(shí)現(xiàn)了ReadWriteLock接口并添加了可重入的特性

(2)ReetrantReadWriteLock讀寫鎖的效率明顯高于synchronized關(guān)鍵字

(3)ReetrantReadWriteLock讀寫鎖的實(shí)現(xiàn)中败砂,讀鎖使用共享模式;寫鎖使用獨(dú)占模式魏铅,換句話說昌犹,讀鎖可以在沒有寫鎖的時(shí)候被多個線程同時(shí)持有,寫鎖是獨(dú)占的

(4)ReetrantReadWriteLock讀寫鎖的實(shí)現(xiàn)中览芳,需要注意的斜姥,當(dāng)有讀鎖時(shí),寫鎖就不能獲得;而當(dāng)有寫鎖時(shí)铸敏,除了獲得寫鎖的這個線程可以獲得讀鎖外缚忧,其他線程不能獲得讀鎖

14、線程池的處理流程

(1)判斷線程池里的核心線程是否都在執(zhí)行任務(wù)杈笔,如果有核心線程空閑或者核心線程還沒有創(chuàng)建闪水,則創(chuàng)建一個新的工作線程來執(zhí)行任務(wù);如果核心線程都在執(zhí)行任務(wù)蒙具,則進(jìn)入下個流程球榆。

(2)線程判斷工作隊(duì)列是否已滿,如果工作隊(duì)列沒有滿禁筏,則將新提交的任務(wù)存儲在這個工作隊(duì)列里持钉。如果工作隊(duì)列滿了,則進(jìn)入下一個流程篱昔。

(3)判斷線程池里的線程是否都處于工作狀態(tài)右钾,如果沒有,則創(chuàng)建一個新的工作線程來執(zhí)行任務(wù)旱爆,如果滿了舀射,則交給飽和策略來處理這個任務(wù)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末怀伦,一起剝皮案震驚了整個濱河市脆烟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌房待,老刑警劉巖邢羔,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異桑孩,居然都是意外死亡拜鹤,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進(jìn)店門流椒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來敏簿,“玉大人,你說我怎么就攤上這事宣虾」咴#” “怎么了?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵绣硝,是天一觀的道長蜻势。 經(jīng)常有香客問我,道長鹉胖,這世上最難降的妖魔是什么握玛? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任够傍,我火速辦了婚禮,結(jié)果婚禮上挠铲,老公的妹妹穿的比我還像新娘冕屯。我一直安慰自己,他們只是感情好市殷,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著刹衫,像睡著了一般醋寝。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上带迟,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天音羞,我揣著相機(jī)與錄音,去河邊找鬼仓犬。 笑死嗅绰,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的搀继。 我是一名探鬼主播窘面,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼叽躯!你這毒婦竟也來了财边?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤点骑,失蹤者是張志新(化名)和其女友劉穎酣难,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體黑滴,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡憨募,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了袁辈。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片菜谣。...
    茶點(diǎn)故事閱讀 38,650評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖晚缩,靈堂內(nèi)的尸體忽然破棺而出葛菇,到底是詐尸還是另有隱情,我是刑警寧澤橡羞,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布眯停,位于F島的核電站,受9級特大地震影響卿泽,放射性物質(zhì)發(fā)生泄漏莺债。R本人自食惡果不足惜滋觉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望齐邦。 院中可真熱鬧椎侠,春花似錦、人聲如沸措拇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽丐吓。三九已至浅悉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間券犁,已是汗流浹背术健。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留粘衬,地道東北人荞估。 一個月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像稚新,于是被迫代替她去往敵國和親勘伺。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評論 2 349