volatile和synchronized

1. volatile


  • 定義:Java編程語(yǔ)言允許線程訪問(wèn)共享變量涝桅,為了確保共享變量能被準(zhǔn)確和一致的更新,線程應(yīng)該確保通過(guò)排他鎖單獨(dú)獲得這個(gè)變量烙样。
  • 實(shí)現(xiàn)原理:

Java代碼如下:

instance = new Singleton();//instance是volatile變量

轉(zhuǎn)換成匯編代碼:

0x01a3de1d: movb $0x0,0x1104800(%esi);
0x01a3de24: lock addl $0x0,(%esp);

有volatile變量修飾的共享變量進(jìn)行寫(xiě)操作的時(shí)候會(huì)多第二行匯編代碼冯遂,lock前綴的指令在多核處理器下會(huì)引發(fā)了兩件事情。

  • 將當(dāng)前處理器緩存行的數(shù)據(jù)會(huì)寫(xiě)回到系統(tǒng)內(nèi)存谒获。
  • 這個(gè)寫(xiě)回內(nèi)存的操作會(huì)引起在其他CPU里緩存了該內(nèi)存地址的數(shù)據(jù)無(wú)效蛤肌。

處理器為了提高處理速度,不直接和內(nèi)存進(jìn)行通訊批狱,而是先將系統(tǒng)內(nèi)存的數(shù)據(jù)讀到內(nèi)部緩存(L1,L2或其他)后再進(jìn)行操作裸准,但操作完之后不知道何時(shí)會(huì)寫(xiě)到內(nèi)存,如果對(duì)聲明了Volatile變量進(jìn)行寫(xiě)操作赔硫,JVM就會(huì)向處理器發(fā)送一條Lock前綴的指令炒俱,將這個(gè)變量所在緩存行的數(shù)據(jù)寫(xiě)回到系統(tǒng)內(nèi)存。但是就算寫(xiě)回到內(nèi)存爪膊,如果其他處理器緩存的值還是舊的权悟,再執(zhí)行計(jì)算操作就會(huì)有問(wèn)題,所以在多處理器下推盛,為了保證各個(gè)處理器的緩存是一致的峦阁,就會(huì)實(shí)現(xiàn)緩存一致性協(xié)議,每個(gè)處理器通過(guò)嗅探在總線上傳播的數(shù)據(jù)來(lái)檢查自己緩存的值是不是過(guò)期了耘成,當(dāng)處理器發(fā)現(xiàn)自己緩存行對(duì)應(yīng)的內(nèi)存地址被修改榔昔,就會(huì)將當(dāng)前處理器的緩存行設(shè)置成無(wú)效狀態(tài),當(dāng)處理器要對(duì)這個(gè)數(shù)據(jù)進(jìn)行修改操作的時(shí)候凿跳,會(huì)強(qiáng)制重新從系統(tǒng)內(nèi)存里把數(shù)據(jù)讀到處理器緩存里件豌。


多線程CPU處理機(jī)制
  • volatile實(shí)現(xiàn)原則
  • Lock前綴指令會(huì)引起處理器緩存回寫(xiě)到內(nèi)存。
  • 一個(gè)處理器的緩存回寫(xiě)到內(nèi)存會(huì)導(dǎo)致其他處理器的緩存無(wú)效控嗜。
  • volatile使用條件

volatile變量具有 synchronized 的可見(jiàn)性特性茧彤,但是不具備原子性。這就是說(shuō)線程能夠自動(dòng)發(fā)現(xiàn) volatile 變量的最新值疆栏。只能在有限的一些情形下使用 volatile 曾掂。要使 volatile 變量提供理想的線程安全,必須同時(shí)滿足下面兩個(gè)條件:

  • 對(duì)變量的寫(xiě)操作不依賴(lài)于當(dāng)前值壁顶。
  • 該變量沒(méi)有包含在具有其他變量的不變式中珠洗。

反例:volatile變量不能用于約束條件中,下面是一個(gè)非線程安全的數(shù)值范圍類(lèi)若专。它包含了一個(gè)不變式 —— 下界總是小于或等于上界许蓖。

public class NumberRange {  
    private volatile int lower;
    private volatile int upper; 
    public int getLower() { return lower; }  
    public int getUpper() { return upper; }  
  
    public void setLower(int value) {   
        if (value > upper)   
            throw new IllegalArgumentException(...);  
        lower = value;  
    }  
  
    public void setUpper(int value) {   
        if (value < lower)   
            throw new IllegalArgumentException(...);  
        upper = value;  
    }  
}

將 lower 和 upper 字段定義為 volatile 類(lèi)型不能夠充分實(shí)現(xiàn)類(lèi)的線程安全;而仍然需要使用同步——使 setLower()和 setUpper() 操作原子化。否則膊爪,如果湊巧兩個(gè)線程在同一時(shí)間使用不一致的值執(zhí)行 setLower 和 setUpper 的話自阱,則會(huì)使范圍處于不一致的狀態(tài)。例如米酬,如果初始狀態(tài)是(0, 5)沛豌,同一時(shí)間內(nèi),線程 A 調(diào)用setLower(4) 并且線程 B 調(diào)用setUpper(3)赃额,顯然這兩個(gè)操作交叉存入的值是不符合條件的加派,那么兩個(gè)線程都會(huì)通過(guò)用于保護(hù)不變式的檢查,使得最后的范圍值是(4, 3) —— 一個(gè)無(wú)效值

  • volatile的適用場(chǎng)景

狀態(tài)標(biāo)志:也許實(shí)現(xiàn) volatile 變量的規(guī)范使用僅僅是使用一個(gè)布爾狀態(tài)標(biāo)志跳芳,用于指示發(fā)生了一個(gè)重要的一次性事件芍锦,例如完成初始化或請(qǐng)求停機(jī)。

volatile boolean isShutdown;  
...    
public void shutdown() {   
    isShutdown = true;   
}  
  
public void doWork() {   
    while (!isShutdown) {   
        // do stuff  
    }  
}

線程1執(zhí)行doWork()的過(guò)程中筛严,可能有另外的線程2調(diào)用了shutdown醉旦,所以boolean變量必須是volatile。
這種類(lèi)型的狀態(tài)標(biāo)記的一個(gè)公共特性是:通常只有一種狀態(tài)轉(zhuǎn)換桨啃;shutdownRequested 標(biāo)志從false 轉(zhuǎn)換為true,然后程序停止檬输。

開(kāi)銷(xiāo)較低的“讀-寫(xiě)鎖”策略:如果讀操作遠(yuǎn)遠(yuǎn)超過(guò)寫(xiě)操作照瘾,您可以結(jié)合使用內(nèi)部鎖和 volatile 變量來(lái)減少公共代碼路徑的開(kāi)銷(xiāo)。
如下顯示的線程安全的計(jì)數(shù)器丧慈,使用 synchronized 確保增量操作是原子的析命,并使用 volatile 保證當(dāng)前結(jié)果的可見(jiàn)性。如果更新不頻繁的話逃默,該方法可實(shí)現(xiàn)更好的性能鹃愤,因?yàn)樽x路徑的開(kāi)銷(xiāo)僅僅涉及 volatile 讀操作,這通常要優(yōu)于一個(gè)無(wú)競(jìng)爭(zhēng)的鎖獲取的開(kāi)銷(xiāo)完域。

public class CheesyCounter {  
    // Employs the cheap read-write lock trick  
    // All mutative operations MUST be done with the 'this' lock held  
    @GuardedBy("this") private volatile int value;  
  
    //讀操作软吐,沒(méi)有synchronized,提高性能  
    public int getValue() {   
        return value;   
    }   
  
    //寫(xiě)操作吟税,必須synchronized凹耙。因?yàn)閤++不是原子操作  
    public synchronized int increment() {  
        return value++;  
    }  
}

使用鎖進(jìn)行所有變化的操作,使用 volatile 進(jìn)行只讀操作肠仪。
其中肖抱,鎖一次只允許一個(gè)線程訪問(wèn)值,volatile 允許多個(gè)線程執(zhí)行讀操作异旧。

2. synchronized


  • 介紹
    • 在多線程并發(fā)編程中synchronized一直是元老級(jí)角色意述,很多人都會(huì)稱(chēng)呼它為重量級(jí)鎖,但是隨著Java SE1.6對(duì)Synchronized進(jìn)行了各種優(yōu)化之后,有些情況下它并不那么重了荤崇。Java SE1.6中為了減少獲得鎖和釋放鎖帶來(lái)的性能消耗而引入的偏向鎖和輕量級(jí)鎖拌屏,以及鎖的存儲(chǔ)結(jié)構(gòu)和升級(jí)過(guò)程。

    • 關(guān)鍵字synchronized可以修飾方法或者以同步塊的形式來(lái)使用天试,他主要確保多個(gè)線程在同一個(gè)時(shí)刻槐壳,只能有一個(gè)線程處于方法或者同步塊中,他保證了線程對(duì)變量訪問(wèn)的可見(jiàn)性和排他性喜每。

  • synchronized特點(diǎn)

    把代碼塊聲明為 synchronized务唐,有兩個(gè)重要后果,通常是指該代碼具有原子性(atomicity)可見(jiàn)性(visibility)带兜。

    • 原子性意味著個(gè)時(shí)刻枫笛,只有一個(gè)線程能夠執(zhí)行一段代碼,這段代碼通過(guò)一個(gè)monitor object保護(hù)刚照。從而防止多個(gè)線程在更新共享狀態(tài)時(shí)相互沖突刑巧。 所謂原子性操作是指不會(huì)被線程調(diào)度機(jī)子打斷的操作,這種操作一旦開(kāi)始无畔,就一直到幸運(yùn)星結(jié)束啊楚,中間不會(huì)有任何切換(切換線程)。
    • 可見(jiàn)性則更為微妙浑彰,它必須確保釋放鎖之前對(duì)共享數(shù)據(jù)做出的更改對(duì)于隨后獲得該鎖的另一個(gè)線程是可見(jiàn)的恭理。 —— 如果沒(méi)有同步機(jī)制提供的這種可見(jiàn)性保證,線程看到的共享變量可能是修改前的值或不一致的值郭变,這將引發(fā)許多嚴(yán)重問(wèn)題颜价。
  • synchronized實(shí)現(xiàn)同步的基礎(chǔ)

Java中的每一個(gè)對(duì)象都可以作為鎖。具體表現(xiàn)為一下3中形式:

  • 對(duì)于普通的同步方法诉濒,鎖是當(dāng)先實(shí)例對(duì)象周伦。
  • 對(duì)于靜態(tài)同步方法,鎖是當(dāng)前類(lèi)的Class對(duì)象未荒。
  • 對(duì)于同步方法塊专挪,鎖是Synchronized括號(hào)里配置的對(duì)象。

示例代碼:

public class SynchronizedTest2 {  
      
    // synchronized關(guān)鍵字修飾靜態(tài)的方法 同步方法  
    public synchronized static void printNum1(){   
        for(int i = 0; i < 10; i++) {  
            System.out.println(Thread.currentThread().getName() + " " + i);  
        }  
    }  
      
    // synchronized關(guān)鍵字使用類(lèi)鎖   同步代碼塊  
    public static void printNum2(){   
        synchronized(SynchronizedTest2.class) {  
            for(int i = 0; i < 10; i++) {  
                System.out.println(Thread.currentThread().getName() + " " + i);  
            }  
        }  
    }  
      
    // synchronized關(guān)鍵字修飾 同步方法  這里使用的是對(duì)象鎖  
    public synchronized void printNum3(){   
        for(int i = 0; i < 10; i++) {  
            System.out.println(Thread.currentThread().getName() + " " + i);  
        }  
    }  
      
    public static void main(String[] args) {  
        // TODO Auto-generated method stub  
        final SynchronizedTest2 test = new SynchronizedTest2();  
        Thread t1 = new Thread(new Runnable() {  
            public void run() {  
                SynchronizedTest2.printNum1();  
            }  
        },"A");  
          
        Thread t2 = new Thread(new Runnable() {  
            public void run() {  
                SynchronizedTest2.printNum2();  
            }  
        },"B");  
          
        Thread t3 = new Thread(new Runnable() {  
            public void run() {  
                test.printNum3();  
            }  
        },"C");  
        t1.start();  
        t2.start();  
        t3.start();  
    }  
}  
  • 以上代碼中 靜態(tài)方法printNum1() 和 printNum2() 使用的都是類(lèi)鎖茄猫,方法printNum3()使用的是當(dāng)前對(duì)象的鎖狈蚤。

  • 我們開(kāi)了三個(gè)線程A,B,C分別運(yùn)行printNum1(),printNum2()划纽,printNum3()方法 從結(jié)果中我們可以看到 線程A和線程B是始終同步的脆侮,線程C和線程A,B之間沒(méi)有同步關(guān)系

  • 實(shí)現(xiàn)原理

    示例代碼: Synchronized.java

public class Synchronized {

    public static void main(String[] args) {
        synchronized (Synchronized.class){//對(duì)Synchronized class對(duì)象進(jìn)行加鎖
            
        }
        m();//靜態(tài)同步方法,對(duì)Synchronized class對(duì)象進(jìn)行加鎖
    }

    public synchronized static void m() {

    }
}

在Synchronized.class同級(jí)目錄執(zhí)行javap -v Synchronized.class勇劣,以下是相關(guān)部分的輸出:

public static void main(java.lang.String[]);  
// 方法修飾符靖避,表示:public staticflags: ACC_PUBLIC, ACC_STATIC  
Code:  
stack=2, locals=1, args_size=1  
0: ldc #1  // class com/murdock/books/multithread/book/Synchronized  
2: dup  
3: monitorenter  // monitorenter:監(jiān)視器進(jìn)入潭枣,獲取鎖  
4: monitorexit   // monitorexit:監(jiān)視器退出,釋放鎖  
5: invokestatic  #16 // Method m:()V  
8: return  
public static synchronized void m();  
// 方法修飾符幻捏,表示: public static synchronized  
flags: ACC_PUBLIC, ACC_STATIC, ACC_SYNCHRONIZED  
Code:  
stack=0, locals=0, args_size=0  
0: return 
  • 上面class信息中盆犁,對(duì)于同步塊的實(shí)現(xiàn)使用了monitorenter和monitorexit指令,而同步方法則是依靠方法修飾符上的ACC_SYNCHRONIZED來(lái)完成的篡九。無(wú)論采用哪種方式谐岁,其本質(zhì)是對(duì)一個(gè)對(duì)象的監(jiān)視器(monitor)進(jìn)行獲取,而這個(gè)獲取過(guò)程是排他的榛臼,也就是同一時(shí)刻只能有一個(gè)線程獲取到由synchronized所保護(hù)對(duì)象的監(jiān)視器伊佃。
  • 任意一個(gè)對(duì)象都擁有自己的監(jiān)視器,當(dāng)這個(gè)對(duì)象由同步塊或者這個(gè)對(duì)象的同步方法調(diào)用時(shí)沛善,執(zhí)行方法的線程必須先獲取到該對(duì)象的監(jiān)視器才能進(jìn)入同步塊或者同步方法航揉,而沒(méi)有獲取到監(jiān)視器(執(zhí)行該方法)的線程將會(huì)被阻塞在同步塊和同步方法的入口處,進(jìn)入BLOCKED狀態(tài)金刁。

下圖描述了對(duì)象帅涂、對(duì)象的監(jiān)視器、同步隊(duì)列和執(zhí)行線程之間的關(guān)系尤蛮。



從圖中可以看到媳友,任意線程對(duì)Object(Object由synchronized保護(hù))的訪問(wèn),首先要獲得Object的監(jiān)視器产捞。如果獲取失敗庆锦,線程進(jìn)入同步隊(duì)列,線程狀態(tài)變?yōu)锽LOCKED轧葛。當(dāng)訪問(wèn)Object的前驅(qū)(獲得了鎖的線程)釋放了鎖,則該釋放操作喚醒阻塞在同步隊(duì)列中的線程艇搀,使其重新嘗試對(duì)監(jiān)視器的獲取尿扯。

  • 線程等待/同步機(jī)制

等待/通知機(jī)制,是指一個(gè)線程A調(diào)用了對(duì)象O的wait()方法進(jìn)入等待狀態(tài)焰雕,而另一個(gè)線程B調(diào)用了對(duì)象O的notify()或者notifyAll()方法衷笋,線程A收到通知后從對(duì)象O的wait()方法返回,進(jìn)而執(zhí)行后續(xù)操作矩屁。上述兩個(gè)線程通過(guò)對(duì)象O來(lái)完成交互辟宗,而對(duì)象上的wait()和notify/notifyAll()的關(guān)系就如同開(kāi)關(guān)信號(hào)一樣,用來(lái)完成等待方和通知方之間的交互工作吝秕。

下面我們直接使用對(duì)象鎖的相關(guān)條件實(shí)現(xiàn)一個(gè)生產(chǎn)者和消費(fèi)者案例:

public class SynchronizedTest3 {  
      
    private Object object = new Object();  
      
    private List<Integer> list = new ArrayList<Integer>();  
      
    private boolean flag = true;  
      
      
    // 這里我們使用object對(duì)象的鎖泊脐,以及該鎖的條件對(duì)象  
    // 生產(chǎn)者線程一次生產(chǎn)一個(gè)數(shù)據(jù)5  
    public void produce() throws InterruptedException {  
        synchronized(object) {  
            while(flag){  
                if (list.size() > 0){  
                    object.wait();  
                } else {  
                    list.add(5);  
                    System.out.println("生產(chǎn)者生產(chǎn)數(shù)據(jù)");  
                    object.notifyAll();  
                }  
            }  
        }  
          
    }  
      
    // 消費(fèi)者線程每次消費(fèi)一個(gè)數(shù)據(jù)  
    public void consume() throws InterruptedException {  
        synchronized(object){  
            while(flag){  
                if (list.size() <= 0) {  
                    object.wait();  
                } else {  
                    System.out.println(list.remove(0));  
                    System.out.println("消費(fèi)者消費(fèi)數(shù)據(jù)");  
                    object.notifyAll();  
                }  
            }  
        }  
    }  
      
      
      
    public boolean isFlag() {  
        return flag;  
    }  
  
    public void setFlag(boolean flag) {  
        this.flag = flag;  
    }  
  
    public static void main(String[] args) {  
        // TODO Auto-generated method stub  
        final SynchronizedTest3 test = new SynchronizedTest3();  
        Thread t1 = new Thread(new Runnable() {  
            public void run() {  
                try {  
                    test.produce();  
                } catch (InterruptedException e) {  
                    // TODO Auto-generated catch block  
                    e.printStackTrace();  
                }  
            }  
        });  
          
        Thread t2 = new Thread(new Runnable() {  
            public void run() {  
                try {  
                    test.consume();  
                } catch (InterruptedException e) {  
                    // TODO Auto-generated catch block  
                    e.printStackTrace();  
                }  
            }  
        });  
          
        t1.start();  
        t2.start();  
          
        try {  
            Thread.sleep(10);  
        } catch (InterruptedException e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        }  
        test.setFlag(false);  
    }  
  
}  
  • 生產(chǎn)者線程檢查容器list中是否有數(shù)據(jù),如果有數(shù)據(jù)則調(diào)用object.wait()使得生產(chǎn)者線程進(jìn)入該條件的等待集中烁峭,如果容器中沒(méi)有數(shù)據(jù)容客,則生產(chǎn)者線程生產(chǎn)數(shù)據(jù)放入list中秕铛,讓后調(diào)用object.notifyAll()方法從該條件等待集中所有線程的阻塞狀態(tài)。
  • 消費(fèi)者線程檢查容器中是否有數(shù)據(jù)缩挑,如果有數(shù)據(jù)則消費(fèi)數(shù)據(jù)然后調(diào)用notifyAll()方法但两,是的處于該條件等待集中的生產(chǎn)者線程解除阻塞狀態(tài)。如果沒(méi)有數(shù)據(jù)調(diào)用object.wait()方法是的消費(fèi)者線程進(jìn)入該條件的等待集中供置。

下圖描述了上述示例的全過(guò)程谨湘。


等待通知機(jī)制
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市芥丧,隨后出現(xiàn)的幾起案子紧阔,更是在濱河造成了極大的恐慌,老刑警劉巖娄柳,帶你破解...
    沈念sama閱讀 222,183評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件寓辱,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡赤拒,警方通過(guò)查閱死者的電腦和手機(jī)秫筏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)挎挖,“玉大人这敬,你說(shuō)我怎么就攤上這事〗抖洌” “怎么了崔涂?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,766評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)始衅。 經(jīng)常有香客問(wèn)我冷蚂,道長(zhǎng),這世上最難降的妖魔是什么汛闸? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,854評(píng)論 1 299
  • 正文 為了忘掉前任蝙茶,我火速辦了婚禮,結(jié)果婚禮上诸老,老公的妹妹穿的比我還像新娘隆夯。我一直安慰自己,他們只是感情好别伏,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布蹄衷。 她就那樣靜靜地躺著,像睡著了一般厘肮。 火紅的嫁衣襯著肌膚如雪愧口。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,457評(píng)論 1 311
  • 那天轴脐,我揣著相機(jī)與錄音调卑,去河邊找鬼抡砂。 笑死,一個(gè)胖子當(dāng)著我的面吹牛恬涧,可吹牛的內(nèi)容都是我干的注益。 我是一名探鬼主播,決...
    沈念sama閱讀 40,999評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼溯捆,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼丑搔!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起提揍,我...
    開(kāi)封第一講書(shū)人閱讀 39,914評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤啤月,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后劳跃,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體谎仲,經(jīng)...
    沈念sama閱讀 46,465評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評(píng)論 3 342
  • 正文 我和宋清朗相戀三年刨仑,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了郑诺。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,675評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡杉武,死狀恐怖辙诞,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情轻抱,我是刑警寧澤飞涂,帶...
    沈念sama閱讀 36,354評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站祈搜,受9級(jí)特大地震影響较店,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜容燕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評(píng)論 3 335
  • 文/蒙蒙 一泽西、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧缰趋,春花似錦、人聲如沸陕见。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,514評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)评甜。三九已至灰粮,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間忍坷,已是汗流浹背粘舟。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,616評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工熔脂, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人柑肴。 一個(gè)月前我還...
    沈念sama閱讀 49,091評(píng)論 3 378
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親慕蔚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子余爆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評(píng)論 2 360

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