Java實(shí)現(xiàn)生產(chǎn)者消費(fèi)者的三種方式

一花墩、使用synchronize以及wait()雳刺、notify() /notifyAll()


package com.zhb.juc;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 使用synchronize wait notify/notifyall實(shí)現(xiàn)生產(chǎn)者消費(fèi)者模式
 */

class ShareDataV1 {
    public static AtomicInteger atomicInteger = new AtomicInteger();
    public volatile boolean flag = true;
    public static final int MAX_COUNT = 10;
    public static final List<Integer> pool = new ArrayList<>();

    public void produce() {
        // 判斷盔性,干活仲锄,通知
        while (flag) {
            // 每隔 1000 毫秒生產(chǎn)一個(gè)商品
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
            }
            synchronized (pool) {
                //池子滿了劲妙,生產(chǎn)者停止生產(chǎn)
                //埋個(gè)坑,這里用的if
                //TODO 判斷
                if (pool.size() == MAX_COUNT) {
                    try {
                        System.out.println("pool is full, wating...");
                        pool.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //干活
                pool.add(atomicInteger.incrementAndGet());
                System.out.println("produce number:" + atomicInteger.get() + "\t" + "current size:" + pool.size());
                //通知
                pool.notifyAll();
            }
        }
    }

    public void consumue() {
        // 判斷儒喊,干活镣奋,通知
        while (flag) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
            synchronized (pool) {
                //池子滿了,生產(chǎn)者停止生產(chǎn)
                //埋個(gè)坑怀愧,這里用的if
                //TODO 判斷
                if (pool.size() == 0) {
                    try {
                        System.out.println("pool is empty, wating...");
                        pool.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //干活
                int temp = pool.get(0);
                pool.remove(0);
                System.out.println("cousume number:" + temp + "\t" + "current size:" + pool.size());
                //通知
                pool.notifyAll();
            }
        }
    }

    public void stop() {
        flag = false;
    }
}

public class ProducerConsumer_V1 {

    public static void main(String[] args) {
        ShareDataV1 shareDataV1 = new ShareDataV1();
        new Thread(() -> {
            shareDataV1.produce();
        }, "AAA").start();

        new Thread(() -> {
            shareDataV1.consumue();
        }, "BBB").start();

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        shareDataV1.stop();
    }
}

上面的程序在只有兩個(gè)線程時(shí)(一個(gè)生產(chǎn)者侨颈,一個(gè)消費(fèi)者)可以正常工作。打印的log如下:

produce number:1    current size:1
produce number:2    current size:2
produce number:3    current size:3
produce number:4    current size:4
produce number:5    current size:5
produce number:6    current size:6
produce number:7    current size:7
produce number:8    current size:8
produce number:9    current size:9
cousume number:1    current size:8
produce number:10   current size:9
produce number:11   current size:10
pool is full, wating...
cousume number:2    current size:9
produce number:12   current size:10
pool is full, wating...
cousume number:3    current size:9
produce number:13   current size:10
pool is full, wating...
cousume number:4    current size:9
produce number:14   current size:10
pool is full, wating...
cousume number:5    current size:9
produce number:15   current size:10

Process finished with exit code 0

但是我們把生產(chǎn)者和消費(fèi)者線程擴(kuò)展至多個(gè)芯义。就出錯(cuò)了哈垢。例如再增加CCC和DDD線程分別生產(chǎn)和消費(fèi)。只改動(dòng)了main方法:

public class ProducerConsumer_V1 {

    public static void main(String[] args) {
        ShareDataV1 shareDataV1 = new ShareDataV1();
        new Thread(() -> {
            shareDataV1.produce();
        }, "AAA").start();

        new Thread(() -> {
            shareDataV1.consumue();
        }, "BBB").start();

        new Thread(() -> {
            shareDataV1.produce();
        }, "CCC").start();

        new Thread(() -> {
            shareDataV1.consumue();
        }, "DDD").start();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        shareDataV1.stop();
    }
}

輸出的log如下:

produce number:1    current size:1
produce number:2    current size:2
produce number:3    current size:3
produce number:4    current size:4
produce number:5    current size:5
produce number:6    current size:6
produce number:7    current size:7
produce number:8    current size:8
produce number:9    current size:9
produce number:10   current size:10
pool is full, wating...
pool is full, wating...
cousume number:1    current size:9
cousume number:2    current size:8
produce number:11   current size:9
produce number:12   current size:10
pool is full, wating...
pool is full, wating...
cousume number:3    current size:9
produce number:13   current size:10
produce number:14   current size:11
cousume number:4    current size:10
pool is full, wating...
pool is full, wating...
cousume number:5    current size:9
produce number:15   current size:10
produce number:16   current size:11
cousume number:6    current size:10
pool is full, wating...
pool is full, wating...
cousume number:7    current size:9
produce number:17   current size:10
produce number:18   current size:11
cousume number:8    current size:10
pool is full, wating...
pool is full, wating...
cousume number:9    current size:9
produce number:19   current size:10
produce number:20   current size:11
cousume number:10   current size:10
pool is full, wating...
pool is full, wating...
cousume number:11   current size:9
produce number:21   current size:10
produce number:22   current size:11

Process finished with exit code 0

我們看到current size 能到11了扛拨。這肯定出錯(cuò)了耘分。因?yàn)槲覀円髉ool的最大容量為10。出現(xiàn)這個(gè)情況的原因是在多線程的環(huán)境下绑警,要防止虛假喚醒求泰。即判斷條件不能用if,而是用while计盒。接下來(lái)我們修改上面//TODO部分的代碼拜秧,把if改成while再來(lái)測(cè)試。最終版正確的代碼如下:

package com.zhb.juc;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 使用synchronize wait notify/notifyall實(shí)現(xiàn)生產(chǎn)者消費(fèi)者模式
 */

class ShareDataV1 {
    public static AtomicInteger atomicInteger = new AtomicInteger();
    public volatile boolean flag = true;
    public static final int MAX_COUNT = 10;
    public static final List<Integer> pool = new ArrayList<>();

    public void produce() {
        // 判斷章郁,干活枉氮,通知
        while (flag) {
            // 每隔 1000 毫秒生產(chǎn)一個(gè)商品
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
            }
            synchronized (pool) {
                //池子滿了,生產(chǎn)者停止生產(chǎn)
                //埋個(gè)坑暖庄,這里用的if
                //TODO 判斷
                while (pool.size() == MAX_COUNT) {
                    try {
                        System.out.println("pool is full, wating...");
                        pool.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //干活
                pool.add(atomicInteger.incrementAndGet());
                System.out.println("produce number:" + atomicInteger.get() + "\t" + "current size:" + pool.size());
                //通知
                pool.notifyAll();
            }
        }
    }

    public void consumue() {
        // 判斷聊替,干活,通知
        while (flag) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
            synchronized (pool) {
                //池子滿了培廓,生產(chǎn)者停止生產(chǎn)
                //埋個(gè)坑惹悄,這里用的if
                //TODO 判斷
                while (pool.size() == 0) {
                    try {
                        System.out.println("pool is empty, wating...");
                        pool.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //干活
                int temp = pool.get(0);
                pool.remove(0);
                System.out.println("cousume number:" + temp + "\t" + "current size:" + pool.size());
                //通知
                pool.notifyAll();
            }
        }
    }

    public void stop() {
        flag = false;
    }
}

public class ProducerConsumer_V1 {

    public static void main(String[] args) {
        ShareDataV1 shareDataV1 = new ShareDataV1();
        new Thread(() -> {
            shareDataV1.produce();
        }, "AAA").start();

        new Thread(() -> {
            shareDataV1.consumue();
        }, "BBB").start();

        new Thread(() -> {
            shareDataV1.produce();
        }, "CCC").start();

        new Thread(() -> {
            shareDataV1.consumue();
        }, "DDD").start();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        shareDataV1.stop();
    }
}

輸出結(jié)果:

produce number:1    current size:1
produce number:2    current size:2
produce number:3    current size:3
produce number:4    current size:4
produce number:5    current size:5
produce number:6    current size:6
produce number:7    current size:7
produce number:8    current size:8
produce number:9    current size:9
produce number:10   current size:10
pool is full, wating...
pool is full, wating...
cousume number:1    current size:9
produce number:11   current size:10
pool is full, wating...
cousume number:2    current size:9
produce number:12   current size:10
pool is full, wating...
pool is full, wating...
cousume number:3    current size:9
produce number:13   current size:10
pool is full, wating...
cousume number:4    current size:9
produce number:14   current size:10
pool is full, wating...
pool is full, wating...
cousume number:5    current size:9
produce number:15   current size:10
pool is full, wating...
cousume number:6    current size:9
produce number:16   current size:10
pool is full, wating...
pool is full, wating...
cousume number:7    current size:9
produce number:17   current size:10
pool is full, wating...
cousume number:8    current size:9
produce number:18   current size:10
pool is full, wating...
pool is full, wating...
cousume number:9    current size:9
produce number:19   current size:10
pool is full, wating...
cousume number:10   current size:9
produce number:20   current size:10
cousume number:11   current size:9

Process finished with exit code 0

二、使用Lock肩钠,Condition的await和signal方法

JUC包下的鎖Lock替代synchronize關(guān)鍵字泣港。await方法代替wait暂殖,signal代替notifyall。
下面這個(gè)demo實(shí)現(xiàn)了pool的大小為1的生產(chǎn)者消費(fèi)者模型当纱。

package com.zhb.juc;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class ShareData {
    private int number = 0;
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public void increment() throws Exception {
        lock.lock();
        try { 
            while (number != 0) {
                //等待呛每,不能生產(chǎn)
                condition.await();
            }
            number++;
            System.out.println(Thread.currentThread().getName() + "\t" + number);

            condition.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }


    }

    public void decrement() throws Exception {
        lock.lock();
        try {
            while (number == 0) {
                //等待,不能消費(fèi)
                condition.await();
            }

            number--;
            System.out.println(Thread.currentThread().getName() + "\t" + number);

            condition.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }


    }
}

public class ProducerConsumer_V2{
    public static void main(String[] args) {
        ShareData shareData = new ShareData();

        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    shareData.increment();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }, "AA").start();

        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    shareData.decrement();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }, "BB").start();

        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    shareData.increment();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }, "CC").start();

        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    shareData.decrement();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }, "DD").start();
    }
}

三坡氯、終極版使用阻塞隊(duì)列

首先談?wù)勛枞?duì)列:
當(dāng)阻塞隊(duì)列為空時(shí)晨横,從阻塞隊(duì)列中取數(shù)據(jù)的操作會(huì)被阻塞。
當(dāng)阻塞隊(duì)列為滿時(shí)箫柳,往阻塞隊(duì)列中添加數(shù)據(jù)的操作會(huì)被阻塞手形。

JDK中的七大阻塞隊(duì)列

阻塞隊(duì)列名稱 說(shuō)明
ArrayBlockingQueue 一個(gè)由數(shù)組結(jié)構(gòu)組成的有界阻塞隊(duì)列。
LinkedBlockingQueue 一個(gè)由鏈表結(jié)構(gòu)組成的有界阻塞隊(duì)列悯恍。
PriorityBlockingQueue 一個(gè)支持優(yōu)先級(jí)排序的無(wú)界阻塞隊(duì)列库糠。
DelayQueue 一個(gè)使用優(yōu)先級(jí)隊(duì)列實(shí)現(xiàn)的無(wú)界阻塞隊(duì)列。
SynchronousQueue 一個(gè)不存儲(chǔ)元素的阻塞隊(duì)列涮毫。
LinkedTransferQueue 一個(gè)由鏈表結(jié)構(gòu)組成的無(wú)界阻塞隊(duì)列曼玩。
LinkedBlockingDeque 一個(gè)由鏈表結(jié)構(gòu)組成的雙向阻塞隊(duì)列。

ArrayBlockingQueue:
基于數(shù)組的阻塞隊(duì)列實(shí)現(xiàn)窒百,其內(nèi)部維護(hù)一個(gè)定長(zhǎng)的數(shù)組黍判,用于存儲(chǔ)隊(duì)列元素。線程阻塞的實(shí)現(xiàn)是通過(guò)ReentrantLock來(lái)完成的篙梢,數(shù)據(jù)的插入與取出共用同一個(gè)鎖顷帖,因此ArrayBlockingQueue并不能實(shí)現(xiàn)生產(chǎn)、消費(fèi)同時(shí)進(jìn)行渤滞。而且在創(chuàng)建ArrayBlockingQueue時(shí)贬墩,我們還可以控制對(duì)象的內(nèi)部鎖是否采用公平鎖,默認(rèn)采用非公平鎖妄呕。

LinkedBlockingQueue:
基于單向鏈表的阻塞隊(duì)列實(shí)現(xiàn)陶舞,在初始化LinkedBlockingQueue的時(shí)候可以指定對(duì)立的大小,也可以不指定绪励,默認(rèn)類似一個(gè)無(wú)限大小的容量(Integer.MAX_VALUE)肿孵,不指隊(duì)列容量大小也是會(huì)有風(fēng)險(xiǎn)的,一旦數(shù)據(jù)生產(chǎn)速度大于消費(fèi)速度疏魏,系統(tǒng)內(nèi)存將有可能被消耗殆盡停做,因此要謹(jǐn)慎操作。另外LinkedBlockingQueue中用于阻塞生產(chǎn)者大莫、消費(fèi)者的鎖是兩個(gè)(鎖分離)蛉腌,因此生產(chǎn)與消費(fèi)是可以同時(shí)進(jìn)行的。

參考:http://www.reibang.com/p/f4eefb069e27

下面是使用阻塞隊(duì)列實(shí)現(xiàn)生產(chǎn)者消費(fèi)者模式:

package com.zhb.juc;

/*
使用阻塞隊(duì)列實(shí)現(xiàn)生產(chǎn)者消費(fèi)者模型
 */

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;


//資源類
class ShareDataV3{
    private static final int MAX_CAPACITY = 10; //阻塞隊(duì)列容量
    private static BlockingQueue<Integer> blockingQueue= new ArrayBlockingQueue<>(MAX_CAPACITY); //阻塞隊(duì)列
    private  volatile boolean FLAG = true;
    private  AtomicInteger atomicInteger = new AtomicInteger();

    public void produce() throws InterruptedException {
        while (FLAG){
            boolean retvalue = blockingQueue.offer(atomicInteger.incrementAndGet(), 2, TimeUnit.SECONDS);
            if (retvalue==true){
                System.out.println(Thread.currentThread().getName()+"\t 插入隊(duì)列"+ atomicInteger.get()+"成功"+"資源隊(duì)列大小= " + blockingQueue.size());
            }else {
                System.out.println(Thread.currentThread().getName()+"\t 插入隊(duì)列"+ atomicInteger.get()+"失敗"+"資源隊(duì)列大小= " + blockingQueue.size());

            }
          TimeUnit.SECONDS.sleep(1);
        }
        System.out.println(Thread.currentThread().getName()+"FLAG變?yōu)閒lase,生產(chǎn)停止");
    }

    public void consume() throws InterruptedException {
        Integer result = null;
        while (true){
            result = blockingQueue.poll(2, TimeUnit.SECONDS);
            if (null==result){
                System.out.println("超過(guò)兩秒沒(méi)有取道數(shù)據(jù)烙丛,消費(fèi)者即將退出");
                return;
            }
            System.out.println(Thread.currentThread().getName()+"\t 消費(fèi)"+ result+"成功"+"\t\t"+"資源隊(duì)列大小= " + blockingQueue.size());
            Thread.sleep(1500);
        }

    }

    public void stop() {
        this.FLAG = false;
    }
}

public class ProducerConsumer_V3 {

    public static void main(String[] args) {
        ShareDataV3 v3 = new ShareDataV3();
        new Thread(()->{
            try {
                v3.produce();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "AAA").start();

        new Thread(()->{
            try {
                v3.consume();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "BBB").start();

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        v3.stop();
    }
}

可以看到使用阻塞隊(duì)列根本不需要我們?nèi)ゼ渔i舅巷,通知什么的,完全解放了河咽。

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

AAA  插入隊(duì)列1成功資源隊(duì)列大小= 0
BBB  消費(fèi)1成功      資源隊(duì)列大小= 0
AAA  插入隊(duì)列2成功資源隊(duì)列大小= 1
BBB  消費(fèi)2成功      資源隊(duì)列大小= 0
AAA  插入隊(duì)列3成功資源隊(duì)列大小= 1
BBB  消費(fèi)3成功      資源隊(duì)列大小= 1
AAA  插入隊(duì)列4成功資源隊(duì)列大小= 1
AAA  插入隊(duì)列5成功資源隊(duì)列大小= 2
BBB  消費(fèi)4成功      資源隊(duì)列大小= 1
AAA  插入隊(duì)列6成功資源隊(duì)列大小= 2
AAAFLAG變?yōu)閒lase钠右,生產(chǎn)停止
BBB  消費(fèi)5成功      資源隊(duì)列大小= 1
BBB  消費(fèi)6成功      資源隊(duì)列大小= 0
超過(guò)兩秒沒(méi)有取道數(shù)據(jù),消費(fèi)者即將退出

Process finished with exit code 0

Java與大數(shù)據(jù)資源分享:
https://zhuanlan.zhihu.com/p/50030125
Java與大數(shù)據(jù)資源分享:
https://zhuanlan.zhihu.com/p/50030125
Java與大數(shù)據(jù)資源分享:
https://zhuanlan.zhihu.com/p/50030125

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末库北,一起剝皮案震驚了整個(gè)濱河市爬舰,隨后出現(xiàn)的幾起案子们陆,更是在濱河造成了極大的恐慌寒瓦,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,000評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件坪仇,死亡現(xiàn)場(chǎng)離奇詭異杂腰,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)椅文,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門喂很,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人皆刺,你說(shuō)我怎么就攤上這事少辣。” “怎么了羡蛾?”我有些...
    開封第一講書人閱讀 168,561評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵漓帅,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我痴怨,道長(zhǎng)忙干,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,782評(píng)論 1 298
  • 正文 為了忘掉前任浪藻,我火速辦了婚禮捐迫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘爱葵。我一直安慰自己施戴,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評(píng)論 6 397
  • 文/花漫 我一把揭開白布萌丈。 她就那樣靜靜地躺著暇韧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪浓瞪。 梳的紋絲不亂的頭發(fā)上懈玻,一...
    開封第一講書人閱讀 52,394評(píng)論 1 310
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼涂乌。 笑死艺栈,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的湾盒。 我是一名探鬼主播湿右,決...
    沈念sama閱讀 40,952評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼罚勾!你這毒婦竟也來(lái)了毅人?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,852評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤尖殃,失蹤者是張志新(化名)和其女友劉穎丈莺,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體送丰,經(jīng)...
    沈念sama閱讀 46,409評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡缔俄,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評(píng)論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了器躏。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片俐载。...
    茶點(diǎn)故事閱讀 40,615評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖登失,靈堂內(nèi)的尸體忽然破棺而出遏佣,到底是詐尸還是另有隱情,我是刑警寧澤揽浙,帶...
    沈念sama閱讀 36,303評(píng)論 5 350
  • 正文 年R本政府宣布状婶,位于F島的核電站,受9級(jí)特大地震影響捏萍,放射性物質(zhì)發(fā)生泄漏太抓。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評(píng)論 3 334
  • 文/蒙蒙 一令杈、第九天 我趴在偏房一處隱蔽的房頂上張望走敌。 院中可真熱鬧,春花似錦逗噩、人聲如沸掉丽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)捶障。三九已至,卻和暖如春纲刀,著一層夾襖步出監(jiān)牢的瞬間项炼,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留锭部,地道東北人暂论。 一個(gè)月前我還...
    沈念sama閱讀 49,041評(píng)論 3 377
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像拌禾,于是被迫代替她去往敵國(guó)和親取胎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評(píng)論 2 359

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