JAVA多線程:狀態(tài)轉(zhuǎn)換以及基本操作

一、CPU、進(jìn)程炊汤、線程

  • CPU
    我們都知道CPU是計(jì)算機(jī)的中央處理器,CPU的主要功能是運(yùn)算弊攘。對CPU的關(guān)注通常都是CPU的核心數(shù)和CPU的線程數(shù)抢腐。而CPU的核心數(shù)代表硬件上存在著幾個核心。而這些核心是相對獨(dú)立的CPU核心單元組襟交。在沒有超線程技術(shù)的時(shí)候氓栈,一個核心只能處理一個線程,而有了超線程技術(shù)后婿着,一個核心可以處理兩個線程授瘦。例如雙核心四線程。就是有兩個CPU核心而每個核心可以處理的線程數(shù)就是兩個竟宋。

  • 進(jìn)程
    進(jìn)程即為程序運(yùn)行的資源分配和調(diào)用的基本單位提完,而進(jìn)程里面是存在多個線程。進(jìn)程中的每個線程都會共享進(jìn)程中的資源丘侠。例如啟動我們的JAVA應(yīng)用就是啟動一個進(jìn)程徒欣,每個請求我們都使用一個線程處理,而每個請求中使用到的全局變量這些就是共享的資源蜗字。

  • 線程
    線程是CPU執(zhí)行的基本單位打肝。線程可以把進(jìn)程的資源分配和執(zhí)行調(diào)度分開,各個線程既可以共享進(jìn)程資源挪捕,又可以獨(dú)立調(diào)度粗梭。而在同一時(shí)間片刻下CPU只能執(zhí)行1個線程。多線程執(zhí)行CPU通過分配給每個線程的執(zhí)行時(shí)間段以達(dá)到多線程計(jì)算级零。這種切換會導(dǎo)致上下文切換断医。而頻繁的上下文切換會影響性能。而至于怎樣影響可以參考《多線程上下文切換》(http://www.reibang.com/p/19fc8aca712c

二奏纪、線程調(diào)度

2.1什么是線程調(diào)度

線程調(diào)度就是系統(tǒng)為線程分配執(zhí)行時(shí)間的過程鉴嗤。

2.2 線程調(diào)度的方式

根據(jù)線程調(diào)度的控制權(quán)是由系統(tǒng)控制或者線程本身來控制劃分為:協(xié)同式的線程調(diào)度和搶占式的線程調(diào)度。
1序调、協(xié)同式線程調(diào)度:線程之間的系統(tǒng)執(zhí)行時(shí)間醉锅,由線程本身進(jìn)行進(jìn)行控制。這種線程調(diào)度方式就像接力賽发绢,一個執(zhí)行完畢后交由下一個接力硬耍。如當(dāng)前線程執(zhí)行完畢后垄琐,通知系統(tǒng)調(diào)度到其他線程執(zhí)行。
(1)協(xié)同的好處:線程的切換是可預(yù)知的默垄。線程之間不存在同步的問題此虑。
(2)協(xié)同的壞處:協(xié)同調(diào)度的致命缺點(diǎn)是當(dāng)某個線程執(zhí)行有問題的時(shí)候甚纲,會導(dǎo)致整個運(yùn)行阻塞和系統(tǒng)崩潰口锭。

2、搶占式線程調(diào)度:線程之間的系統(tǒng)執(zhí)行時(shí)間介杆,是由系統(tǒng)進(jìn)行控制鹃操。而搶占式的線程調(diào)度對線程的不可預(yù)知,系統(tǒng)定期的中斷當(dāng)前正在執(zhí)行的線程春哨,將CPU執(zhí)行權(quán)切換到下一個等待的線程荆隘。所以任何一個線程都不能獨(dú)占CPU。正因?yàn)檫@種定期的線程切換導(dǎo)致線程之間存在不同的問題赴背。當(dāng)線程執(zhí)行過程中椰拒,某個線程出現(xiàn)問題的時(shí)候,由線程對CPU不具有獨(dú)占性凰荚。因此不會造成阻塞燃观。

我們所使用的操作系統(tǒng)都是是用搶占性的線程調(diào)度。如果使用協(xié)同式的線程調(diào)度情況下便瑟,如果我們再使用某個軟件出現(xiàn)問題時(shí)候缆毁,操作系統(tǒng)處于阻塞狀態(tài),導(dǎo)致整個操作系統(tǒng)崩潰到涂,我們肯定會抓狂脊框。

3、JAVA線程調(diào)度
Java線程調(diào)度就是搶占式調(diào)度践啄。

三浇雹、Java線程的實(shí)現(xiàn)方式

JAVA提供了3中創(chuàng)建線程的方式:

  • Thread
    繼承Thread類重寫run方法,這種創(chuàng)建線程的方式在我們的編程中很少使用屿讽。
   private static class TheadExtends extends Thread{
       @Override
       public void run() {
           System.out.println("TheadExtends");
       }
   }
  • Runnable
    既然JAVA提供了Thread創(chuàng)建線程的方式箫爷,為什么還要提供Runnable接口的方式進(jìn)行創(chuàng)建線程?因?yàn)镴AVA是單繼承聂儒,不能多繼承虎锚。因此就有了Runnable接口的方式來進(jìn)行創(chuàng)建線程。
    private static class RunnableImpl implements Runnable{
        @Override
        public void run() {
            System.out.println("RunnableImpl");
        }
    }
  • Callable
    Callable接口與Runnable接口的區(qū)別在于Callable在線程調(diào)用完畢后有返回結(jié)果衩婚,而Runnable沒有窜护,而對于一些業(yè)務(wù)處理比較耗時(shí)并且無需立即返回處理結(jié)果的情況下,我們都會通過asynchronous+Future的方式處理非春,而對于這種業(yè)務(wù)情景我們可以通過Callable進(jìn)行處理柱徙。
public class ThreadImplement {

    private static class CallableImpl implements Callable<String>{

        @Override
        public String call() throws Exception {
            Thread.sleep(2000);
            return "Callable";
        }
    }

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        
        CallableImpl callableImpl=new CallableImpl();
        FutureTask<String> futureTask = new FutureTask<String>(callableImpl);
        Thread  CallableThread= new Thread(futureTask);
        CallableThread.start();
        System.out.println(futureTask.get());
    }
}

四缓屠、JAVA線程狀態(tài)轉(zhuǎn)換

4.1Java線程狀態(tài)轉(zhuǎn)換圖
image.png
4.2Java線程狀態(tài)

JAVA線程狀態(tài)包括:

  • New :新創(chuàng)建一個線程是處于該狀態(tài)。

  • Runnable:線程的調(diào)度是由操作系統(tǒng)可以決定护侮,因此Runnable是包含Ready和Running敌完。當(dāng)我們調(diào)用了start()方法后,當(dāng)前的線程處于一個Ready的狀態(tài)羊初,等待操作系統(tǒng)線程調(diào)用到當(dāng)前線程分配CPU執(zhí)行時(shí)間滨溉,若當(dāng)前線程獲得CPU執(zhí)行時(shí)間時(shí),線程就處于一個Running的狀態(tài)长赞。而在Running狀態(tài)的情況下晦攒,我們可以調(diào)用yield()方法,放棄當(dāng)前線程的CPU執(zhí)行得哆。而調(diào)用yield后當(dāng)前線程處于一個Ready的狀態(tài)脯颜,這種狀態(tài)下操作系統(tǒng)在線程調(diào)度的時(shí)候分配CPU執(zhí)行時(shí)間給當(dāng)前的線程。

  • Blocked:阻塞狀態(tài)下代表著當(dāng)前的線程被掛起贩据。而這掛起的原因的線程在等待一個鎖栋操。如我們在一個方法或者代碼塊中使用Synchronized時(shí),同一時(shí)間有2個線程進(jìn)入該方法的時(shí)候饱亮,先獲取到鎖的線程執(zhí)行矾芙。而沒有獲得鎖的線程就處于這種阻塞狀態(tài)。

  • WAITING:等待狀態(tài)下近尚,當(dāng)前線程不被執(zhí)行和操作系統(tǒng)不會給該線程進(jìn)行線程調(diào)度蠕啄。而當(dāng)前線程處于等待其他線程喚醒。只有被喚醒后戈锻,操作系統(tǒng)才會給該線程進(jìn)行線程調(diào)度歼跟。這種線程的等待的主要作用是為了線程之間的協(xié)作。一般情況下通過Synchronized獲得鎖后格遭,調(diào)用鎖的wait的方法進(jìn)入等待狀態(tài)哈街,而調(diào)用wait方法后,當(dāng)前的線程會釋放鎖拒迅,而另外一個線程獲得鎖后骚秦,通過notifyall()/notify()進(jìn)行喚醒處于等待的線程。

  • TIMED_WAITING:處于這種有限期的等待的情況下璧微,在限期內(nèi)當(dāng)前線程不會被執(zhí)行和操作系統(tǒng)不會給該線程進(jìn)行線程調(diào)度作箍。在限期過后,操作系統(tǒng)才給該線程進(jìn)行線程調(diào)度前硫。

  • TERMINATED:該狀態(tài)下線程處于終止胞得,而這種終止引起的原因分為正常的執(zhí)行完畢的終止和非正常情況下的終止,而非正常情況下可能是線程執(zhí)行異骋俚纾或者調(diào)用interrupt()中止線程引起阶剑。

五跃巡、多線程編程

5.1 多線程編程的好處
  • 充分利用CPU的資源。
  • 加快請求響應(yīng)
  • 異步化
5.2 多線程帶來的問題
  • 設(shè)計(jì)更復(fù)雜
    1.線程之間是共享進(jìn)程資源牧愁,存在資源沖突素邪。
    2.線程之間的協(xié)作往往是非常復(fù)雜。若不能正確的使用鎖的機(jī)制猪半,通常會造成數(shù)據(jù)錯誤兔朦,整個業(yè)務(wù)功能出現(xiàn)問題。
  • 上下文切換的開銷
  • 增加資源消耗办龄,多線程變成是一種空間換時(shí)間的方式烘绽。線程在運(yùn)行的時(shí)候需要從計(jì)算機(jī)里面得到一些資源淋昭。除了CPU俐填,線程還需要一些內(nèi)存來維持它本地的堆棧,若開啟過多的線程時(shí)會導(dǎo)致程序占用過多的內(nèi)存和機(jī)器崩潰翔忽。

七英融、線程基本操作

interrupt
  • JAVA提倡通過協(xié)作的方式結(jié)束線程,而不是使用強(qiáng)制停止的方式進(jìn)行結(jié)束線程如stop()歇式,resume(),suspend()已不建議使用驶悟,stop()會導(dǎo)致線程不會正確釋放資源,suspend()容易導(dǎo)致死鎖材失。那么怎樣協(xié)同的方式結(jié)束線程呢痕鳍?就是同過Thread的interrupt()方法進(jìn)行協(xié)作中斷線程。而調(diào)用interrupt方法是在線程中設(shè)置一個中斷的標(biāo)志位龙巨,中斷標(biāo)志默認(rèn)為fals笼呆。被中斷的線程通過循環(huán)的方式監(jiān)聽這個標(biāo)志位確定當(dāng)前線程需要中斷。
    public static class SafeEndRunnable implements Runnable{

        @Override
        public void run() {
            System.out.println("flag = "+Thread.currentThread().isInterrupted());
            while(!Thread.currentThread().isInterrupted()) {
                System.out.println(Thread.currentThread().getName()+"running");
            }
            System.out.println(Thread.currentThread().getName()+"is end ,flag = "+Thread.currentThread().isInterrupted());
        }
    }

    
    public static void main(String[] args) throws InterruptedException {
        SafeEndRunnable safeEndRunnable = new SafeEndRunnable();
        Thread t1 = new Thread(safeEndRunnable);
        t1.start();
        Thread.sleep(1);
        t1.interrupt();
}
輸出:
flag = false
Thread-0running
Thread-0running
Thread-0running
Thread-0running
Thread-0is end ,flag = true
  • 相關(guān)方法
方法名 方法類型 Demo 描述
isInterrupted 對象方法 Thread.currentThread().isInterrupted() 判斷當(dāng)前線程是否處于中斷狀態(tài)
interrupt 對象方法 Thread.currentThread().interrupt() 設(shè)置標(biāo)志位為true
interrupted 靜態(tài)方法 Thread.interrupted() 判斷當(dāng)前線程是否處于中斷狀態(tài)并且設(shè)置中斷狀態(tài)為false
  • 在進(jìn)行協(xié)作處理線程結(jié)束的時(shí)候清除標(biāo)志位旨别。在我們的被中斷的線程中如果使用到了sleep方法時(shí)诗赌,如果中斷線程調(diào)用時(shí),該線程處于sleep時(shí)秸弛,會拋出InterruptedException铭若,如果使用進(jìn)行try/catch捕捉該異常的時(shí)候會清除標(biāo)志位。所以我們需要再調(diào)用被中斷的線程的 interrupt()方法递览。
public static class SafeEndThread implements Runnable{
        @Override
        public void run() {
            while(!Thread.currentThread().isInterrupted()) {
                System.out.println(Thread.currentThread().getName()+"running");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e){
                    e.printStackTrace();
                    System.out.println("flag = "+Thread.currentThread().isInterrupted());
                    Thread.currentThread().interrupt();
                }
            }
            System.out.println(Thread.currentThread().getName()+"is end ,flag = "+Thread.currentThread().isInterrupted());          
        }
            
    public static void main(String[] args) throws InterruptedException {
        SafeEndThread safeEndThread = new SafeEndThread();
        Thread t2 = new Thread(safeEndThread);
        t2.start(); 
        Thread.sleep(1);
        t2.interrupt();
    }
輸出:
Thread-0running
java.lang.InterruptedException: sleep interrupted
flag = false
Thread-0is end ,flag = true
yield

yield的主要作用的是讓出CPU的執(zhí)行時(shí)間叼屠,需要注意的時(shí)候,調(diào)用yield雖然讓出了CPU的執(zhí)行時(shí)間绞铃,但是會參與下一次的CPU執(zhí)行時(shí)間的競爭中镜雨,如果當(dāng)前線程重新獲得CPU執(zhí)行時(shí)間,那么當(dāng)前的線程再次執(zhí)行憎兽。如下:

public static class ThreadYieldRunnable implements Runnable{

        @Override
        public void run() {
            for (int i = 0; i < 20; i++) {
                System.out.println(Thread.currentThread().getName()+"running"+i);
                Thread.yield();
            }
        }
    }
    
    public static void main(String[] args) {
        ThreadYieldRunnable threadYieldRunnable= new ThreadYieldRunnable();
        Thread t1 = new Thread(threadYieldRunnable);
        t1.start();
        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("t1.yield");
    }

輸出:
Thread-0running0
Thread-0running1
t1.yield
Thread-0running2
Thread-0running3
Thread-0running4
Thread-0running5
Thread-0running6
Thread-0running7
Thread-0running8
Thread-0running9
Thread-0running10
Thread-0running11
Thread-0running12
Thread-0running13
Thread-0running14
Thread-0running15
Thread-0running16
Thread-0running17
Thread-0running18
Thread-0running19

六冷离、線程共享

鎖的主要作用是保護(hù)臨界區(qū)資源吵冒,在多線程訪問臨界區(qū)時(shí)互斥。那么在線程訪問共享的資源時(shí)西剥,JAVA提供了以下保存線程之間的線程共享資源痹栖。

Synchronized
  • Synchronized的實(shí)現(xiàn)方式
方式 鎖對象 Demo
對象同步 當(dāng)前對象 synchronized void demo()
靜態(tài)同步 當(dāng)前類 static synchronized void demo()
代碼塊 當(dāng)前對象、其他對象瞭空、類 Demo demo = new Demo();
synchronized (demo) {}
synchronized (this){}
synchronized(Demo.class) {}
  • Synchronized的綜述
    (1)Synchronized主要作用實(shí)現(xiàn)同步揪阿。而這種同步是通過互斥鎖來保證多線程訪問時(shí)實(shí)現(xiàn)同步。即在同一時(shí)間內(nèi)只有一個線程可以訪問臨界區(qū)的資源咆畏,同時(shí)保證了共享資源的可預(yù)見性和原子性南捂。
    (2)Synchronized的使用:可以在方法定義中使用,也可以使用同步代碼塊的形式使用旧找。在使用Synchronized的時(shí)候溺健,盡量使用代碼塊的形式,將同步的操作控制在最小的粒度中钮蛛。如果使用在Synchronized在方法定義中鞭缭,那么該方法中不存在鎖競爭的部分會被同步。如果該方法高并發(fā)情況下魏颓,可能會導(dǎo)致多線程等待從而引起應(yīng)用dump掉岭辣。

  • Synchronized死鎖
    死鎖引起的原因是由于兩個線程之間,相互持有對象的鎖和相互等待對象釋放鎖甸饱。在使用Synchronized的時(shí)候不允許出現(xiàn)死鎖的情況沦童。

    public static void main(String[] args) {
        Object lock1 = new Object();
        Object lock2 = new Object();
        Thread t1 = new Thread(() -> {
            synchronized (lock1) {
                System.out.println("Thread1 get locke1");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lock2) {
                    System.out.println("Thread1 get locke2");
                }
            }
        });

        Thread t2 = new Thread(() -> {
            synchronized (lock2) {
                System.out.println("Thread2 get locke2");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lock1) {
                    System.out.println("Thread2 get locke1");
                }
            }

        });
        t1.start();
        t2.start();
    }
  • 避免使用常量池對象作為鎖對象
    Java為我們提供了String、Integer叹话、Long常量池偷遗,因此我們再使用這些常量池的對象作為鎖對象的時(shí)候,會存在鎖隱患渣刷。
public class ConstLock implements Runnable {
    private Object  lock ;
    
    public ConstLock(Object lock) {
        super();
        this.lock = lock;
    }

    public void run() {
        synchronized (lock) {
            while(true) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"sayHello");
            }
        }
    }
    
    public static void main(String[] args) {
        ConstLock constLock1 = new ConstLock("lock");
        ConstLock constLock2 = new ConstLock("lock");
        Thread t1 = new Thread(constLock1,"Thread1");
        Thread t2 = new Thread(constLock2,"Thread2");
        t1.start();
        t2.start();
    }
    public static void main(String[] args) {
        ConstLock constLock1 = new ConstLock(21);
        ConstLock constLock2 = new ConstLock(21);
        Thread t1 = new Thread(constLock1,"Thread1");
        Thread t2 = new Thread(constLock2,"Thread2");
        t1.start();
        t2.start();
    }
    
    public static void main(String[] args) {
        ConstLock constLock1 = new ConstLock(21l);
        ConstLock constLock2 = new ConstLock(21l);
        Thread t1 = new Thread(constLock1,"Thread1");
        Thread t2 = new Thread(constLock2,"Thread2");
        t1.start();
        t2.start();
    }

}

打羽兄住:
Thread1sayHello
Thread1sayHello
Thread1sayHello

volatile關(guān)鍵字

volatile是JAVA中提供的一種輕量級的同步機(jī)制。而這種輕量級的同步機(jī)制是通過線程之間的通訊來保證辅柴。而不是通過鎖的機(jī)制進(jìn)行處理箩溃。因此不會對執(zhí)行的線程造成阻塞。

  • 線程通訊過程


    image.png
  • volatile主要作用
    (1)確保了所有的線程對volatile修飾的變量具有可見性碌嘀。
    (2)禁止操作系統(tǒng)指令重排序涣旨,如果變量沒有被volatile表示禁止指令重排優(yōu)化的情況下。操作系統(tǒng)默認(rèn)會對不相關(guān)的執(zhí)行指令進(jìn)行重排序提高執(zhí)行的效率股冗。

public class Reorder {

    public static int x = 0;
    public static int y = 0;
    public static int a = 0;
    public static int b = 0;

    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(()->{
            a = 1;
            x = b;
        }) ;
        Thread thread2 = new Thread(()->{
            b = 1;
            y = a;
        });
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        System.out.println("x=" + x + ";y=" + y);
    }
}

如沒有禁止指令重排序就會出現(xiàn):x=1;y=0霹陡、x=0;y=1、x=1;y=1、x=0;y=0四種結(jié)果烹棉。


image.png
  • volatile原子性
    1攒霹、原子性表示一個操作或者多個操作的情況下,要么全部執(zhí)行成功浆洗,要么全部執(zhí)行失敗催束。
    2、volatile在符合條件以下條件的情況下具有原子性:
    (1)對volatile修飾的變量的操作不依賴變量本身伏社,如i++這種復(fù)合操作不具有原子性抠刺。代碼如下:

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 10000; i++)
                        counter++;
                }
            });
            thread.start();
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(counter);
    }

(2)確保只有一個線程修改變量的值的情況。

  • volatile適用場景
    (1)禁止系統(tǒng)重排序的情況
    (2)只有一個線程寫摘昌,多個線程讀的情況速妖。
ThreadLocal

ThreadLocal是一個線程本地存儲,而每個線程有自己獨(dú)立的副本聪黎。也就是說每個線程可以存放各自變量到線程本地存儲中罕容,并且線程之間各自訪問各自的線程本地存儲。當(dāng)線程結(jié)束后挺举,線程的本地存儲會被垃圾回收杀赢。如果線程本地存儲中的變量被其他引用到的情況下烘跺,是不會被回收湘纵。我們可以把ThreadLocal看作一個Map<Thread,Object>。

static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() {
        protected Integer initialValue() {
            return 1;
        };
    };

    public void startThread() {
        for (int i = 0; i < 2; i++) {
            Thread t1 = new Thread(new ThreadLocalRunnable(i));
            t1.start();
        }

    }

    @Data
    @AllArgsConstructor
    public static class ThreadLocalRunnable implements Runnable {

        private int id;

        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + "  id=" + id);
            int beforeId = threadLocal.get();
            int afterId = beforeId + id;
            threadLocal.set(afterId);
            System.out.println(Thread.currentThread().getName() + "  after id =" + threadLocal.get());
        }

    }

    public static void main(String[] args) {
        new UseThreadLocal().startThread();
    }
輸出:
Thread-0  id=0
Thread-0  after id =1
Thread-1  id=1
Thread-1  after id =2

參考資料:

《深入理解Java虛擬機(jī)》

《Java特種兵》5.1 基礎(chǔ)介紹

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末滤淳,一起剝皮案震驚了整個濱河市梧喷,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌脖咐,老刑警劉巖铺敌,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異屁擅,居然都是意外死亡偿凭,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進(jìn)店門派歌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來弯囊,“玉大人,你說我怎么就攤上這事胶果∝抑觯” “怎么了?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵早抠,是天一觀的道長霎烙。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么悬垃? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任游昼,我火速辦了婚禮,結(jié)果婚禮上尝蠕,老公的妹妹穿的比我還像新娘酱床。我一直安慰自己,他們只是感情好趟佃,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布扇谣。 她就那樣靜靜地躺著,像睡著了一般闲昭。 火紅的嫁衣襯著肌膚如雪罐寨。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天序矩,我揣著相機(jī)與錄音鸯绿,去河邊找鬼。 笑死簸淀,一個胖子當(dāng)著我的面吹牛瓶蝴,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播租幕,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼舷手,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了劲绪?” 一聲冷哼從身側(cè)響起男窟,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎贾富,沒想到半個月后歉眷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡颤枪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年汗捡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片畏纲。...
    茶點(diǎn)故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡扇住,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出霍骄,到底是詐尸還是另有隱情台囱,我是刑警寧澤,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布读整,位于F島的核電站簿训,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜强品,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一膘侮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧的榛,春花似錦琼了、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至晓淀,卻和暖如春所袁,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背凶掰。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工燥爷, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人懦窘。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓前翎,卻偏偏與公主長得像,于是被迫代替她去往敵國和親畅涂。 傳聞我的和親對象是個殘疾皇子港华,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評論 2 355

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