Java線程池總結(jié)

本篇文章講述Java中的線程池問題勺疼,同樣適用于Android中的線程池使用。本篇文章參考:Java線程池分析,Java中的線程池掠归。以上兩位大神的博客有很多干貨掀亩,強(qiáng)烈推薦關(guān)注學(xué)習(xí)。

一、概述

在我們的開發(fā)中經(jīng)常會(huì)使用到多線程铺峭。例如在Android中墓怀,由于主線程的諸多限制,像網(wǎng)絡(luò)請(qǐng)求等一些耗時(shí)的操作我們必須在子線程中運(yùn)行卫键。我們往往會(huì)通過new Thread來開啟一個(gè)子線程傀履,待子線程操作完成以后通過Handler切換到主線程中運(yùn)行。這么以來我們無法管理我們所創(chuàng)建的子線程莉炉,并且無限制的創(chuàng)建子線程钓账,它們相互之間競(jìng)爭(zhēng),很有可能由于占用過多資源而導(dǎo)致死機(jī)或者OOM絮宁。所以在Java中為我們提供了線程池來管理我們所創(chuàng)建的線程梆暮。
線程池的優(yōu)勢(shì)

①降低系統(tǒng)資源消耗,通過重用已存在的線程绍昂,降低線程創(chuàng)建和銷毀造成的消耗啦粹;

②提高系統(tǒng)響應(yīng)速度,當(dāng)有任務(wù)到達(dá)時(shí)治专,無需等待新線程的創(chuàng)建便能立即執(zhí)行卖陵;

③方便線程并發(fā)數(shù)的管控,線程若是無限制的創(chuàng)建张峰,不僅會(huì)額外消耗大量系統(tǒng)資源泪蔫,更是占用過多資源而阻塞系統(tǒng)或oom等狀況,從而降低系統(tǒng)的穩(wěn)定性喘批。線程池能有效管控線程撩荣,統(tǒng)一分配、調(diào)優(yōu)饶深,提供資源使用率餐曹;

④更強(qiáng)大的功能,線程池提供了定時(shí)敌厘、定期以及可控線程數(shù)等功能的線程池台猴,使用方便簡(jiǎn)單。
二俱两、ThreadPoolExecutor

我們可以通過ThreadPoolExecutor來創(chuàng)建一個(gè)線程池饱狂。

ExecutorService service = new ThreadPoolExecutor(....);

下面我們就來看一下ThreadPoolExecutor中的一個(gè)構(gòu)造方法。

public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)

ThreadPoolExecutor參數(shù)含義

  1. corePoolSize

線程池中的核心線程數(shù)宪彩,默認(rèn)情況下休讳,核心線程一直存活在線程池中,即便他們?cè)诰€程池中處于閑置狀態(tài)尿孔。除非我們將ThreadPoolExecutor的allowCoreThreadTimeOut屬性設(shè)為true的時(shí)候俊柔,這時(shí)候處于閑置的核心線程在等待新任務(wù)到來時(shí)會(huì)有超時(shí)策略筹麸,這個(gè)超時(shí)時(shí)間由keepAliveTime來指定。一旦超過所設(shè)置的超時(shí)時(shí)間雏婶,閑置的核心線程就會(huì)被終止物赶。

  1. maximumPoolSize

線程池中所容納的最大線程數(shù),如果活動(dòng)的線程達(dá)到這個(gè)數(shù)值以后尚骄,后續(xù)的新任務(wù)將會(huì)被阻塞块差。包含核心線程數(shù)+非核心線程數(shù)侵续。

  1. keepAliveTime

非核心線程閑置時(shí)的超時(shí)時(shí)長(zhǎng)倔丈,對(duì)于非核心線程,閑置時(shí)間超過這個(gè)時(shí)間状蜗,非核心線程就會(huì)被回收需五。只有對(duì)ThreadPoolExecutor的allowCoreThreadTimeOut屬性設(shè)為true的時(shí)候,這個(gè)超時(shí)時(shí)間才會(huì)對(duì)核心線程產(chǎn)生效果轧坎。

  1. unit

用于指定keepAliveTime參數(shù)的時(shí)間單位宏邮。他是一個(gè)枚舉,可以使用的單位有天(TimeUnit.DAYS)缸血,小時(shí)(TimeUnit.HOURS)蜜氨,分鐘(TimeUnit.MINUTES),毫秒(TimeUnit.MILLISECONDS)捎泻,微秒(TimeUnit.MICROSECONDS, 千分之一毫秒)和毫微秒(TimeUnit.NANOSECONDS, 千分之一微秒);

  1. workQueue

線程池中保存等待執(zhí)行的任務(wù)的阻塞隊(duì)列飒炎。通過線程池中的execute方法提交的Runable對(duì)象都會(huì)存儲(chǔ)在該隊(duì)列中。我們可以選擇下面幾個(gè)阻塞隊(duì)列笆豁。

ArrayBlockingQueue:基于數(shù)組實(shí)現(xiàn)的有界的阻塞隊(duì)列,該隊(duì)列按照FIFO(先進(jìn)先出)原則對(duì)隊(duì)列中的元素進(jìn)行排序郎汪。

LinkedBlockingQueue:基于鏈表實(shí)現(xiàn)的阻塞隊(duì)列,該隊(duì)列按照FIFO(先進(jìn)先出)原則對(duì)隊(duì)列中的元素進(jìn)行排序闯狱。

SynchronousQueue:內(nèi)部沒有任何容量的阻塞隊(duì)列煞赢。在它內(nèi)部沒有任何的緩存空間。對(duì)于SynchronousQueue中的數(shù)據(jù)元素只有當(dāng)我們?cè)囍∽叩臅r(shí)候才可能存在哄孤。

PriorityBlockingQueue:具有優(yōu)先級(jí)的無限阻塞隊(duì)列照筑。

我們還能夠通過實(shí)現(xiàn)BlockingQueue接口來自定義我們所需要的阻塞隊(duì)列。

  1. threadFactory

線程工廠瘦陈,為線程池提供新線程的創(chuàng)建凝危。ThreadFactory是一個(gè)接口,里面只有一個(gè)newThread方法双饥。 默認(rèn)為DefaultThreadFactory類媒抠。

  1. handler

是RejectedExecutionHandler對(duì)象,而RejectedExecutionHandler是一個(gè)接口咏花,里面只有一個(gè)rejectedExecution方法阀趴。當(dāng)任務(wù)隊(duì)列已滿并且線程池中的活動(dòng)線程已經(jīng)達(dá)到所限定的最大值或者是無法成功執(zhí)行任務(wù)苍匆,這時(shí)候ThreadPoolExecutor會(huì)調(diào)用RejectedExecutionHandler中的rejectedExecution方法。在ThreadPoolExecutor中有四個(gè)內(nèi)部類實(shí)現(xiàn)了RejectedExecutionHandler接口浸踩。在線程池中它默認(rèn)是AbortPolicy叔汁,在無法處理新任務(wù)時(shí)拋出RejectedExecutionException異常。

下面是在ThreadPoolExecutor中提供的四個(gè)可選值据块。

CallerRunsPolicy:只用調(diào)用者所在線程來運(yùn)行任務(wù)折剃。

AbortPolicy:直接拋出RejectedExecutionException異常另假。

DiscardPolicy:丟棄掉該任務(wù),不進(jìn)行處理

DiscardOldestPolicy:丟棄隊(duì)列里最近的一個(gè)任務(wù)怕犁,并執(zhí)行當(dāng)前任務(wù)边篮。

我們也可以通過實(shí)現(xiàn)RejectedExecutionHandler接口來自定義我們自己的handler奏甫。如記錄日志或持久化不能處理的任務(wù)。
ThreadPoolExecutor的使用

ExecutorService service = new ThreadPoolExecutor(5, 10, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<>());

對(duì)于ThreadPoolExecutor有多個(gè)構(gòu)造方法思杯,對(duì)于上面的構(gòu)造方法中的其他參數(shù)都采用默認(rèn)值款筑。可以通過execute和submit兩種方式來向線程池提交一個(gè)任務(wù)奈梳。
execute
當(dāng)我們使用execute來提交任務(wù)時(shí)攘须,由于execute方法沒有返回值,所以說我們也就無法判定任務(wù)是否被線程池執(zhí)行成功于宙。

service.execute(new Runnable() {
public void run() {
System.out.println("execute方式");
}
});

submit
當(dāng)我們使用submit來提交任務(wù)時(shí),它會(huì)返回一個(gè)future,我們就可以通過這個(gè)future來判斷任務(wù)是否執(zhí)行成功捞魁,還可以通過future的get方法來獲取返回值。如果子線程任務(wù)沒有完成谱俭,get方法會(huì)阻塞住直到任務(wù)完成宵蛀,而使用get(long timeout, TimeUnit unit)方法則會(huì)阻塞一段時(shí)間后立即返回县貌,這時(shí)候有可能任務(wù)并沒有執(zhí)行完煤痕。

Future<Integer> future = service.submit(new Callable<Integer>() {

            @Override
            public Integer call() throws Exception {
                System.out.println("submit方式");
                return 2;
            }
        });
        try {
            Integer number = future.get();
        } catch (ExecutionException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

線程池關(guān)閉

調(diào)用線程池的shutdown()或shutdownNow()方法來關(guān)閉線程池

shutdown原理:將線程池狀態(tài)設(shè)置成SHUTDOWN狀態(tài)梧宫,然后中斷所有沒有正在執(zhí)行任務(wù)的線程。

shutdownNow原理:將線程池的狀態(tài)設(shè)置成STOP狀態(tài)塘匣,然后中斷所有任務(wù)(包括正在執(zhí)行的)的線程兆解,并返回等待執(zhí)行任務(wù)的列表跑揉。

中斷采用interrupt方法,所以無法響應(yīng)中斷的任務(wù)可能永遠(yuǎn)無法終止现拒。但調(diào)用上述的兩個(gè)關(guān)閉之一望侈,isShutdown()方法返回值為true,當(dāng)所有任務(wù)都已關(guān)閉侥猬,表示線程池關(guān)閉完成捐韩,則isTerminated()方法返回值為true。當(dāng)需要立刻中斷所有的線程瞧预,不一定需要執(zhí)行完任務(wù)仅政,可直接調(diào)用shutdownNow()方法。
三滩愁、線程池執(zhí)行流程

①如果在線程池中的線程數(shù)量沒有達(dá)到核心的線程數(shù)量辫封,這時(shí)候就回啟動(dòng)一個(gè)核心線程來執(zhí)行任務(wù)玖瘸。

②如果線程池中的線程數(shù)量已經(jīng)超過核心線程數(shù)雅倒,這時(shí)候任務(wù)就會(huì)被插入到任務(wù)隊(duì)列中排隊(duì)等待執(zhí)行弧可。

③由于任務(wù)隊(duì)列已滿,無法將任務(wù)插入到任務(wù)隊(duì)列中裁良。這個(gè)時(shí)候如果線程池中的線程數(shù)量沒有達(dá)到線程池所設(shè)定的最大值校套,那么這時(shí)候就會(huì)立即啟動(dòng)一個(gè)非核心線程來執(zhí)行任務(wù)。

④如果線程池中的數(shù)量達(dá)到了所規(guī)定的最大值侨把,那么就會(huì)拒絕執(zhí)行此任務(wù)妹孙,這時(shí)候就會(huì)調(diào)用RejectedExecutionHandler中的rejectedExecution方法來通知調(diào)用者。
四骇笔、四種線程池類

Java中四種具有不同功能常見的線程池嚣崭。他們都是直接或者間接配置ThreadPoolExecutor來實(shí)現(xiàn)他們各自的功能。這四種線程池分別是newFixedThreadPool,newCachedThreadPool,newScheduledThreadPool和newSingleThreadExecutor芦劣。這四個(gè)線程池可以通過Executors類獲取葱跋。

  1. newFixedThreadPool

通過Executors中的newFixedThreadPool方法來創(chuàng)建,該線程池是一種線程數(shù)量固定的線程池稍味。

ExecutorService service = Executors.newFixedThreadPool(4);

在這個(gè)線程池中所容納最大的線程數(shù)就是我們?cè)O(shè)置的核心線程數(shù)荠卷。如果線程池的線程處于空閑狀態(tài)的話,它們并不會(huì)被回收掂碱,除非是這個(gè)線程池被關(guān)閉。如果所有的線程都處于活動(dòng)狀態(tài)的話沧卢,新任務(wù)就會(huì)處于等待狀態(tài)醉者,直到有線程空閑出來。

由于newFixedThreadPool只有核心線程立磁,并且這些線程都不會(huì)被回收剥槐,也就是它能夠更快速的響應(yīng)外界請(qǐng)求。從下面的newFixedThreadPool方法的實(shí)現(xiàn)可以看出颅崩,newFixedThreadPool只有核心線程温圆,并且不存在超時(shí)機(jī)制,采用LinkedBlockingQueue,所以對(duì)于任務(wù)隊(duì)列的大小也是沒有限制的锅移。

public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}

  1. newCachedThreadPool

通過Executors中的newCachedThreadPool方法來創(chuàng)建饱搏。

public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}

通過s上面的newCachedThreadPool方法在這里我們可以看出它的核心線程數(shù)為0,線程池的最大線程數(shù)Integer.MAX_VALUE备绽。而Integer.MAX_VALUE是一個(gè)很大的數(shù)鬓催,也差不多可以說這個(gè)線程池中的最大線程數(shù)可以任意大。

當(dāng)線程池中的線程都處于活動(dòng)狀態(tài)的時(shí)候倍靡,線程池就會(huì)創(chuàng)建一個(gè)新的線程來處理任務(wù)课舍。該線程池中的線程超時(shí)時(shí)長(zhǎng)為60秒他挎,所以當(dāng)線程處于閑置狀態(tài)超過60秒的時(shí)候便會(huì)被回收办桨。這也就意味著若是整個(gè)線程池的線程都處于閑置狀態(tài)超過60秒以后站辉,在newCachedThreadPool線程池中是不存在任何線程的,所以這時(shí)候它幾乎不占用任何的系統(tǒng)資源狸相。

對(duì)于newCachedThreadPool他的任務(wù)隊(duì)列采用的是SynchronousQueue捐川,上面說到在SynchronousQueue內(nèi)部沒有任何容量的阻塞隊(duì)列。SynchronousQueue內(nèi)部相當(dāng)于一個(gè)空集合瘸右,我們無法將一個(gè)任務(wù)插入到SynchronousQueue中岩齿。所以說在線程池中如果現(xiàn)有線程無法接收任務(wù),將會(huì)創(chuàng)建新的線程來執(zhí)行任務(wù)。

  1. newScheduledThreadPool

通過Executors中的newScheduledThreadPool方法來創(chuàng)建龄章。

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}

它的核心線程數(shù)是固定的乞封,對(duì)于非核心線程幾乎可以說是沒有限制的肃晚,并且當(dāng)非核心線程處于限制狀態(tài)的時(shí)候就會(huì)立即被回收。

創(chuàng)建一個(gè)可定時(shí)執(zhí)行或周期執(zhí)行任務(wù)的線程池

ScheduledExecutorService service = Executors.newScheduledThreadPool(4);
service.schedule(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName()+"延遲三秒執(zhí)行");
}
}, 3, TimeUnit.SECONDS);
service.scheduleAtFixedRate(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName()+"延遲三秒后每隔2秒執(zhí)行");
}
}, 3, 2, TimeUnit.SECONDS);

輸出結(jié)果:

pool-1-thread-2延遲三秒后每隔2秒執(zhí)行
pool-1-thread-1延遲三秒執(zhí)行
pool-1-thread-1延遲三秒后每隔2秒執(zhí)行
pool-1-thread-2延遲三秒后每隔2秒執(zhí)行
pool-1-thread-2延遲三秒后每隔2秒執(zhí)行

schedule(Runnable command, long delay, TimeUnit unit):延遲一定時(shí)間后執(zhí)行Runnable任務(wù)拧廊;

schedule(Callable callable, long delay, TimeUnit unit):延遲一定時(shí)間后執(zhí)行Callable任務(wù)晋修;

scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit):延遲一定時(shí)間后,以間隔period時(shí)間的頻率周期性地執(zhí)行任務(wù)滤港;

scheduleWithFixedDelay(Runnable command, long initialDelay, long delay,TimeUnit unit):與scheduleAtFixedRate()方法很類似,但是不同的是scheduleWithFixedDelay()方法的周期時(shí)間間隔是以上一個(gè)任務(wù)執(zhí)行結(jié)束到下一個(gè)任務(wù)開始執(zhí)行的間隔山叮,而scheduleAtFixedRate()方法的周期時(shí)間間隔是以上一個(gè)任務(wù)開始執(zhí)行到下一個(gè)任務(wù)開始執(zhí)行的間隔添履,也就是這一些任務(wù)系列的觸發(fā)時(shí)間都是可預(yù)知的暮胧。

ScheduledExecutorService功能強(qiáng)大,對(duì)于定時(shí)執(zhí)行的任務(wù)往衷,建議多采用該方法席舍。

  1. newSingleThreadExecutor

通過Executors中的newSingleThreadExecutor方法來創(chuàng)建,在這個(gè)線程池中只有一個(gè)核心線程汰扭,對(duì)于任務(wù)隊(duì)列沒有大小限制福铅,也就意味著這一個(gè)任務(wù)處于活動(dòng)狀態(tài)時(shí),其他任務(wù)都會(huì)在任務(wù)隊(duì)列中排隊(duì)等候依次執(zhí)行笆包。

newSingleThreadExecutor將所有的外界任務(wù)統(tǒng)一到一個(gè)線程中支持拷沸,所以在這個(gè)任務(wù)執(zhí)行之間我們不需要處理線程同步的問題。

public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}

五、線程池的使用技巧

需要針對(duì)具體情況而具體處理序无,不同的任務(wù)類別應(yīng)采用不同規(guī)模的線程池衡创,任務(wù)類別可劃分為CPU密集型任務(wù)、IO密集型任務(wù)和混合型任務(wù)哟玷。(N代表CPU個(gè)數(shù))

對(duì)于CPU密集型任務(wù):線程池中線程個(gè)數(shù)應(yīng)盡量少,如配置N+1個(gè)線程的線程池喉脖;

對(duì)于IO密集型任務(wù):由于IO操作速度遠(yuǎn)低于CPU速度抑月,那么在運(yùn)行這類任務(wù)時(shí),CPU絕大多數(shù)時(shí)間處于空閑狀態(tài)题诵,那么線程池可以配置盡量多些的線程层皱,以提高CPU利用率,如2*N草冈;

對(duì)于混合型任務(wù):可以拆分為CPU密集型任務(wù)和IO密集型任務(wù)臭家,當(dāng)這兩類任務(wù)執(zhí)行時(shí)間相差無幾時(shí),通過拆分再執(zhí)行的吞吐率高于串行執(zhí)行的吞吐率蹄殃,但若這兩類任務(wù)執(zhí)行時(shí)間有數(shù)據(jù)級(jí)的差距你踩,那么沒有拆分的意義。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市膝藕,隨后出現(xiàn)的幾起案子芭挽,更是在濱河造成了極大的恐慌,老刑警劉巖袜爪,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件辛馆,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡腊状,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門胰苏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來醇疼,“玉大人秧荆,你說我怎么就攤上這事∫冶簦” “怎么了颁股?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)诉儒。 經(jīng)常有香客問我亏掀,道長(zhǎng),這世上最難降的妖魔是什么温算? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任注竿,我火速辦了婚禮魂贬,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己锦庸,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布梆掸。 她就那樣靜靜地躺著牙言,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上封孙,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音硝拧,去河邊找鬼葛假。 笑死,一個(gè)胖子當(dāng)著我的面吹牛抱究,可吹牛的內(nèi)容都是我干的魔眨。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼侄刽,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼州丹!你這毒婦竟也來了杂彭?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤所计,失蹤者是張志新(化名)和其女友劉穎团秽,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體踪栋,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡夷都,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年囤官,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片治拿。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡劫谅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出荞驴,到底是詐尸還是另有隱情贯城,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布鲫骗,位于F島的核電站踩晶,受9級(jí)特大地震影響渡蜻,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜茸苇,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一学密、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧幔翰,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至燎含,卻和暖如春腿短,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背赴魁。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來泰國打工钝诚, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人潘拱。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓芦岂,卻偏偏與公主長(zhǎng)得像辑鲤,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子弛随,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

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