并發(fā)編程之美讀書筆記 1

線程的概念

線程不能獨(dú)立存在,資源由操作系統(tǒng)分配給進(jìn)程,但是CPU資源是分配給線程的.同一個(gè)進(jìn)程內(nèi)的線程:

  • 共享: 堆(主要存放使用new操作創(chuàng)建的對(duì)象實(shí)例)和方法區(qū)(JVM加載的類,常量以及靜態(tài)變量等)
  • 獨(dú)立: 程序計(jì)數(shù)器(獲得CPU控制權(quán)后可以從計(jì)數(shù)器指定地址繼續(xù)執(zhí)行)和棧區(qū)域.

當(dāng)啟動(dòng)main函數(shù)時(shí),就相當(dāng)于啟動(dòng)了一個(gè)JVM的進(jìn)程,而main所在的線程就是該進(jìn)程中的主線程.

如何創(chuàng)建線程

有三種方式:

  1. 繼承Thread類,重寫run方法:
// Thread1.java
public class Thread1 extends Thread{

    @Override
    public void run() {
        System.out.println("current-thread: "+this.getName());
        System.out.println("繼承自Thread");
    }

    public static void main(String[] args) {
        Thread1 t = new Thread1();
        t.start();
    }
}

不需要使用currentThread就可以獲取當(dāng)前線程,但是不能再繼承其他類

  1. 實(shí)現(xiàn) Runnable方法,并重寫run方法:
//Thread2.java
public class Thread2 implements Runnable{
    private String name;

    public Thread2(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        System.out.println("this is "+ name + " running");
        System.out.println("實(shí)現(xiàn)了Runnable接口");
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(new Thread2("t1"));
        t1.start();
        Thread t2 = new Thread(new Thread2("t2"));
        t2.start();
    }
}

可以繼承其他類,還可以添加參數(shù)區(qū)分

  1. 實(shí)現(xiàn)Callable接口的call方法:
//Thread3.java
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class Thread3 implements Callable<String> {
    @Override
    public String call(){
        System.out.println("使用FutureTask方式,可以有返回值");
        return "done";
    }

    public static void main(String[] args) throws InterruptedException {
        FutureTask<String> ft = new FutureTask<String>(new Thread3());
        Thread t = new Thread(ft);
        t.start();
        try {
            String result = ft.get();
            System.out.println(result);
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

具有返回值,可以使用get方法獲得返回值.也可以繼承其他類.

當(dāng)調(diào)用Threadstart方法,線程只是進(jìn)入了就緒狀態(tài),只有當(dāng)cpu資源得到滿足時(shí),才會(huì)真正開(kāi)始運(yùn)行.run方法結(jié)束后,線程就處于終止?fàn)顟B(tài).

wait與notify

waitnotify都是Object類中的方法.

wait

只有獲得了變量的監(jiān)視鎖,才能調(diào)用該變量的wait方法,否則會(huì)拋出異常:

public class WaitExample {
    private int a;

    void incr() {
        a++;
    }

    int getA() {
        return a;
    }
    public static void main(String[] args) {
        WaitExample waitExample = new WaitExample();
        try {
            // wrong
            waitExample.wait();
            for (int i = 0; i < 20000; i++) {
                Thread t = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        waitExample.incr();
                    }
                });
                t.start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println(waitExample.getA());

    }
}

運(yùn)行結(jié)果:

java.lang.IllegalMonitorStateException
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Object.java:502)
    at com.may.learning.WaitExample.main(WaitExample.java:17)
0

獲得監(jiān)視鎖可以通過(guò)synchronized關(guān)鍵字:
比如在方法上加上關(guān)鍵字:

    synchronized void incr() {
        a++;
    }

或者,在調(diào)用時(shí)對(duì)該類加上關(guān)鍵字:

synchronized (waitExample) {
...
}

當(dāng)調(diào)用wait時(shí),只會(huì)釋放當(dāng)前變量的鎖:

    public static void main(String[] args) throws InterruptedException{
        WaitExample waitExample = new WaitExample();
        WaitExample anotherWaitExample = new WaitExample();
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (waitExample) {
                    System.out.println("t: get waitExample lock success!");
                    System.out.println("t: try get anotherWaitExample lock");
                    try {
                        synchronized (anotherWaitExample) {
                            System.out.println("t: get anotherWaitExample success!");
                            System.out.println("t: release waitExample lock");
                            // t只釋放了waitExample的鎖
                            waitExample.wait();

                        }
                    } catch (InterruptedException e) {
                        System.out.println("被中斷");
                    }
                }

            }
        });
        t.start();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (waitExample) {
                    System.out.println("t1: get waitExample lock success!");
                    System.out.println("t1: try get anotherWaitExample lock");
                    try {
                        // 由于t未釋放鎖,因此t1獲取不到anotherWaitExample的鎖
                        synchronized (anotherWaitExample) {
                            System.out.println("t1: get anotherWaitExample success!");
                            System.out.println("t1: release waitExample lock");
                            waitExample.wait();

                        }
                    } catch (InterruptedException e) {
                        System.out.println("被中斷");
                    }
                }

            }
        });
        t1.start();
        Thread.sleep(1000);
    }

運(yùn)行結(jié)果:

t: get waitExample lock success!
t: try get anotherWaitExample lock
t: get anotherWaitExample success!
t: release waitExample lock
t1: get waitExample lock success!
t1: try get anotherWaitExample lock

如果需要指定時(shí)間,可以使用wait(long timeout)或者wait(long timeout, int nanos).
wait掛起時(shí),被中斷時(shí)會(huì)拋出異常:

public class WaitExample {

    private int a;

    void incr() {
        a++;
    }

    int getA() {
        return a;
    }

    public static void main(String[] args) throws InterruptedException{
        WaitExample waitExample = new WaitExample();
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (waitExample) {
                    waitExample.incr();
                    try {
                        waitExample.wait();
                    } catch (InterruptedException e) {
                        System.out.println("被中斷");
                    }
                }

            }
        });
        t.start();
        Thread.sleep(1000);
        t.interrupt();
        System.out.println(waitExample.getA());
    }
}

運(yùn)行結(jié)果:

1
被中斷

notify

notify會(huì)喚醒被wait阻塞掛起的線程.與wait類似,需要獲得了變量的監(jiān)視鎖后才能對(duì)其進(jìn)行進(jìn)行notify操作.如果有多個(gè)線程都在等待喚醒,那么會(huì)隨機(jī)喚醒某一個(gè)線程.而notifyAll會(huì)喚醒所有阻塞等待的線程.
類似wait方法直奋,notify也需要先獲得對(duì)象的監(jiān)視鎖(但是notify不會(huì)釋放鎖)盗似。

    public static void main(String[] args) throws InterruptedException {
        NotifyExample notifyExample = new NotifyExample();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    synchronized (notifyExample) {
                        System.out.println("t1 掛起");
                        notifyExample.wait();
                        System.out.println("t1 被喚醒了");
                    }
                } catch (InterruptedException e) {
                    System.out.println("被中斷了");
                }
            }
        });
        t1.start();
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    synchronized (notifyExample) {
                        System.out.println("t2 掛起");
                        notifyExample.wait();
                        System.out.println("t2 被喚醒了");
                    }
                } catch (InterruptedException e) {
                    System.out.println("被中斷了");
                }
            }
        });
        t2.start();
        Thread.sleep(1000);
        synchronized (notifyExample) {
            notifyExample.notify();
        }
    }

運(yùn)行結(jié)果:

t1 掛起
t2 掛起
t1 被喚醒了

如果將notifyExample.notify()換成notifyExample.notifyAll(),那么t1t2都能被喚醒:

t1 掛起
t2 掛起
t2 被喚醒了
t1 被喚醒了

生產(chǎn)者消費(fèi)者

利用waitnotify寫一個(gè)簡(jiǎn)單的生產(chǎn)者消費(fèi)者:

import java.util.LinkedList;
import java.util.Queue;

public class ProducerConsumer {

    public static void main(String[] args) throws InterruptedException {
        Queue<Integer> queue = new LinkedList<>();
        Thread producer = new Thread(new Runnable() {
            @Override
            public void run() {
                int i=0;
                synchronized (queue) {
                    while (true){
                        try {
                            if (!queue.isEmpty()) {
                                queue.wait();
                            }else{
                                queue.add(++i);
                                System.out.println("生產(chǎn)了"+i);
                                queue.notify();
                            }
                        } catch (InterruptedException e) {
                            System.out.println("被中斷了");
                            return;
                        }
                    }
                }
            }
        });
        Thread consumer = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (queue) {
                    while (true){
                        try{
                            if (queue.isEmpty()) {
                                queue.wait();
                            }else{
                                int i = queue.poll();
                                System.out.println("消費(fèi)了"+i);
                                queue.notify();
                            }
                        }catch (InterruptedException e){
                            System.out.println("被中斷了");
                            return;
                        }
                    }
                }
            }
        });
        producer.start();
        consumer.start();
        Thread.sleep(10000);
        producer.interrupt();
        consumer.interrupt();
    }
}

運(yùn)行結(jié)果:

...
生產(chǎn)了782421
消費(fèi)了782421
生產(chǎn)了782422
消費(fèi)了782422
生產(chǎn)了782423
消費(fèi)了782423
生產(chǎn)了782424
被中斷了
被中斷了

join

waitnotify屬于Ojbect的方法,而joinThread的方法.
調(diào)用某一線程的join方法,可以使當(dāng)前線程(下例中的main線程)阻塞等待該線程完成:

public class JoinTest {

    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                    System.out.println("t 結(jié)束了!");
                } catch (InterruptedException e) {
                    System.out.println("被中斷了");
                }
            }
        });
        t.start();
        t.join();
        System.out.println("main 結(jié)束了!");
    }
}

運(yùn)行結(jié)果:

t 結(jié)束了!
main 結(jié)束了!

sleep

sleepwait 一樣可以掛起當(dāng)前線程,被中斷時(shí)也會(huì)拋出異常.但不同的是它是屬于Thread的方法,并且它不會(huì)釋放對(duì)象的監(jiān)視鎖.指定睡眠時(shí)間到達(dá)后,會(huì)進(jìn)入就緒狀態(tài),等待cpu的調(diào)度.

public class SleepTest {
    public static void main(String[] args) throws InterruptedException {
        SleepTest sleepTest = new SleepTest();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (sleepTest){
                    try {
                        System.out.println("t1 獲取到鎖");
                        Thread.sleep(60000);
                    } catch (InterruptedException e) {
                        System.out.println("被中斷了!");
                    }
                }
            }
        });
        t1.start();
        Thread.sleep(1000);
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("t2 等待鎖");
                synchronized (sleepTest) {
                    System.out.println("t2 獲取到鎖了");
                }
            }
        });
        t2.start();
        Thread.sleep(2000);
        t1.interrupt();
    }
}

運(yùn)行結(jié)果:

t1 獲取到鎖
t2 等待鎖
被中斷了!
t2 獲取到鎖了

yield

線程會(huì)主動(dòng)讓出自己的cpu時(shí)間,并不會(huì)被掛起,只是進(jìn)入了就緒狀態(tài).但是下一次仍然可能被調(diào)度到.

中斷

前面已經(jīng)使用了interrupt很多次,需要注意與isInterrupted以及interrupted進(jìn)行區(qū)分.
isInterrupted: 判斷當(dāng)前線程是否被中斷;
interrupted: 判斷當(dāng)前線程是否被中斷,并且復(fù)位(清除中斷標(biāo)志);

使用interrupted判斷中斷并且復(fù)位:

public class InterruptTest {

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                while (!Thread.interrupted()) {

                }
                System.out.println("t1 is Interrupted: "+Thread.currentThread().isInterrupted());
            }
        });
        t1.start();
        t1.interrupt();
        t1.join();
        System.out.println("done");
    }
}

運(yùn)行結(jié)果:

t1 is Interrupted: false
done

需要注意的是調(diào)用線程的interrupt方法,只是為該線程設(shè)置中斷位.當(dāng)線程在運(yùn)行時(shí),會(huì)立即往下執(zhí)行.而當(dāng)被wait,join或者sleep方法阻塞掛起時(shí),才會(huì)拋出InterruptedException異常,此時(shí)中斷位會(huì)被恢復(fù),如下面這個(gè)例子:

public class InterruptTest throws InterruptedException{

    public static void main(String[] args){
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("t1 running");
                while (true) {
                }
            }
        });
        t1.start();
        t1.interrupt();
        System.out.println("main thread isInterrupted: " + Thread.interrupted());
        System.out.println("t1 isInterrupted: " + t1.isInterrupted());
        boolean isInterrupted = Thread.interrupted();
        System.out.println("isInterrupted: " + isInterrupted);
        System.out.println("main thread isInterrupted: " + Thread.interrupted());
        System.out.println("t1 isInterrupted: " + t1.isInterrupted());
        t1.join();
        System.out.println("done");
    }
}

輸出結(jié)果:

main thread isInterrupted: false
t1 isInterrupted: true
isInterrupted: false
main thread isInterrupted: false
t1 running
t1 isInterrupted: true

因?yàn)?code>t1并沒(méi)有被掛起,所以即使中斷位為true,也仍然在繼續(xù)運(yùn)行,不會(huì)輸出"done".而interrupted針對(duì)是當(dāng)前線程,也就是主線程,所以中斷標(biāo)志位一直是false.
如果在阻塞情況下,中斷位會(huì)被馬上復(fù)位,對(duì)上面的例子稍加修改:

public class InterruptTest {

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try{
                    while (!Thread.currentThread().isInterrupted()) {
                        System.out.println("t1: running");
                        Thread.sleep(1000);
                    }
                }catch (Exception e){
                    System.out.println("t1 被中斷");
                    System.out.println("thread t1 isInterrupted : "+Thread.currentThread().isInterrupted());
                }
            }
        });
        t1.start();
        Thread.sleep(1000);
        t1.interrupt();
        System.out.println("main thread isInterrupted: " + Thread.interrupted());
        System.out.println("t1 isInterrupted: " + t1.isInterrupted());
        t1.join();
        System.out.println("done");
    }
}

運(yùn)行結(jié)果:

t1: running
t1 被中斷
thread t1 isInterrupted : false
main thread isInterrupted: false
t1 isInterrupted: false
done

主線程中的isInterrupted仍然是false,但是打印出的t1isInterrupted由于處在阻塞狀態(tài)被中斷,中斷位又被復(fù)位成了false.

上下文切換與死鎖

當(dāng)出現(xiàn):

  • CPU時(shí)間用盡,線程進(jìn)入就緒狀態(tài)時(shí)
  • 被其他線程中斷時(shí)

會(huì)出現(xiàn)上下文的切換.

避免死鎖的出現(xiàn),可以采用不同線程都按照相同的順序去請(qǐng)求資源,保證資源獲取的有序一致性.

守護(hù)線程與用戶線程

守護(hù)線程的存在不影響JVM的退出,只要最后一個(gè)用戶線程沒(méi)有退出,正常情況下JVM也不會(huì)退出.
JVM沒(méi)有退出:

public class DaemonTest {

    public static void main(String[] args) {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {

                }
            }
        });
//        t.setDaemon(true);
        t.start();
        System.out.println("main exit");
    }
}

運(yùn)行結(jié)果:

main exit

t利用setDeamon設(shè)置為守護(hù)線程的注釋打開(kāi),運(yùn)行結(jié)果:

main exit

Process finished with exit code 0

原理是,main運(yùn)行后,JVM會(huì)自動(dòng)啟動(dòng)一個(gè)叫做DestoryJavaVM的線程,它會(huì)等待所有用戶線程結(jié)束后終止JVM進(jìn)程.

ThreadLocal

如果創(chuàng)建了一個(gè)ThreadLocal變量,每個(gè)訪問(wèn)這個(gè)變量的線程都會(huì)獲得一個(gè)副本.

public class ThreadLocalTest {
    static ThreadLocal<Integer> val = new ThreadLocal<>();

    static void print(String string) {
        System.out.println(string + ":" + val.get());
    }
    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                val.set(1);
                for (int i = 0; i < 50; i++) {
                    int v = val.get();
                    v++;
                    val.set(v);
                }
                print("thread1");
                val.remove();
                print("after remove thread1");
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                val.set(1);
                for (int i = 0; i < 50; i++) {
                    int v = val.get();
                    v += 2;
                    val.set(v);
                }
                print("thread2");
                val.remove();
                print("after remove thread2");
            }
        });
        t1.start();
        t2.start();
        System.out.println("done");
    }
}

運(yùn)行結(jié)果:

thread1:51
after remove thread1:null
done
thread2:101
after remove thread2:null

ThreadLocal的原理:

  1. Thread中有一個(gè)threadLocals變量,它的類型是ThreadLocal.ThreadLocalMap,實(shí)際上是一個(gè)hashMap.
  2. 當(dāng)使用set方法賦值時(shí):
// ThreadLocal.java
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

getMap方法獲得的是threadLocals,如果不為空,將當(dāng)前threadLocal變量作為key,設(shè)置的值作為value放入進(jìn)行存儲(chǔ),而如果為空,則利用createMap進(jìn)行初始化.

// ThreadLocal.java
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

需要注意的是createMap中傳入的是當(dāng)前線程,因?yàn)樾枰獮槠湓O(shè)置threadLocals變量的值.而threadLocals中的key實(shí)際上是ThreadLocal變量,也就是可以理解為:thread1.threadLocals -> {ThreadLocal@xxx:1, ThreadLocal@yyy:"hello"}

但是ThreadLocal不支持繼承,如果需要繼承父線程的值,需要使用InheritableThreadLocal:

public class InheritThreadLocalTest {
    static InheritableThreadLocal<String> inheritableThreadLocal = new InheritableThreadLocal<>();

    static void print(String str) {
        System.out.println(str + ":" + inheritableThreadLocal.get());
    }

    public static void main(String[] args) {
        inheritableThreadLocal.set("hello");
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                String initVal = inheritableThreadLocal.get();
                if (initVal != null) {
                    inheritableThreadLocal.set(initVal+" world");
                }
                print("thread 1");
            }
        });
        t.start();
        print("main");
        System.out.println("done");
    }
}

運(yùn)行結(jié)果:

main:hello
done
thread 1:hello world

InheritableThreadLocalThreadLocalset方法是一樣的,區(qū)別在于createMap,它將變量寫入了inheritableThreadLocals里:

    void createMap(Thread t, T firstValue) {
        t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
    }

在初始化線程的時(shí)候,init方法會(huì)設(shè)置inheritableThreadLocals:

    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc,
                      boolean inheritThreadLocals){
...
        if (inheritThreadLocals && parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
...
}

它會(huì)將父線程的inheritableThreadLocals都復(fù)制到自己的inheritableThreadLocals中.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市仑濒,隨后出現(xiàn)的幾起案子捆愁,更是在濱河造成了極大的恐慌疲酌,老刑警劉巖氓奈,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異呢铆,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)蹲缠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門棺克,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人线定,你說(shuō)我怎么就攤上這事娜谊。” “怎么了斤讥?”我有些...
    開(kāi)封第一講書人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵纱皆,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我芭商,道長(zhǎng)派草,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任铛楣,我火速辦了婚禮近迁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘簸州。我一直安慰自己鉴竭,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布勿侯。 她就那樣靜靜地躺著拓瞪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪助琐。 梳的紋絲不亂的頭發(fā)上祭埂,一...
    開(kāi)封第一講書人閱讀 51,482評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音兵钮,去河邊找鬼蛆橡。 笑死,一個(gè)胖子當(dāng)著我的面吹牛掘譬,可吹牛的內(nèi)容都是我干的泰演。 我是一名探鬼主播,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼葱轩,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼睦焕!你這毒婦竟也來(lái)了藐握?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤垃喊,失蹤者是張志新(化名)和其女友劉穎猾普,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體本谜,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡初家,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了乌助。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片溜在。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖他托,靈堂內(nèi)的尸體忽然破棺而出掖肋,到底是詐尸還是另有隱情,我是刑警寧澤上祈,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布培遵,位于F島的核電站,受9級(jí)特大地震影響登刺,放射性物質(zhì)發(fā)生泄漏籽腕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一纸俭、第九天 我趴在偏房一處隱蔽的房頂上張望皇耗。 院中可真熱鬧,春花似錦揍很、人聲如沸郎楼。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)呜袁。三九已至,卻和暖如春简珠,著一層夾襖步出監(jiān)牢的瞬間阶界,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工聋庵, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留膘融,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓祭玉,卻偏偏與公主長(zhǎng)得像氧映,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子脱货,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

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