Java高并發(fā)編程:取消和關(guān)閉

Java沒有提供任何機(jī)制來安全地終止線程,但是它提供了中斷(Interruption).這是一種協(xié)作機(jī)制厂抖,能夠使一個(gè)線程終止另一個(gè)線程當(dāng)前的工作。

在對一個(gè)線程對象調(diào)用Thread.interrupted()方法之后,一般情況下對這個(gè)線程不會產(chǎn)生任何影響。因?yàn)檎{(diào)用Thread.interrupted()方法只是將增線程的中斷標(biāo)志位設(shè)置為true强挫。

如果一個(gè)線程被調(diào)用Thread.interrupted()方法之后,如果它的狀態(tài)是阻塞狀態(tài)或者是等待狀態(tài)薛躬,而且這個(gè)狀態(tài)正是因?yàn)檎趫?zhí)行的wait俯渤、join、sleep線程造成的型宝,那么是會改變運(yùn)行的結(jié)果(拋出InterruptException異常)

1.線程終止

由于Java沒有提供任何機(jī)制來安全地終止線程,那么我們應(yīng)該如何終止線程呢八匠?下面我們提供三種線程終止的方法:

使用退出標(biāo)志,使線程正常退出趴酣,也就是當(dāng)run方法完成后線程終止梨树。

使用stop方法強(qiáng)行終止線程(這個(gè)方法不推薦使用,因?yàn)閟top和suspend岖寞、resume一樣抡四,也可能發(fā)生不可預(yù)料的結(jié)果)。

使用interrupt方法中斷線程慎璧。

1.1 使用退出標(biāo)志

當(dāng)run方法執(zhí)行完后床嫌,線程就會退出。但有時(shí)run方法是永遠(yuǎn)不會結(jié)束的胸私。如在服務(wù)端程序中使用線程進(jìn)行監(jiān)聽客戶端請求厌处,或是其他的需要循環(huán)處理的任務(wù)。在這種情況下岁疼,一般是將這些任務(wù)放在一個(gè)循環(huán)中卓嫂,如while循環(huán)。如果想讓循環(huán)永遠(yuǎn)運(yùn)行下去唧取,可以使用while(true){……}來處理平酿。但要想使while循環(huán)在某一特定條件下退出可款,最直接的方法就是設(shè)一個(gè)boolean類型的標(biāo)志,并通過設(shè)置這個(gè)標(biāo)志為true或false來控制while循環(huán)是否退出。

public class ThreadFlag implements Runnable{

? ? private volatile boolean exit=false;

? ? @Override

? ? public void run() {

? ? ? ? while (!exit){

? ? ? ? ? ? ///do something

? ? ? ? ? ? try {

? ? ? ? ? ? ? ? Thread.sleep(500);

? ? ? ? ? ? } catch (InterruptedException e) {

? ? ? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? System.out.println("-----------ThreadFlag shutdown----------");

? ? }

? ? public static void main(String[] args) throws InterruptedException {

? ? ? ? ThreadFlag threadFlag=new ThreadFlag();

? ? ? ? Thread thread=new Thread(threadFlag);

? ? ? ? thread.start();

? ? ? ? Thread.sleep(3000);

? ? ? ? threadFlag.exit=true;

? ? ? ? thread.join();

? ? ? ? System.out.println("線程退出");

? ? }

}


上面代碼使用了一個(gè)線程標(biāo)志位來判斷線程是否關(guān)閉.通過對線程標(biāo)志位進(jìn)行操作來決定線程是否關(guān)閉.

1.2 使用stop方法終止線程

使用stop方法可以強(qiáng)行終止正在運(yùn)行或掛起的線程。我們可以使用如下的代碼來終止線程:

public class ThreadStop implements Runnable {

? ? @Override

? ? public void run() {

? ? ? ? try {

? ? ? ? ? ? while (true){

? ? ? ? ? ? ? ? try {

? ? ? ? ? ? ? ? ? ? Thread.sleep(500);

? ? ? ? ? ? ? ? } catch (InterruptedException e) {

? ? ? ? ? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? } finally {

? ? ? ? ? ? System.out.println("-----------ThreadStop shutdown----------");

? ? ? ? }

? ? }

? ? public static void main(String[] args) throws InterruptedException {

? ? ? ? ThreadStop threadStop=new ThreadStop();

? ? ? ? Thread thread=new Thread(threadStop);

? ? ? ? thread.start();

? ? ? ? Thread.sleep(3000);

? ? ? ? thread.stop();

? ? ? ? System.out.println("線程退出");

? ? }

}


這種方法線程不安全崇渗,Java不建議使用這種stop方法關(guān)閉線程。

1.3 使用interrupt方法終止線程

使用interrupt方法來終端線程可分為兩種情況:

(1)線程處于阻塞狀態(tài)京郑,如使用了sleep方法宅广。

(2)使用while(!isInterrupted()){……}來判斷線程是否被中斷些举。

enum? FuntuionType{

? ? FunctionType1,

? ? FunctionType2,

}

public class ThreadInterrupt implements Runnable{

? ? private FuntuionType funtuionType;

? ? public ThreadInterrupt(FuntuionType funtuionType) {

? ? ? ? this.funtuionType = funtuionType;

? ? }

? ? @Override

? ? public void run() {

? ? ? ? switch (funtuionType){

? ? ? ? ? ? case FunctionType1:

? ? ? ? ? ? ? ? int i = 0;

? ? ? ? ? ? ? ? while (!Thread.interrupted()){

? ? ? ? ? ? ? ? ? ? //do something

? ? ? ? ? ? ? ? ? ? i++;

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? System.out.println("Thread.interrupted() shutdown");

? ? ? ? ? ? ? ? break;

? ? ? ? ? ? case FunctionType2:

? ? ? ? ? ? ? ? try {

? ? ? ? ? ? ? ? ? ? Thread.sleep(50*1000);

? ? ? ? ? ? ? ? } catch (InterruptedException e) {

? ? ? ? ? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? System.out.println("Sleep InterruptedException throws");

? ? ? ? ? ? ? ? break;

? ? ? ? ? ? default:

? ? ? ? ? ? ? ? break;

? ? ? ? }

? ? }

? ? public static void main(String[] args) throws InterruptedException {

? ? ? ? ThreadInterrupt threadInterrupt=new ThreadInterrupt(FuntuionType.FunctionType2);

? ? ? ? Thread thread=new Thread(threadInterrupt);

? ? ? ? thread.start();

? ? ? ? Thread.sleep(2000);

? ? ? ? thread.interrupt();

? ? ? ? System.out.println("線程已經(jīng)退出");

? ? }

}


2. 任務(wù)取消

Java中沒有一種安全的搶占式方法來停止線程跟狱,因此就沒有安全的搶占式方法來停止任務(wù)。下面我們就來介紹一中協(xié)作式的方式來取消一個(gè)任務(wù)户魏。

2.1 取消標(biāo)志位

第一種方式就是設(shè)置某個(gè)“已請求取消”的標(biāo)志位驶臊,而任務(wù)周期性的查看這個(gè)標(biāo)志位。如果設(shè)置了這個(gè)標(biāo)志位叼丑,那么任務(wù)就提前結(jié)束关翎。

public class PrimeGenerator implements Runnable{

? ? private final List<BigInteger> primes=new ArrayList<>();

? ? private volatile boolean cancelled = false;

? ? private volatile BigInteger p = BigInteger.ONE;

? ? @Override

? ? public void run() {

? ? ? ? while (!cancelled){

? ? ? ? ? ? //此方法返回一個(gè)整數(shù)大于該BigInteger的素?cái)?shù)。

? ? ? ? ? ? p = p.nextProbablePrime();

? ? ? ? ? ? synchronized (this) {

? ? ? ? ? ? ? ? primes.add(p);

? ? ? ? ? ? }

? ? ? ? }

? ? }

? ? public void cancel(){

? ? ? ? this.cancelled=true;

? ? }

? ? public synchronized List<BigInteger> get(){

? ? ? ? return new ArrayList<>(primes);

? ? }

? ? public static void main(String[] args) throws InterruptedException {

? ? ? ? PrimeGenerator primeGenerator=new PrimeGenerator();

? ? ? ? for (int i = 0; i < 10; i++) {

? ? ? ? ? ? Thread thread=new Thread(primeGenerator);

? ? ? ? ? ? thread.start();

? ? ? ? }

? ? ? ? Thread.sleep(2000);

? ? ? ? primeGenerator.cancel();

? ? ? ? for (BigInteger bigInteger : primeGenerator.get()) {

? ? ? ? ? ? System.out.println(bigInteger);

? ? ? ? }

? ? }

}


2.2 中斷 Interrupt

由于PrimeGenerator中的取消機(jī)制最終會使得素?cái)?shù)的任務(wù)進(jìn)行退出幢码。但是如果使用這個(gè)方法中的任務(wù)調(diào)用了一個(gè)阻塞方法笤休,列如BlockingQueue.put,那么就會產(chǎn)生一個(gè)嚴(yán)重的問題————任務(wù)可能永遠(yuǎn)不會檢查取消標(biāo)志症副。因此永遠(yuǎn)不會結(jié)束。所以這個(gè)時(shí)候我們就采用中斷Interrupt來取消任務(wù)政基。

public class PrimeProducer implements Runnable {

? ? private final BlockingQueue<BigInteger> bigIntegers;

? ? private Thread thread;

? ? public void setThread(Thread thread) {

? ? ? ? this.thread = thread;

? ? }

? ? public PrimeProducer(BlockingQueue<BigInteger> bigIntegers) {

? ? ? ? this.bigIntegers = bigIntegers;

? ? }

? ? private volatile BigInteger p = BigInteger.ONE;

? ? @Override

? ? public void run() {

? ? ? ? try {

? ? ? ? ? ? while (!Thread.currentThread().isInterrupted()){

? ? ? ? ? ? ? ? p = p.nextProbablePrime();

? ? ? ? ? ? ? ? bigIntegers.put(p.nextProbablePrime());

? ? ? ? ? ? }

? ? ? ? } catch (InterruptedException e) {

? ? ? ? ? ? e.printStackTrace();

? ? ? ? }

? ? }

? ? public void cancel(){

? ? ? ? thread.interrupt();

? ? }

? ? public BlockingQueue<BigInteger> getBigIntegers() {

? ? ? ? return bigIntegers;

? ? }

? ? public static void main(String[] args) throws InterruptedException {

? ? ? ? BlockingQueue<BigInteger> bigIntegers=new LinkedBlockingQueue<>();

? ? ? ? PrimeProducer primeProducer=new PrimeProducer(bigIntegers);

? ? ? ? Thread thread=new Thread(primeProducer);

? ? ? ? primeProducer.setThread(thread);

? ? ? ? thread.start();


? ? ? ? Thread.sleep(1000);

? ? ? ? primeProducer.cancel();

? ? ? ? for (BigInteger bigInteger : primeProducer.getBigIntegers()) {

? ? ? ? ? ? System.out.println(bigInteger);

? ? ? ? }

? ? }

}


每個(gè)線程都有一個(gè)Boolean類型的中斷狀態(tài)贞铣。當(dāng)中斷線程發(fā)生的時(shí)候,這個(gè)線程就把這個(gè)中斷狀態(tài)設(shè)置為true沮明。咋Thread中包含了中斷線程以及查詢線程中斷狀態(tài)的方法辕坝。

Thrad中的中斷方法:

public class Thread{

? ? public void interrupt(){}

? ? public boolean isInterrupted(){}

? ? public static boolean interrupted(){}

}


interrupt()方法能夠中斷目標(biāo)線程

isInterrupted方法能夠返回目標(biāo)線程的中斷狀態(tài)

interrupted靜態(tài)方法能夠?qū)⑶宄?dāng)前線程的中斷狀態(tài),并返回它之前的值荐健,這也是清除中斷狀態(tài)的唯一方法

阻塞庫方法酱畅,比如Thread.sleep和Object.wait和Thread.join等,都會檢查線程何時(shí)中斷江场,并且在發(fā)生中斷時(shí)提前返回纺酸。他們在響應(yīng)中斷時(shí)只需的操作包括:清除中斷狀態(tài),拋出InterruptExecption異常址否,表示阻塞操作由于中斷而提前結(jié)束餐蔬。

當(dāng)線程在非阻塞狀態(tài)下中斷時(shí),它的中斷狀態(tài)將被設(shè)置為true,然后根據(jù)將取消的操作來檢查中斷狀態(tài)以判斷發(fā)生了中斷樊诺。通過這樣的方法仗考,中斷操作將變得有粘性————如果不觸發(fā)InterruptException,那么中斷將一直保持词爬,直到明確的清除中斷狀態(tài)秃嗜。

總結(jié):

對中斷的正確理解是:它并不會真正地中斷在一個(gè)正在運(yùn)行的線程,而是發(fā)出中斷請求顿膨,然后由線程在下一個(gè)合適的時(shí)刻中斷自己锅锨。(這些合適的時(shí)刻稱為取消點(diǎn))。有些方法虽惭,比如wait橡类、slee和join等,將嚴(yán)格處理這種請求芽唇,當(dāng)他們收到中斷請求或者開始執(zhí)行發(fā)現(xiàn)某個(gè)已經(jīng)被設(shè)置好的中斷狀態(tài)的時(shí)候顾画,將拋出一個(gè)異常。

中斷策略

最合理的中斷策略使某

種線程級(Thread-Level)取消操作或者服務(wù)級的取消操作:盡快退出匆笤,在必要時(shí)候進(jìn)行清理研侣,通知某個(gè)所有線程已經(jīng)退出。當(dāng)前檢查到中斷請求時(shí)候炮捧,任務(wù)不需要放棄所有的操作————它可以推遲處理中斷請求庶诡,并找到合適的時(shí)刻。因此需要記住中斷請求咆课,并在完成當(dāng)前任務(wù)之后拋出InterruptExeception或者表示已經(jīng)收到中斷請求末誓。這項(xiàng)技術(shù)能夠確保在更新過程中發(fā)生中斷時(shí),數(shù)據(jù)結(jié)構(gòu)不會發(fā)生破壞书蚪。除了將InterruptException傳遞給調(diào)用者外還需要執(zhí)行額外的操作喇澡,那么應(yīng)該在捕獲InterruptException之后恢復(fù)中斷狀態(tài):

Thread.currentThread().interrupt();

1

響應(yīng)中斷

當(dāng)中斷異常發(fā)生的時(shí)候,我們有兩種方式進(jìn)行響應(yīng)中斷請求:

傳遞異常(可能在執(zhí)行某個(gè)特定于任務(wù)的清除操作之后):從而使你的方法也可以是中斷的阻塞方法

恢復(fù)中斷狀態(tài):從而使調(diào)用占中的上層代碼能對其進(jìn)行處理殊校。如果不想處理中斷請求晴玖,一種標(biāo)準(zhǔn)的方法就是通過再次調(diào)用interrupt來恢復(fù)中斷狀態(tài)。你不能屏蔽中斷狀態(tài)为流,你只能恢復(fù)中斷狀態(tài)呕屎。

2.3 通過Future來實(shí)現(xiàn)取消

我們已經(jīng)使用了一種抽象機(jī)制來管理任務(wù)的生命周期,處理異常敬察,下面我們來介紹一種使用Future類來實(shí)現(xiàn)任務(wù)取消秀睛。

public class TimeRun {

? ? private static ExecutorService executorService= Executors.newFixedThreadPool(5);


? ? public static void timeRun(Runnable runnable, long timeout, TimeUnit timeUnit){

? ? ? ? Future<?> submit = executorService.submit(runnable);

? ? ? ? try {

? ? ? ? ? ? submit.get(timeout,timeUnit);

? ? ? ? } catch (InterruptedException e) {

? ? ? ? ? ? e.printStackTrace();

? ? ? ? } catch (ExecutionException e) {

? ? ? ? ? ? e.printStackTrace();

? ? ? ? } catch (TimeoutException e) {

? ? ? ? ? ? //接下來任務(wù)將被取消

? ? ? ? ? ? e.printStackTrace();

? ? ? ? } finally {

? ? ? ? ? ? //如果任務(wù)已經(jīng)結(jié)束,那么執(zhí)行取消操作也不會帶來任何影響

? ? ? ? ? ? //如果任務(wù)正在運(yùn)行静汤,那么將會被中斷

? ? ? ? ? ? submit.cancel(true);

? ? ? ? }

? ? }

}


當(dāng)Future.get拋出InterruptException或者TimeoutException時(shí)琅催,如果你知道不再需要結(jié)果居凶,那么就可以調(diào)用Future.cancel來取消任務(wù)。

2.4 處理不可中斷的阻塞

如果一個(gè)線程由于執(zhí)行同步的Socket I/O 或者等待獲得內(nèi)置鎖而阻塞藤抡,那么中斷請求只能設(shè)置線程的中斷狀態(tài)侠碧,除此之外沒有其他任何作用。對于那些由于執(zhí)行不可中斷操作而被阻塞的線程缠黍,可以使用類似于中斷的手段來停止這些線程弄兜。

public class ReaderThread extends Thread {

? ? private final Socket socket;

? ? private final InputStream inputStream;

? ? public static final int BUFSIZE=1024;


? ? public ReaderThread(Socket socket) throws IOException {

? ? ? ? this.socket = socket;

? ? ? ? this.inputStream=socket.getInputStream();

? ? }

? ? @Override

? ? public void interrupt() {

? ? ? ? try {

? ? ? ? ? ? socket.close();

? ? ? ? } catch (IOException e) {

? ? ? ? ? ? e.printStackTrace();

? ? ? ? }finally {

? ? ? ? ? ? super.interrupt();

? ? ? ? }

? ? }

? ? @Override

? ? public void run() {

? ? ? ? byte [] buf=new byte[BUFSIZE];

? ? ? ? try {

? ? ? ? ? ? while (true) {

? ? ? ? ? ? ? ? int count= inputStream.read(buf);

? ? ? ? ? ? ? ? //dosomething

? ? ? ? ? ? }

? ? ? ? } catch (IOException e) {

? ? ? ? ? ? e.printStackTrace();

? ? ? ? }

? ? }

}


通過重寫Interrupt方法將非標(biāo)準(zhǔn)的取消操作封裝到Thread中,實(shí)現(xiàn)中斷功能

3. 停止線程的服務(wù)

正確的封裝原則是:除非擁有某個(gè)線程瓷式,否則不能對線程進(jìn)行操作替饿。比如,中斷線程贸典,或者修改線程的優(yōu)先級等等视卢。

服務(wù)應(yīng)該提供生命周期方法(Lifecycle Method)來關(guān)閉它自己以及它所擁有的線程。這樣應(yīng)用程序關(guān)閉服務(wù)的時(shí)候廊驼,服務(wù)就可以關(guān)閉所有線程了据过。對于持有線程的服務(wù),只要服務(wù)的存在時(shí)間大于創(chuàng)建線程的方法的存在時(shí)間妒挎,就應(yīng)該提供生命周期方法绳锅。

3.1 關(guān)閉ExecutorService

關(guān)閉ExecutorService提供了兩種關(guān)閉方法:shutdown和shutdownNow方法

強(qiáng)行關(guān)閉的速度更快,但是風(fēng)險(xiǎn)也更大酝掩,因?yàn)槿蝿?wù)很可能執(zhí)行到一半就結(jié)束

正常關(guān)閉的速度雖然慢鳞芙,但是卻更為安全,因?yàn)镋xecutorService會一直等到隊(duì)列中的所有任務(wù)都執(zhí)行完成之后才關(guān)閉期虾。

4. JVM關(guān)閉

JVM關(guān)閉應(yīng)用程序可以分為兩種方式:

正常關(guān)閉:當(dāng)最后一個(gè)“正常(非守護(hù))”線程結(jié)束的時(shí)候原朝,或者調(diào)用了System.exit(0)時(shí),或者通過其他特定于平臺的方法關(guān)閉(比如發(fā)出了SIGNT信號或者Ctrl-C)

強(qiáng)行關(guān)閉:通過調(diào)用Runtime.halt或者在操作系統(tǒng)中“殺死”JVM進(jìn)程來強(qiáng)行關(guān)閉JVM

4.1 關(guān)閉鉤子

在正常關(guān)閉中镶苞,JVM首先調(diào)用以及注冊的關(guān)閉鉤子(shutdown Hook)竿拆。關(guān)閉鉤子是指通過Runntime.addShutdwonHook注冊的但是尚未開始的線程。JVM不能保證這些線程的執(zhí)行順序宾尚。在關(guān)閉應(yīng)用程序線程時(shí),如果有線程正在運(yùn)行谢澈,那么這些線程接下來將于關(guān)閉進(jìn)程并發(fā)執(zhí)行煌贴。

public class JavaHook {

? ? private static class JavaTask implements Runnable{

? ? ? ? @Override

? ? ? ? public void run() {

? ? ? ? ? ? try {

? ? ? ? ? ? ? ? Thread.sleep(2000);

? ? ? ? ? ? } catch (InterruptedException e) {

? ? ? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? }

? ? ? ? ? ? System.out.println("-----------JavaTask shutdown----------");

? ? ? ? }

? ? }

? ? public static void main(String[] args) {

? ? ? ? JavaTask javaTask=new JavaTask();

? ? ? ? Thread thread=new Thread(javaTask);

? ? ? ? thread.start();

? ? ? ? Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {

? ? ? ? ? ? @Override

? ? ? ? ? ? public void run() {

? ? ? ? ? ? ? ? try {

? ? ? ? ? ? ? ? ? ? Thread.sleep(4000);

? ? ? ? ? ? ? ? } catch (InterruptedException e) {

? ? ? ? ? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? System.out.println("-----------JavaHook finish----------");

? ? ? ? ? ? }

? ? ? ? }));

? ? ? ? System.out.println("JVM finsih....");

? ? }

}


關(guān)閉鉤子應(yīng)該是線程安全的:他們在訪問共享數(shù)據(jù)的時(shí)候必須使用同步機(jī)制,并且小心的避免發(fā)生死鎖锥忿,這與其他并發(fā)代碼的要求相同牛郑。而且關(guān)閉鉤子不應(yīng)該對應(yīng)用程序的狀態(tài)(比如其他服務(wù)是否已經(jīng)關(guān)閉,后者所有的正常線是否已經(jīng)執(zhí)行完成)后者JVm的關(guān)閉原因作出任何假設(shè)敬鬓。

5.總結(jié)

Java并沒有提供某種搶占式的機(jī)制來取消或者終結(jié)線程淹朋。想法它提供一種協(xié)作式的中斷機(jī)制來實(shí)現(xiàn)取消操作笙各,但是這要依賴于如何構(gòu)建取消操作的協(xié)議,以及能否遵循這些協(xié)議础芍。

現(xiàn)在加群:810589193杈抢,點(diǎn)擊鏈接加入群聊【Java架構(gòu)學(xué)習(xí)交流群】:https://jq.qq.com/?_wv=1027&k=5deQUBl獲取Java工程化、高性能及分布式仑性、高性能惶楼、高架構(gòu)、性能調(diào)優(yōu)诊杆、Spring歼捐、MyBatis、Netty源碼分析等多個(gè)知識點(diǎn)高級進(jìn)階干貨的直播免費(fèi)學(xué)習(xí)權(quán)限及相關(guān)視頻資料晨汹,還有spring和虛擬機(jī)等書籍掃描版

合理利用自己每一分每一秒的時(shí)間來學(xué)習(xí)提升自己豹储,不要再用"沒有時(shí)間“來掩飾自己思想上的懶惰!趁年輕淘这,使勁拼剥扣,給未來的自己一個(gè)交代!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末慨灭,一起剝皮案震驚了整個(gè)濱河市朦乏,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌氧骤,老刑警劉巖呻疹,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異筹陵,居然都是意外死亡刽锤,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門朦佩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來并思,“玉大人,你說我怎么就攤上這事语稠∷伪耍” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵仙畦,是天一觀的道長输涕。 經(jīng)常有香客問我,道長慨畸,這世上最難降的妖魔是什么莱坎? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮寸士,結(jié)果婚禮上檐什,老公的妹妹穿的比我還像新娘碴卧。我一直安慰自己,他們只是感情好乃正,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布住册。 她就那樣靜靜地躺著,像睡著了一般烫葬。 火紅的嫁衣襯著肌膚如雪界弧。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天搭综,我揣著相機(jī)與錄音垢箕,去河邊找鬼。 笑死兑巾,一個(gè)胖子當(dāng)著我的面吹牛条获,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蒋歌,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼帅掘,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了堂油?” 一聲冷哼從身側(cè)響起修档,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎府框,沒想到半個(gè)月后吱窝,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡迫靖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年院峡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片系宜。...
    茶點(diǎn)故事閱讀 38,161評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡照激,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出盹牧,到底是詐尸還是另有隱情俩垃,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布汰寓,位于F島的核電站吆寨,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏踩寇。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一六水、第九天 我趴在偏房一處隱蔽的房頂上張望俺孙。 院中可真熱鬧辣卒,春花似錦、人聲如沸睛榄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽场靴。三九已至啡莉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間旨剥,已是汗流浹背咧欣。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留轨帜,地道東北人魄咕。 一個(gè)月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像蚌父,于是被迫代替她去往敵國和親哮兰。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評論 2 344

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