jps & jstack

本文的初衷僅供自己做備忘筆記, 內(nèi)容大多從網(wǎng)上搜集和整理, 并非都是自己原創(chuàng).
參考的來源我會在后面注明, 對于可能遺漏的來源, 還請相關原創(chuàng)作者提醒, 非常感謝.

參考來源:
https://www.cnblogs.com/michael-xiang/p/10779566.html
https://www.iteye.com/blog/crane-ding-968862
https://blog.csdn.net/wufaliang003/article/details/80414267

拜讀了三位博主的發(fā)文, 感覺很實用, 故記錄下來.

java自帶的常用工具

JDK本身提供了很多方便的JVM性能調(diào)優(yōu)監(jiān)控工具粹湃,除了集成式的VisualVM和jConsole外, 還有jps、jstack胖喳、jmap仙粱、jhat藕届、jstat勺鸦、hprof等小巧的工具妨退,每一種工具都有其自身的特點讽坏, 用戶可以根據(jù)你需要檢測的應用或者程序片段的狀況锭魔,適當?shù)倪x擇相應的工具進行檢測, 先通過一個表格形式簡要介紹下這幾個命令的作用和使用方法路呜。

命令 作用
jps 基礎工具
jstack 查看某個Java進程內(nèi)的線程堆棧信息
jmap jmap導出堆內(nèi)存迷捧,然后使用jhat來進行分析
jhat 主要用來解析java堆dump并啟動一個web服務器,然后就可以在瀏覽器中查看堆的dump文件
jstat 主要是對java應用程序的資源和性能進行實時的命令行監(jiān)控胀葱,包括了對heap size和垃圾回收狀況的監(jiān)控
hprof hprof能夠展現(xiàn)CPU使用率漠秋,統(tǒng)計堆內(nèi)存使用情況

jps

jps 全稱 JVM Process Status Tool,命令位于 jdk 的 bin 目錄下抵屿,其作用是顯示當前系統(tǒng)的 Java 進程情況膛堤,及其 pid 號。他是 Java自帶的一個命令晌该。
jps 命令用來查看所有 Java 進程肥荔,每一行就是一個 Java 進程信息。

jps 僅查找當前用戶的 Java 進程朝群,而不是當前系統(tǒng)中的所有進程燕耿,要顯示其他用戶的還只能用 ps 命令。

jps 常用參數(shù)
第一列的數(shù)字就是進程的 pid

  • jps -l
    如果是以 class 方式運行姜胖,會顯示進程的主類 main.class 的全名誉帅,如果是以 jar 包方式運行的,就會輸出 jar 包的完整路徑名
root@VM-1-3-ubuntu:/home/wechatCrawlerJava# jps
5409 Jps
4172 chapter5-0.0.1-SNAPSHOT.jar
root@VM-1-3-ubuntu:/home/wechatCrawlerJava# jps -l
6629 sun.tools.jps.Jps
4172 ./chapter5-0.0.1-SNAPSHOT.jar
  • jps -v
    輸出傳遞給 JVM 的參數(shù)右莱,v 表示虛擬機蚜锨,jps -vl 比較常見的組合;
  • jps -V
    大寫 v慢蜓,表示通過文件傳遞給 JVM 的參數(shù)
# michael @ Michael-MBP in ~ [16:37:59]
$ jps -v |grep Mybatis
8005 MybatisDemoApplication -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:53364,suspend=y,server=n -XX:TieredStopAtLevel=1 -Xverify:none -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=53363 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=127.0.0.1 -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true -javaagent:/Users/michael/Library/Caches/IntelliJIdea2018.2/captureAgent/debugger-agent.jar=file:/private/var/folders/m1/ydypchs901lffc5sms07mrp40000gn/T/capture.props -Dfile.encoding=UTF-8
  • jps -m
    輸出傳遞給 main.class 方法的參數(shù)亚再,實用的一個命令,jps -ml 比較實用的組合晨抡,會顯示包名/類名/參數(shù)
  • jps -q
    只輸出進程的 pid

jstack

簡介

jstack是java虛擬機自帶的一種堆棧跟蹤工具氛悬。
jstack用于生成java虛擬機當前時刻的線程快照则剃。線程快照是當前java虛擬機內(nèi)每一條線程正在執(zhí)行的方法堆棧的集合,生成線程快照的主要目的是定位線程出現(xiàn)長時間停頓的原因如捅,如線程間死鎖棍现、死循環(huán)、請求外部資源導致的長時間等待等镜遣。 線程出現(xiàn)停頓的時候通過jstack來查看各個線程的調(diào)用堆棧己肮,就可以知道沒有響應的線程到底在后臺做什么事情,或者等待什么資源悲关。 如果java程序崩潰生成core文件朴肺,jstack工具可以用來獲得core文件的java stack和native stack的信息,從而可以輕松地知道java程序是如何崩潰和在程序何處發(fā)生問題坚洽。另外戈稿,jstack工具還可以附屬到正在運行的java程序中,看到當時運行的java程序的java stack和native stack的信息, 如果現(xiàn)在運行的java程序呈現(xiàn)hung的狀態(tài)讶舰,jstack是非常有用的鞍盗。
jstack命令主要用來查看Java線程的調(diào)用堆棧的,可以用來分析線程問題(如死鎖)跳昼。

jstack命令

Usage:
    jstack [-l] <pid>
        (to connect to running process)
    jstack -F [-m] [-l] <pid>
        (to connect to a hung process)
    jstack [-m] [-l] <executable> <core>
        (to connect to a core file)
    jstack [-m] [-l] [server_id@]<remote server IP or hostname>
        (to connect to a remote debug server)

Options:
    -F  to force a thread dump. Use when jstack <pid> does not respond (process is hung)
    -m  to print both java and native frames (mixed mode)
    -l  long listing. Prints additional information about locks
    -h or -help to print this help message

-F 當’jstack [-l] pid’沒有相應的時候強制打印棧信息,如果直接jstack無響應時般甲,用于強制jstack,一般情況不需要使用
-l 長列表. 打印關于鎖的附加信息,例如屬于java.util.concurrent的ownable synchronizers列表鹅颊,會使得JVM停頓得長久得多 (可能會差很多倍敷存,比如普通的jstack可能幾毫秒和一次GC沒區(qū)別,加了-l 就是近一秒的時間)堪伍,-l 建議不要用锚烦。一般情況不需要使用
-m 打印java和native c/c++ 框架的所有棧信息.可以打印JVM的堆棧,顯示上Native的棧幀,一般應用排查不需要使用

執(zhí)行命令:

 jstack -m 12905

線程狀態(tài)

想要通過jstack命令來分析線程的情況的話帝雇,首先要知道線程都有哪些狀態(tài)涮俄,下面這些狀態(tài)是我們使用jstack命令查看線程堆棧信息時可能會看到的線程的幾種狀態(tài):

  • NEW,未啟動的。不會出現(xiàn)在Dump中尸闸。
  • RUNNABLE,在虛擬機內(nèi)執(zhí)行的彻亲。
  • BLOCKED,受阻塞并等待監(jiān)視器鎖。
  • WATING,無限期等待另一個線程執(zhí)行特定操作吮廉。
  • TIMED_WATING,有時限的等待另一個線程的特定操作苞尝。
  • TERMINATED,已退出的。

Monitor

在多線程的 JAVA程序中宦芦,實現(xiàn)線程之間的同步宙址,就要說說 Monitor。 Monitor是 Java中用以實現(xiàn)線程之間的互斥與協(xié)作的主要手段踪旷,它可以看成是對象或者 Class的鎖曼氛。每一個對象都有,也僅有一個 monitor令野。下 面這個圖舀患,描述了線程和 Monitor之間關系,以 及線程的狀態(tài)轉(zhuǎn)換圖:


7e99e25b.png
  • 進入?yún)^(qū)(Entrt Set):表示線程通過synchronized要求獲取對象的鎖气破。如果對象未被鎖住,則迚入擁有者;否則則在進入?yún)^(qū)等待聊浅。一旦對象鎖被其他線程釋放,立即參與競爭。
  • 擁有者(The Owner):表示某一線程成功競爭到對象鎖现使。
  • 等待區(qū)(Wait Set):表示線程通過對象的wait方法,釋放對象的鎖,并在等待區(qū)等待被喚醒低匙。

從圖中可以看出,一個 Monitor在某個時刻碳锈,只能被一個線程擁有顽冶,該線程就是 “Active Thread”,而其它線程都是 “Waiting Thread”售碳,分別在兩個隊列 “ Entry Set”和 “Wait Set”里面等候强重。在 “Entry Set”中等待的線程狀態(tài)是 “Waiting for monitor entry”,而在 “Wait Set”中等待的線程狀態(tài)是 “in Object.wait()”贸人。 先看 “Entry Set”里面的線程间景。我們稱被 synchronized保護起來的代碼段為臨界區(qū)。當一個線程申請進入臨界區(qū)時艺智,它就進入了 “Entry Set”隊列倘要。對應的 code就像:

synchronized(obj) {
.........

}

調(diào)用修飾

表示線程在方法調(diào)用時,額外的重要的操作。線程Dump分析的重要信息十拣。修飾上方的方法調(diào)用封拧。

  • locked <地址> 目標:使用synchronized申請對象鎖成功,監(jiān)視器的擁有者。
  • waiting to lock <地址> 目標:使用synchronized申請對象鎖未成功,在迚入?yún)^(qū)等待夭问。
  • waiting on <地址> 目標:使用synchronized申請對象鎖成功后,釋放鎖幵在等待區(qū)等待哮缺。
  • parking to wait for <地址> 目標
locked
at oracle.jdbc.driver.PhysicalConnection.prepareStatement
- locked <0x00002aab63bf7f58> (a oracle.jdbc.driver.T4CConnection)
at oracle.jdbc.driver.PhysicalConnection.prepareStatement
- locked <0x00002aab63bf7f58> (a oracle.jdbc.driver.T4CConnection)
at com.jiuqi.dna.core.internal.db.datasource.PooledConnection.prepareStatement

通過synchronized關鍵字,成功獲取到了對象的鎖,成為監(jiān)視器的擁有者,在臨界區(qū)內(nèi)操作。對象鎖是可以線程重入的甲喝。

waiting to lock
at com.jiuqi.dna.core.impl.CacheHolder.isVisibleIn(CacheHolder.java:165)
- waiting to lock <0x0000000097ba9aa8> (a CacheHolder)
at com.jiuqi.dna.core.impl.CacheGroup$Index.findHolder
at com.jiuqi.dna.core.impl.ContextImpl.find
at com.jiuqi.dna.bap.basedata.common.util.BaseDataCenter.findInfo

通過synchronized關鍵字,沒有獲取到了對象的鎖,線程在監(jiān)視器的進入?yún)^(qū)等待尝苇。在調(diào)用棧頂出現(xiàn),線程狀態(tài)為Blocked。

waiting on
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000da2defb0> (a WorkingThread)
at com.jiuqi.dna.core.impl.WorkingManager.getWorkToDo
- locked <0x00000000da2defb0> (a WorkingThread)
at com.jiuqi.dna.core.impl.WorkingThread.run

通過synchronized關鍵字,成功獲取到了對象的鎖后,調(diào)用了wait方法,進入對象的等待區(qū)等待埠胖。在調(diào)用棧頂出現(xiàn),線程狀態(tài)為WAITING或TIMED_WATING糠溜。

parking to wait for

park是基本的線程阻塞原語,不通過監(jiān)視器在對象上阻塞。隨concurrent包會出現(xiàn)的新的機制,不synchronized體系不同直撤。

線程動作

線程狀態(tài)產(chǎn)生的原因

  • runnable:狀態(tài)一般為RUNNABLE非竿。
  • in Object.wait():等待區(qū)等待,狀態(tài)為WAITING或TIMED_WAITING。
  • waiting for monitor entry:進入?yún)^(qū)等待,狀態(tài)為BLOCKED谋竖。
  • waiting on condition:等待區(qū)等待红柱、被park承匣。
  • sleeping:休眠的線程,調(diào)用了Thread.sleep()。

Wait on condition 該狀態(tài)出現(xiàn)在線程等待某個條件的發(fā)生锤悄。具體是什么原因韧骗,可以結合 stacktrace來分析。 最常見的情況就是線程處于sleep狀態(tài)零聚,等待被喚醒袍暴。 常見的情況還有等待網(wǎng)絡IO:在java引入nio之前,對于每個網(wǎng)絡連接隶症,都有一個對應的線程來處理網(wǎng)絡的讀寫操作政模,即使沒有可讀寫的數(shù)據(jù),線程仍然阻塞在讀寫操作上蚂会,這樣有可能造成資源浪費淋样,而且給操作系統(tǒng)的線程調(diào)度也帶來壓力。在 NewIO里采用了新的機制胁住,編寫的服務器程序的性能和可擴展性都得到提高习蓬。 正等待網(wǎng)絡讀寫,這可能是一個網(wǎng)絡瓶頸的征兆措嵌。因為網(wǎng)絡阻塞導致線程無法執(zhí)行躲叼。一種情況是網(wǎng)絡非常忙,幾 乎消耗了所有的帶寬企巢,仍然有大量數(shù)據(jù)等待網(wǎng)絡讀 寫枫慷;另一種情況也可能是網(wǎng)絡空閑,但由于路由等問題浪规,導致包無法正常的到達或听。所以要結合系統(tǒng)的一些性能觀察工具來綜合分析,比如 netstat統(tǒng)計單位時間的發(fā)送包的數(shù)目笋婿,如果很明顯超過了所在網(wǎng)絡帶寬的限制 ; 觀察 cpu的利用率誉裆,如果系統(tǒng)態(tài)的 CPU時間,相對于用戶態(tài)的 CPU時間比例較高缸濒;如果程序運行在 Solaris 10平臺上足丢,可以用 dtrace工具看系統(tǒng)調(diào)用的情況,如果觀察到 read/write的系統(tǒng)調(diào)用的次數(shù)或者運行時間遙遙領先庇配;這些都指向由于網(wǎng)絡帶寬所限導致的網(wǎng)絡瓶頸斩跌。

死鎖例子

jstack [-l] <pid>, pid可以通過使用jps命令來查看當前Java程序的pid值,-l是可選參數(shù),它可以顯示線程阻塞/死鎖情況。

/** 
 * 死鎖例子 
 * @author crane.ding 
 * @since 2011-3-20 
 */  
public class DeadLock {  

    public static void main(String[] args) {  
        final Object obj_1 = new Object(), obj_2 = new Object();  

        Thread t1 = new Thread("t1"){  
            @Override  
            public void run() {  
                synchronized (obj_1) {  
                    try {  
                        Thread.sleep(3000);  
                    } catch (InterruptedException e) {}  

                    synchronized (obj_2) {  
                        System.out.println("thread t1 done.");  
                    }  
                }  
            }  
        };  

        Thread t2 = new Thread("t2"){  
            @Override  
            public void run() {  
                synchronized (obj_2) {  
                    try {  
                        Thread.sleep(3000);  
                    } catch (InterruptedException e) {}  

                    synchronized (obj_1) {  
                        System.out.println("thread t2 done.");  
                    }  
                }  
            }  
        };  

        t1.start();  
        t2.start();  
    }  
}  

以上DeadLock類是一個死鎖的例子,假使在我們不知情的情況下,運行DeadLock后,發(fā)現(xiàn)等了N久都沒有在屏幕打印線程完成信息捞慌。這個時候我們就可以使用jps查看該程序的jpid值和使用jstack來生產(chǎn)堆棧結果問題耀鸦。

$ java -cp deadlock.jar DeadLock &  
$   
$ jps  
  3076 Jps  
  448 DeadLock  
$ jstack -l 448 > deadlock.jstack  

結果文件deadlock.jstack內(nèi)容如下:

2011-03-20 23:05:20  
Full thread dump Java HotSpot(TM) Client VM (19.1-b02 mixed mode, sharing):  

"DestroyJavaVM" prio=6 tid=0x00316800 nid=0x9fc waiting on condition [0x00000000]  
   java.lang.Thread.State: RUNNABLE  

   Locked ownable synchronizers:  
    - None  

"t2" prio=6 tid=0x02bcf000 nid=0xc70 waiting for monitor entry [0x02f6f000]  
   java.lang.Thread.State: BLOCKED (on object monitor)  
    at com.demo.DeadLock$2.run(DeadLock.java:40)  
    - waiting to lock <0x22a297a8> (a java.lang.Object)  
    - locked <0x22a297b0> (a java.lang.Object)  

   Locked ownable synchronizers:  
    - None  

"t1" prio=6 tid=0x02bce400 nid=0xba0 waiting for monitor entry [0x02f1f000]  
   java.lang.Thread.State: BLOCKED (on object monitor)  
    at com.demo.DeadLock$1.run(DeadLock.java:25)  
    - waiting to lock <0x22a297b0> (a java.lang.Object)  
    - locked <0x22a297a8> (a java.lang.Object)  

   Locked ownable synchronizers:  
    - None  

"Low Memory Detector" daemon prio=6 tid=0x02bb9400 nid=0xa6c runnable [0x00000000]  
   java.lang.Thread.State: RUNNABLE  

   Locked ownable synchronizers:  
    - None  

"CompilerThread0" daemon prio=10 tid=0x02bb2800 nid=0xcb8 waiting on condition [0x00000000]  
   java.lang.Thread.State: RUNNABLE  

   Locked ownable synchronizers:  
    - None  

"Attach Listener" daemon prio=10 tid=0x02bb1000 nid=0x7f4 waiting on condition [0x00000000]  
   java.lang.Thread.State: RUNNABLE  

   Locked ownable synchronizers:  
    - None  

"Signal Dispatcher" daemon prio=10 tid=0x02bd2800 nid=0xd80 runnable [0x00000000]  
   java.lang.Thread.State: RUNNABLE  

   Locked ownable synchronizers:  
    - None  

"Finalizer" daemon prio=8 tid=0x02bab000 nid=0xe1c in Object.wait() [0x02d3f000]  
   java.lang.Thread.State: WAITING (on object monitor)  
    at java.lang.Object.wait(Native Method)  
    - waiting on <0x229e1148> (a java.lang.ref.ReferenceQueue$Lock)  
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118)  
    - locked <0x229e1148> (a java.lang.ref.ReferenceQueue$Lock)  
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134)  
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)  

   Locked ownable synchronizers:  
    - None  

"Reference Handler" daemon prio=10 tid=0x02ba6800 nid=0xbe0 in Object.wait() [0x02cef000]  
   java.lang.Thread.State: WAITING (on object monitor)  
    at java.lang.Object.wait(Native Method)  
    - waiting on <0x229e1048> (a java.lang.ref.Reference$Lock)  
    at java.lang.Object.wait(Object.java:485)  
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)  
    - locked <0x229e1048> (a java.lang.ref.Reference$Lock)  

   Locked ownable synchronizers:  
    - None  

"VM Thread" prio=10 tid=0x02b6a400 nid=0x568 runnable   

"VM Periodic Task Thread" prio=10 tid=0x02bc8400 nid=0x75c waiting on condition   

JNI global references: 878  


Found one Java-level deadlock:  
=============================  
"t2":  
  waiting to lock monitor 0x02baaeec (object 0x22a297a8, a java.lang.Object),  
  which is held by "t1"  
"t1":  
  waiting to lock monitor 0x02baa2bc (object 0x22a297b0, a java.lang.Object),  
  which is held by "t2"  

Java stack information for the threads listed above:  
===================================================  
"t2":  
    at com.demo.DeadLock$2.run(DeadLock.java:40)  
    - waiting to lock <0x22a297a8> (a java.lang.Object)  
    - locked <0x22a297b0> (a java.lang.Object)  
"t1":  
    at com.demo.DeadLock$1.run(DeadLock.java:25)  
    - waiting to lock <0x22a297b0> (a java.lang.Object)  
    - locked <0x22a297a8> (a java.lang.Object)  

Found 1 deadlock.  

從這個結果文件我們一看到發(fā)現(xiàn)了一個死鎖,具體是線程t2在等待線程t1,而線程t1在等待線程t2造成的,同時也記錄了線程的堆棧和代碼行數(shù),通過這個堆棧和行數(shù)我們就可以去檢查對應的代碼塊,從而發(fā)現(xiàn)問題和解決問題。

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末啸澡,一起剝皮案震驚了整個濱河市袖订,隨后出現(xiàn)的幾起案子氮帐,更是在濱河造成了極大的恐慌,老刑警劉巖上沐,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件吏口,死亡現(xiàn)場離奇詭異奄容,居然都是意外死亡产徊,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門蜀细,熙熙樓的掌柜王于貴愁眉苦臉地迎上來舟铜,“玉大人,你說我怎么就攤上這事痊夭。” “怎么了迫横?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵恨狈,是天一觀的道長禾怠。 經(jīng)常有香客問我,道長牲证,這世上最難降的妖魔是什么十厢? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任蛮放,我火速辦了婚禮,結果婚禮上娩嚼,老公的妹妹穿的比我還像新娘岳悟。我一直安慰自己贵少,他們只是感情好,可當我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著潜沦,像睡著了一般涝影。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上伯襟,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天稽揭,我揣著相機與錄音,去河邊找鬼事镣。 笑死喊递,一個胖子當著我的面吹牛蕴掏,可吹牛的內(nèi)容都是我干的挽荡。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼青自!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起荠藤,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤淤井,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后总寻,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體轰坊,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年卓鹿,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片藻治。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖矾屯,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情排作,我是刑警寧澤哈雏,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站派殷,受9級特大地震影響虱黄,放射性物質(zhì)發(fā)生泄漏粱甫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一瞒大、第九天 我趴在偏房一處隱蔽的房頂上張望透敌。 院中可真熱鬧,春花似錦背率、人聲如沸蕴纳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽吹零。三九已至茫蛹,卻和暖如春窃蹋,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工垂谢, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留徙邻,地道東北人畸裳。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像耍贾,于是被迫代替她去往敵國和親晃听。 傳聞我的和親對象是個殘疾皇子砰识,可洞房花燭夜當晚...
    茶點故事閱讀 45,033評論 2 355

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