java多線程同步(wait振愿、notify)生產(chǎn)者消費(fèi)者簡(jiǎn)單示例

一毅糟、為何寫(xiě)

最為一個(gè)Android開(kāi)發(fā)者红选,如果做得不夠深入可能為不會(huì)去處理多線程同步的問(wèn)題,稍微簡(jiǎn)單點(diǎn)可能使用一個(gè)線程池就可以搞定了留特,有關(guān)線程池的介紹可以參考我的另一篇文章:ExecutorService+LruCache+DiskLruCache用一個(gè)類打造簡(jiǎn)單的圖片加載庫(kù)
只是前段時(shí)間研究Android音視頻硬解碼纠脾,看到開(kāi)源項(xiàng)目中用到了線程同步,就是在視頻的YUV數(shù)據(jù)的暫存蜕青,和解碼為視頻并展示苟蹈,用到了兩個(gè)線程去做,一個(gè)線程收集視頻源數(shù)據(jù)右核,一個(gè)線程負(fù)責(zé)解碼并播放視頻慧脱,一個(gè)視頻數(shù)據(jù)池是兩個(gè)線程共享的,數(shù)據(jù)池滿了或者空了的時(shí)候兩個(gè)線程是要做出相應(yīng)處理的贺喝,這就涉及到線程同步了菱鸥。

這里寫(xiě)圖片描述

學(xué)習(xí)、工作和生活的心態(tài)就要像向日葵躏鱼,就算是太陽(yáng)不在也要迎著月亮氮采!

二、名字講解

什么是線程同步染苛?

當(dāng)使用多個(gè)線程來(lái)訪問(wèn)同一個(gè)數(shù)據(jù)時(shí)鹊漠,非常容易出現(xiàn)線程安全問(wèn)題(比如多個(gè)線程都在操作同一數(shù)據(jù)導(dǎo)致數(shù)據(jù)不一致),所以我們用同步機(jī)制來(lái)解決這些問(wèn)題。

實(shí)現(xiàn)同步機(jī)制有兩個(gè)方法:

1茶行、同步代碼塊:

synchronized(同一個(gè)數(shù)據(jù)){} 同一個(gè)數(shù)據(jù):就是N條線程同時(shí)訪問(wèn)一個(gè)數(shù)據(jù)躯概。

2、同步方法:

public synchronized 數(shù)據(jù)返回類型方法名(){}

通過(guò)使用同步方法畔师,可非常方便的將某類變成線程安全的類娶靡,具有如下特征:
1,該類的對(duì)象可以被多個(gè)線程安全的訪問(wèn)看锉。
2姿锭,每個(gè)線程調(diào)用該對(duì)象的任意方法之后,都將得到正確的結(jié)果伯铣。
3艾凯,每個(gè)線程調(diào)用該對(duì)象的任意方法之后,該對(duì)象狀態(tài)依然保持合理狀態(tài)懂傀。
注:synchronized關(guān)鍵字可以修飾方法,也可以修飾代碼塊蜡感,但不能修飾構(gòu)造器蹬蚁,屬性等

※不要對(duì)線程安全類的所有方法都進(jìn)行同步恃泪,只對(duì)那些會(huì)改變共享資源方法的進(jìn)行同步。
線程通訊:
當(dāng)使用synchronized 來(lái)修飾某個(gè)共享資源時(shí)(分同步代碼塊和同步方法兩種情況),當(dāng)某個(gè)線程獲得共享資源的鎖后就可以執(zhí)行相應(yīng)的代碼段犀斋,直到該線程運(yùn)行完該代碼段后才釋放對(duì)該共享資源的鎖贝乎,讓其他線程有機(jī)會(huì)執(zhí)行對(duì)該共享資源的修改。當(dāng)某個(gè)線程占有某個(gè)共享資源的鎖時(shí)叽粹,如果另外一個(gè)線程也想獲得這把鎖運(yùn)行就需要使用wait() 和notify()/notifyAll()方法來(lái)進(jìn)行線程通訊了览效。
Java.lang.object 里的三個(gè)方法wait() notify() notifyAll()

wait()
導(dǎo)致當(dāng)前線程等待,直到其他線程調(diào)用同步監(jiān)視器的notify方法或notifyAll方法來(lái)喚醒該線程虫几。

wait(mills)
都是等待指定時(shí)間后自動(dòng)蘇醒锤灿,調(diào)用wait方法的當(dāng)前線程會(huì)釋放該同步監(jiān)視器的鎖定,可以不用notify或notifyAll方法把它喚醒辆脸。

notify()
喚醒在同步監(jiān)視器上等待的單個(gè)線程但校,如果所有線程都在同步監(jiān)視器上等待,則會(huì)選擇喚醒其中一個(gè)線程啡氢,選擇是任意性的状囱,只有當(dāng)前線程放棄對(duì)該同步監(jiān)視器的鎖定后,也就是使用wait方法后倘是,才可以執(zhí)行被喚醒的線程亭枷。

notifyAll()
喚醒在同步監(jiān)視器上等待的所有的線程。只用當(dāng)前線程放棄對(duì)該同步監(jiān)視器的鎖定后搀崭,也就是使用wait方法后,才可以執(zhí)行被喚醒的線程叨粘。

注意,notify方法一定要在synchronized同步里面調(diào)用门坷,還有做異常捕捉宣鄙。


原子操作:根據(jù)Java規(guī)范,對(duì)于基本類型的賦值或者返回值操作默蚌,是原子操作冻晤。但這里的基本數(shù)據(jù)類型不包括long和double, 因?yàn)镴VM看到的基本存儲(chǔ)單位是32位,而long 和double都要用64位來(lái)表示绸吸。所以無(wú)法在一個(gè)時(shí)鐘周期內(nèi)完成鼻弧。

自增操作(++)不是原子操作,因?yàn)樗婕暗揭淮巫x和一次寫(xiě)锦茁。

原子操作:由一組相關(guān)的操作完成攘轩,這些操作可能會(huì)操縱與其它的線程共享的資源,為了保證得到正確的運(yùn)算結(jié)果码俩,一個(gè)線程在執(zhí)行原子操作其間度帮,應(yīng)該采取其他的措施使得其他的線程不能操縱共享資源。

同步代碼塊:為了保證每個(gè)線程能夠正常執(zhí)行原子操作,Java引入了同步機(jī)制笨篷,具體的做法是在代表原子操作的程序代碼前加上synchronized標(biāo)記瞳秽,這樣的代碼被稱為同步代碼塊。

同步鎖:每個(gè)JAVA對(duì)象都有且只有一個(gè)同步鎖率翅,在任何時(shí)刻练俐,最多只允許一個(gè)線程擁有這把鎖。

當(dāng)一個(gè)線程試圖訪問(wèn)帶有synchronized(this)標(biāo)記的代碼塊時(shí)冕臭,必須獲得 this關(guān)鍵字引用的對(duì)象的鎖腺晾,在以下的兩種情況下,本線程有著不同的命運(yùn)辜贵。
1悯蝉、 假如這個(gè)鎖已經(jīng)被其它的線程占用,JVM就會(huì)把這個(gè)線程放到本對(duì)象的鎖池中念颈。本線程進(jìn)入阻塞狀態(tài)泉粉。鎖池中可能有很多的線程,等到其他的線程釋放了鎖榴芳,JVM就會(huì)從鎖池中隨機(jī)取出一個(gè)線程嗡靡,使這個(gè)線程擁有鎖,并且轉(zhuǎn)到就緒狀態(tài)窟感。
2讨彼、 假如這個(gè)鎖沒(méi)有被其他線程占用,本線程會(huì)獲得這把鎖柿祈,開(kāi)始執(zhí)行同步代碼塊哈误。 (一般情況下在執(zhí)行同步代碼塊時(shí)不會(huì)釋放同步鎖,但也有特殊情況會(huì)釋放對(duì)象鎖 如在執(zhí)行同步代碼塊時(shí)躏嚎,遇到異常而導(dǎo)致線程終止蜜自,鎖會(huì)被釋放;在執(zhí)行代碼塊時(shí)卢佣,執(zhí)行了鎖所屬對(duì)象的wait()方法重荠,這個(gè)線程會(huì)釋放對(duì)象鎖,進(jìn)入對(duì)象的等待池中)

線程同步的特征:
1虚茶、 如果一個(gè)同步代碼塊和非同步代碼塊同時(shí)操作共享資源戈鲁,仍然會(huì)造成對(duì)共享資源的競(jìng)爭(zhēng)。因?yàn)楫?dāng)一個(gè)線程執(zhí)行一個(gè)對(duì)象的同步代碼塊時(shí)嘹叫,其他的線程仍然可以執(zhí)行對(duì)象的非同步代碼塊婆殿。(所謂的線程之間保持同步,是指不同的線程在執(zhí)行同一個(gè)對(duì)象的同步代碼塊時(shí)罩扇,因?yàn)橐@得對(duì)象的同步鎖而互相牽制)
2婆芦、 每個(gè)對(duì)象都有唯一的同步鎖
3、 在靜態(tài)方法前面可以使用synchronized修飾符。
4寞缝、 當(dāng)一個(gè)線程開(kāi)始執(zhí)行同步代碼塊時(shí)癌压,并不意味著必須以不間斷的方式運(yùn)行,進(jìn)入同步代碼塊的線程可以執(zhí)行Thread.sleep()或執(zhí)行Thread.yield()方法荆陆,此時(shí)它并不釋放對(duì)象鎖,只是把運(yùn)行的機(jī)會(huì)讓給其他的線程集侯。
5被啼、 Synchronized聲明不會(huì)被繼承,如果一個(gè)用synchronized修飾的方法被子類覆蓋棠枉,那么子類中這個(gè)方法不在保持同步浓体,除非用synchronized修飾。

釋放對(duì)象的鎖:
1辈讶、 執(zhí)行完同步代碼塊就會(huì)釋放對(duì)象的鎖
2命浴、 在執(zhí)行同步代碼塊的過(guò)程中,遇到異常而導(dǎo)致線程終止贱除,鎖也會(huì)被釋放
3生闲、 在執(zhí)行同步代碼塊的過(guò)程中,執(zhí)行了鎖所屬對(duì)象的wait()方法月幌,這個(gè)線程會(huì)釋放對(duì)象鎖碍讯,進(jìn)入對(duì)象的等待池。

死鎖:
線程1獨(dú)占(鎖定)資源A扯躺,等待獲得資源B后捉兴,才能繼續(xù)執(zhí)行
同時(shí)
線程2獨(dú)占(鎖定)資源B,等待獲得資源A后录语,才能繼續(xù)執(zhí)行
這樣就會(huì)發(fā)生死鎖倍啥,程序無(wú)法正常執(zhí)行

如何避免死鎖
一個(gè)通用的經(jīng)驗(yàn)法則是:當(dāng)幾個(gè)線程都要訪問(wèn)共享資源A、B澎埠、C 時(shí)虽缕,保證每個(gè)線程都按照同樣的順序去訪問(wèn)他們。


注意:
1失暂、線程同步就是線程排隊(duì)彼宠。同步就是排隊(duì)。線程同步的目的就是避免線程“同步”執(zhí)行弟塞。
2凭峡、只有共享資源的讀寫(xiě)訪問(wèn)才需要同步。如果不是共享資源决记,那么就根本沒(méi)有同步的必要摧冀。
3、只有“變量”才需要同步訪問(wèn)。如果共享的資源是固定不變的索昂,那么就相當(dāng)于“常量”建车,線程同時(shí)讀取常量也不需要同步。至少一個(gè)線程修改共享資源椒惨,這樣的情況下缤至,線程之間就需要同步。
4康谆、多個(gè)線程訪問(wèn)共享資源的代碼有可能是同一份代碼领斥,也有可能是不同的代碼;無(wú)論是否執(zhí)行同一份代碼沃暗,只要這些線程的代碼訪問(wèn)同一份可變的共享資源月洛,這些線程之間就需要同步。

5孽锥、我們要盡量避免這種直接把synchronized加在函數(shù)定義上的偷懶做法嚼黔。因?yàn)槲覀円刂仆搅6取M降拇a段越小越好惜辑。synchronized控制的范圍越小越好唬涧。

同步鎖:
我們可以給共享資源加一把鎖,這把鎖只有一把鑰匙韵丑。哪個(gè)線程獲取了這把鑰匙爵卒,才有權(quán)利訪問(wèn)該共享資源。
同步鎖不是加在共享資源上撵彻,而是加在訪問(wèn)共享資源的代碼段上钓株。
訪問(wèn)同一份共享資源的不同代碼段,應(yīng)該加上同一個(gè)同步鎖陌僵;如果加的是不同的同步鎖轴合,那么根本就起不到同步的作用,沒(méi)有任何意義碗短。
這就是說(shuō)受葛,同步鎖本身也一定是多個(gè)線程之間的共享對(duì)象。

三偎谁、生產(chǎn)者消費(fèi)者代碼示例

產(chǎn)品倉(cāng)庫(kù)

package com.danxx.javalib2;

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

/**
 * 數(shù)據(jù)存儲(chǔ)倉(cāng)庫(kù)和操作
 * 一個(gè)緩沖區(qū)总滩,緩沖區(qū)有最大限制,當(dāng)緩沖區(qū)滿
 * 的時(shí)候巡雨,生產(chǎn)者是不能將產(chǎn)品放入到緩沖區(qū)里面的闰渔,
 * 當(dāng)然,當(dāng)緩沖區(qū)是空的時(shí)候铐望,消費(fèi)者也不能從中拿出來(lái)產(chǎn)品冈涧,
 * 這就涉及到了在多線程中的條件判斷
 * Created by dawish on 2017/7/13.
 */
public class Storage {
    
    private static volatile int goodNumber = 1;
    
    private final static int MAX_SIZE = 20;
    /**
     *  Queue操作解析:
     *  add       增加一個(gè)元索                 如果隊(duì)列已滿茂附, 則拋出一個(gè)IIIegaISlabEepeplian異常
     *  remove    移除并返回隊(duì)列頭部的元素     如果隊(duì)列為空, 則拋出一個(gè)NoSuchElementException異常
     *  element   返回隊(duì)列頭部的元素           如果隊(duì)列為空督弓, 則拋出一個(gè)NoSuchElementException異常
     *  offer     添加一個(gè)元素并返回true       如果隊(duì)列已滿营曼, 則返回false
     *  poll      移除并返問(wèn)隊(duì)列頭部的元素     如果隊(duì)列為空, 則返回null
     *  peek      返回隊(duì)列頭部的元素           如果隊(duì)列為空愚隧, 則返回null
     *  put       添加一個(gè)元素                 如果隊(duì)列滿蒂阱,   則阻塞
     *  take      移除并返回隊(duì)列頭部的元素     如果隊(duì)列為空, 則阻塞
     *
     */
    Queue<String> storage;
    public Storage() {
        storage = new LinkedList<String>();
    }

    /**
     *
     * @param dataValue
     */
    public synchronized void put(String dataValue, String threadName){
        if(storage.size() >= MAX_SIZE){
            try {
                goodNumber = 1;
                super.wait();  //當(dāng)生產(chǎn)滿了后讓生產(chǎn)線程等待
                return;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        storage.add(dataValue + goodNumber++);
        System.out.println(threadName + dataValue + goodNumber);
        super.notify();  //每次添加一個(gè)數(shù)據(jù)就喚醒一個(gè)消費(fèi)等待的線程來(lái)消費(fèi)
    }

    /**
     *
     * @return
     * @throws InterruptedException
     */
    public synchronized String get(String threadName) {
        if(storage.size() == 0){
            try {
                super.wait();  //當(dāng)產(chǎn)品倉(cāng)庫(kù)為空的時(shí)候讓消費(fèi)線程等待
                System.out.println(threadName + "wait");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return null;
        }
        super.notify();  //當(dāng)數(shù)據(jù)不為空的時(shí)候就喚醒一個(gè)生產(chǎn)線程來(lái)生產(chǎn)
        String value = storage.remove();
        return value;
    }

}

生產(chǎn)者

package com.danxx.javalib2;

import java.util.UUID;

/**
 * 生產(chǎn)者
 * Created by dawish on 2017/7/13.
 */
public class Producer extends Thread{

    private Storage storage;//生產(chǎn)者倉(cāng)庫(kù)
    private String name="";
    
    public Producer(Storage storage, String name) {
        this.storage = storage;
        this.name = name;
    }
    public void run(){
        //生產(chǎn)者每隔1s生產(chǎn)1~100消息
        long oldTime = System.currentTimeMillis();
        while(true){
            synchronized(storage){
                if (System.currentTimeMillis() - oldTime >= 1000) {
                    oldTime = System.currentTimeMillis();
                    String msg = UUID.randomUUID().toString();
                    storage.put("-ID:" ,name);
                }
            }
        }
    }
}

消費(fèi)者

package com.danxx.javalib2;

/**
 * 消費(fèi)者
 * Created by dawish on 2017/7/13.
 */

public class Consumer extends Thread{

    private Storage storage;//倉(cāng)庫(kù)
    
    private String name="";
    
    public Consumer(Storage storage, String name) {
        this.storage = storage;
        this.name = name;
    }
    public void run(){
        while(true){
            synchronized(storage){
                //消費(fèi)者去倉(cāng)庫(kù)拿消息的時(shí)候狂塘,如果發(fā)現(xiàn)倉(cāng)庫(kù)數(shù)據(jù)為空蒜危,則等待
                String data = storage.get(name);
                if(data != null){
                    
                    System.out.println(name +"-------------"+ data);
                    
                }
            }
        }
    }
}

main方法

package com.danxx.javalib2;

/**
 *  Java中的多線程會(huì)涉及到線程間通信,常見(jiàn)的線程通信方式睹耐,例如共享變量、管道流等部翘,
 *  這里我們要實(shí)現(xiàn)生產(chǎn)者消費(fèi)者模式硝训,也需要涉及到線程通信,不過(guò)這里我們用到了java中的
 *  wait()新思、notify()方法:
 *  wait():進(jìn)入臨界區(qū)的線程在運(yùn)行到一部分后窖梁,發(fā)現(xiàn)進(jìn)行后面的任務(wù)所需的資源還沒(méi)有準(zhǔn)備充分,
 *  所以調(diào)用wait()方法夹囚,讓線程阻塞纵刘,等待資源,同時(shí)釋放臨界區(qū)的鎖荸哟,此時(shí)線程的狀態(tài)也從RUNNABLE狀態(tài)變?yōu)閃AITING狀態(tài)假哎;
 *  notify():準(zhǔn)備資源的線程在準(zhǔn)備好資源后,調(diào)用notify()方法通知需要使用資源的線程鞍历,
 *  同時(shí)釋放臨界區(qū)的鎖舵抹,將臨界區(qū)的鎖交給使用資源的線程。
 *  wait()劣砍、notify()這兩個(gè)方法惧蛹,都必須要在臨界區(qū)中調(diào)用,即是在synchronized同步塊中調(diào)用刑枝,
 *  不然會(huì)拋出IllegalMonitorStateException的異常香嗓。
 *  Created by dawish on 2017/7/14.
 */

public class MainApp {
    public static void main(String[] args) {
        Storage storage = new Storage();
        
        Producer producer1 = new Producer(storage, "Producer-1");
        Producer producer2 = new Producer(storage, "Producer-2");
        Producer producer3 = new Producer(storage, "Producer-3");
        Producer producer4 = new Producer(storage, "Producer-4");
        
        Consumer consumer1 = new Consumer(storage, "Consumer-1");
        Consumer consumer2 = new Consumer(storage, "Consumer-2");
        
        producer1.start();
        producer2.start();
        producer3.start();
        producer4.start();
        
        consumer1.start();
        consumer2.start();
    }
}

運(yùn)行結(jié)果(4個(gè)生產(chǎn)者2個(gè)消費(fèi)者)

這里寫(xiě)圖片描述

四、Github地址

https://github.com/Dawish/CustomViews/tree/master/JavaLib

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末装畅,一起剝皮案震驚了整個(gè)濱河市靠娱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌洁灵,老刑警劉巖饱岸,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掺出,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡苫费,警方通過(guò)查閱死者的電腦和手機(jī)汤锨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)百框,“玉大人闲礼,你說(shuō)我怎么就攤上這事☆砦” “怎么了柬泽?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)嫁蛇。 經(jīng)常有香客問(wèn)我锨并,道長(zhǎng),這世上最難降的妖魔是什么睬棚? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任第煮,我火速辦了婚禮,結(jié)果婚禮上抑党,老公的妹妹穿的比我還像新娘包警。我一直安慰自己,他們只是感情好底靠,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布害晦。 她就那樣靜靜地躺著,像睡著了一般暑中。 火紅的嫁衣襯著肌膚如雪壹瘟。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,772評(píng)論 1 290
  • 那天痒芝,我揣著相機(jī)與錄音俐筋,去河邊找鬼。 笑死严衬,一個(gè)胖子當(dāng)著我的面吹牛澄者,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播请琳,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼粱挡,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了俄精?” 一聲冷哼從身側(cè)響起询筏,我...
    開(kāi)封第一講書(shū)人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎竖慧,沒(méi)想到半個(gè)月后嫌套,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體逆屡,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年踱讨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了魏蔗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡痹筛,死狀恐怖莺治,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情帚稠,我是刑警寧澤谣旁,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站滋早,受9級(jí)特大地震影響榄审,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜杆麸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一瘟判、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧角溃,春花似錦、人聲如沸篮撑。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)赢笨。三九已至未蝌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間茧妒,已是汗流浹背萧吠。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留桐筏,地道東北人纸型。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像梅忌,于是被迫代替她去往敵國(guó)和親狰腌。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348

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