java線程池源碼解析

主要介紹線程池相關(guān)知識(shí),關(guān)于線程池虚婿,首先我們思考下為什么要用線程池旋奢。如果單純的使用線程,線程的創(chuàng)建和銷(xiāo)毀都是自己來(lái)完成然痊,如果并發(fā)請(qǐng)求過(guò)多至朗,可能造成資源耗盡。線程池可以對(duì)線程進(jìn)行統(tǒng)一分配剧浸,調(diào)優(yōu)和監(jiān)控爽丹。本篇文章為《圖靈學(xué)院》課程筆記

  • 降低資源消耗(線程無(wú)限制地創(chuàng)建筑煮,然后使用完畢后銷(xiāo)毀)
  • 提高響應(yīng)速度(無(wú)須創(chuàng)建線程)
  • 提高線程的可管理性

java是如何實(shí)現(xiàn)和管理線程池的,jdk5開(kāi)始把工作單元和任務(wù)執(zhí)行分離粤蝎,工作單元包括callable真仲、runnable,而執(zhí)行機(jī)制由Executor提供初澎,Executor的實(shí)現(xiàn)還提供了對(duì)線程生命周期的管理

相關(guān)接口

image

接口介紹

  • java.util.concurrent.Executor (執(zhí)行器秸应,執(zhí)行方法)

  • java.util.concurrent.ExecutorService (執(zhí)行服務(wù)) 包含服務(wù)的生命周期

  • java.util.concurrent.ScheduledExecutorService (調(diào)度相關(guān)的服務(wù))

核心接口實(shí)現(xiàn)

  • java.util.concurrent.ThreadPoolExecutor (普通的的線程池實(shí)現(xiàn)類)
  • java.util.concurrent.ScheduledThreadPoolExecutor (調(diào)度的核心實(shí)現(xiàn)類)
名稱 方法 說(shuō)明 類型
java.util.concurrent.<br />Executor execute 執(zhí)行接口 接口
java.util.concurrent.<br />ExecutorService submit(java.util.concurrent.Callable) 提交接口 接口
java.util.concurrent.<br />AbstractExecutorService submit(Callable<T> task) 把執(zhí)行和提交接口<br />進(jìn)行合并區(qū)別:有<br />返回值和無(wú)返回值 抽象類
java.util.concurrent.<br />ThreadPoolExecutor execute(Runnable command) 調(diào) 用
runwork 方 法
getTask(從隊(duì)列
拿數(shù)據(jù))
實(shí)現(xiàn)類
java.util.concurrent.<br />ScheduledExecutorService scheduleAtFixedRate、scheduleWithFixedDelay 定義方法 接口
java.util.concurrent.<br />ScheduledThreadPoolExecutor delayedExecute 具體實(shí)現(xiàn)
add>task>addWo
rk
實(shí)現(xiàn)類
image

內(nèi)部類分為兩種

  • policy 策略
  • worker 工作

內(nèi)部工作原理(構(gòu)造方法賦值)

  • corePool:核心線程池大小
  • maximumPool:最大線程池大小
  • BlockingQueue:任務(wù)工作隊(duì)列
  • keepAliveTime:線程活躍時(shí)間碑宴,如果線程數(shù)量大于核心線程數(shù)量软啼,多余線程空閑時(shí)間超時(shí)候被銷(xiāo)毀
  • RejectedExecutionHandler:當(dāng)ThreadPoolExecutor關(guān)閉或最大線程池已經(jīng)滿了,executor將調(diào)用的handler
  • ThreadFactory:使用ThreadFactory創(chuàng)建線程延柠,默認(rèn)使用defaultThreadFactory

線程池的運(yùn)行思路

  • 如果當(dāng)前線程池中的線程數(shù)目小于corePoolSize祸挪,則每來(lái)一個(gè)任務(wù),就會(huì)創(chuàng)建一個(gè)線程去執(zhí)行這個(gè)任務(wù)贞间;
  • 如果當(dāng)前線程池中的線程數(shù)目>=corePoolSize贿条,則每來(lái)一個(gè)任務(wù),會(huì)嘗試將其添加到任務(wù)緩存隊(duì)列當(dāng)中增热,若添加成功整以,則該任務(wù)會(huì)等待空閑線程將其取出去執(zhí)行;若添加失斁稹(一般來(lái)說(shuō)是任務(wù)緩存隊(duì)列已滿)公黑,則會(huì)嘗試創(chuàng)建新的線程去執(zhí)行這個(gè)任務(wù);
  • 如果當(dāng)前線程池中的線程數(shù)目達(dá)到maximumPoolSize摄咆,則會(huì)采取任務(wù)拒絕策略進(jìn)行處理凡蚜;
  • 如果線程池中的線程數(shù)量大于 corePoolSize時(shí),如果某線程空閑時(shí)間超過(guò)keepAliveTime吭从,線程將被終止番刊,直至線程池中的線程數(shù)目不大于corePoolSize;如果允許為核心池中的線程設(shè)置存活時(shí)間影锈,那么核心池中的線程空閑時(shí)間超過(guò)keepAliveTime芹务,線程也會(huì)被終止

[圖片上傳失敗...(image-c13745-1598087752516)]

拒接策略

 ThreadPoolExecutor.AbortPolicy:丟棄任務(wù)并拋出RejectedExecutionException異常(默認(rèn))
 ThreadPoolExecutor.DiscardPolicy:也是丟棄任務(wù),但是不拋出異常
 ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊(duì)列最前面的任務(wù)鸭廷,然后重新嘗試執(zhí)行任務(wù)(重復(fù)此過(guò)程)
 ThreadPoolExecutor.CallerRunsPolicy:由調(diào)用線程處理該任務(wù)

源碼解析

線程池的執(zhí)行原理

初始化構(gòu)造器

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {
    if (corePoolSize < 0 ||
        maximumPoolSize <= 0 ||
        maximumPoolSize < corePoolSize ||
        keepAliveTime < 0)
        throw new IllegalArgumentException();
    if (workQueue == null || threadFactory == null || handler == null)
        throw new NullPointerException();
    this.acc = System.getSecurityManager() == null ?
            null :
            AccessController.getContext();
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}

ThreadPoolExecutor#execute

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        int c = ctl.get();
  //判斷是否小于核心數(shù)量枣抱,是直接新增work成功后直接退出
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
          // 增加失敗后繼續(xù)獲取標(biāo)記 
            c = ctl.get();
        }
  //判斷是運(yùn)行狀態(tài)并且扔到workQueue里成功后 
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
          //再次check判斷運(yùn)行狀態(tài)如果是非運(yùn)行狀態(tài)就移除出去&reject掉
            if (! isRunning(recheck) && remove(command))
                reject(command);
          //否則發(fā)現(xiàn)可能運(yùn)行線程數(shù)是0那么增加一個(gè)null的worker
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
         }
      //直接增加worker如果不成功直接reject
        else if (!addWorker(command, false))
            reject(command);
    }

ThreadPoolExecutor#addWorker

private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
for (;;) {
    int c = ctl.get();
    int rs = runStateOf(c);

    // Check if queue empty only if necessary. 
    if (rs >= SHUTDOWN &&
        ! (rs == SHUTDOWN &&
           firstTask == null &&
           ! workQueue.isEmpty()))
      // 兩種情況
      //1.如果非運(yùn)行狀態(tài) 
      //2.不是這種情況(停止?fàn)顟B(tài)并且是null對(duì)象并且workQueue不等于null)
        return false;

    for (;;) {
        int wc = workerCountOf(c);
        if (wc >= CAPACITY ||
            wc >= (core ? corePoolSize : maximumPoolSize))
            return false;// 判斷是否飽和容量了
        if (compareAndIncrementWorkerCount(c)) //增加一個(gè)work數(shù)量 然后跳出去
            break retry;
        c = ctl.get();  // Re-read ctl  增加work失敗后繼續(xù)遞歸
        if (runStateOf(c) != rs)
            continue retry;
        // else CAS failed due to workerCount change; retry inner loop
    }
}

boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
  //增加一個(gè)worker
    w = new Worker(firstTask);
    final Thread t = w.thread;
  //判斷是否 為null
    if (t != null) {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            // Recheck while holding lock.
            // Back out on ThreadFactory failure or if
            // shut down before lock acquired.  鎖定后并重新檢查下 是否存在線程工廠的失敗或者鎖定前的關(guān)閉
            int rs = runStateOf(ctl.get());

            if (rs < SHUTDOWN ||
                (rs == SHUTDOWN && firstTask == null)) {
                if (t.isAlive()) // precheck that t is startable
                    throw new IllegalThreadStateException();  
                workers.add(w);   //增加work
                int s = workers.size();
                if (s > largestPoolSize)
                    largestPoolSize = s;
                workerAdded = true;
            }
        } finally {
            mainLock.unlock();
        }
        if (workerAdded) { //本次要是新增加work成功就調(diào)用start運(yùn)行
            t.start();
            workerStarted = true;
        }
    }
} finally {
    if (! workerStarted)
        addWorkerFailed(w);
}
return workerStarted;
    }

ThreadPoolExecutor#runWorker

final void runWorker(Worker w) {
Thread wt = Thread.currentThread();//1.取到當(dāng)前線程
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
    while (task != null || (task = getTask()) != null) { //獲取任務(wù) 看看是否能拿到
        w.lock();
        // If pool is stopping, ensure thread is interrupted;
        // if not, ensure thread is not interrupted.  This
        // requires a recheck in second case to deal with
        // shutdownNow race while clearing interrupt
        if ((runStateAtLeast(ctl.get(), STOP) ||
             (Thread.interrupted() &&
              runStateAtLeast(ctl.get(), STOP))) &&
            !wt.isInterrupted())
            wt.interrupt();// 確保線程是能中斷的
        try {
            beforeExecute(wt, task); //開(kāi)始任務(wù)前的鉤子
            Throwable thrown = null;
            try {
                task.run();//執(zhí)行任務(wù)
            } catch (RuntimeException x) {
                thrown = x; throw x;
            } catch (Error x) {
                thrown = x; throw x;
            } catch (Throwable x) {
                thrown = x; throw new Error(x);
            } finally {
                afterExecute(task, thrown); //任務(wù)后的鉤子
            }
        } finally {
            task = null;
            w.completedTasks++;
            w.unlock();
        }
    }
    completedAbruptly = false;
} finally {
    processWorkerExit(w, completedAbruptly);
}
}

ThreadPoolExecutor#processWorkerExit

 private void processWorkerExit(Worker w, boolean completedAbruptly) {
if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
    decrementWorkerCount();

final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
    completedTaskCount += w.completedTasks;
    workers.remove(w);  //移除work
} finally {
    mainLock.unlock();
}

tryTerminate();

int c = ctl.get();
if (runStateLessThan(c, STOP)) { //判斷是否還有任務(wù)
    if (!completedAbruptly) {
        int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
        if (min == 0 && ! workQueue.isEmpty())
            min = 1;
        if (workerCountOf(c) >= min)
            return; // replacement not needed
    }
    addWorker(null, false);
}
}
image

線程池調(diào)度原理

調(diào)度核心構(gòu)造器

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

ScheduledThreadPoolExecutor#delayedExecute

private void delayedExecute(RunnableScheduledFuture<?> task) {
if (isShutdown())
    reject(task);
else {
    super.getQueue().add(task);//增加任務(wù)
    if (isShutdown() &&
        !canRunInCurrentRunState(task.isPeriodic()) &&
        remove(task))
        task.cancel(false);
    else
        ensurePrestart();
}
}

通過(guò)DelayedWorkQueue 延遲隊(duì)列實(shí)現(xiàn) offer獲取對(duì)象的延遲

ScheduledThreadPoolExecutor.DelayedWorkQueue#offer

public boolean offer(Runnable x) {
if (x == null)
    throw new NullPointerException();
RunnableScheduledFuture<?> e = (RunnableScheduledFuture<?>)x; //當(dāng)前對(duì)象
final ReentrantLock lock = this.lock;
lock.lock();
try {
    int i = size;
    if (i >= queue.length) //擴(kuò)容
        grow();
    size = i + 1;
    if (i == 0) {
        queue[0] = e;
        setIndex(e, 0); //第一個(gè)直接設(shè)置索引和下標(biāo)0
    } else {
        siftUp(i, e); //篩選到上邊
    }
    if (queue[0] == e) {
        leader = null;
        available.signal(); //喚醒所有的被擠壓的wait線程
    }
} finally {
    lock.unlock();
}
return true;
}

ScheduledThreadPoolExecutor.DelayedWorkQueue#siftUp

 private void siftUp(int k, RunnableScheduledFuture<?> key) {
while (k > 0) {
    int parent = (k - 1) >>> 1; 
    RunnableScheduledFuture<?> e = queue[parent];
    if (key.compareTo(e) >= 0)
        break; 
    queue[k] = e;
    setIndex(e, k);
    k = parent;
}
queue[k] = key;
setIndex(key, k);
 }

ScheduledThreadPoolExecutor.ScheduledFutureTask#compareTo


 public int compareTo(Delayed other) {
if (other == this) // compare zero if same object
    return 0;
if (other instanceof ScheduledFutureTask) {
    ScheduledFutureTask<?> x = (ScheduledFutureTask<?>)other;
    long diff = time - x.time; //判斷time
    if (diff < 0)
        return -1;
    else if (diff > 0)
        return 1;
    else if (sequenceNumber < x.sequenceNumber)
        return -1;
    else
        return 1;
}
long diff = getDelay(NANOSECONDS) - other.getDelay(NANOSECONDS);
return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
   }

ThreadPoolExecutor#ensurePrestart

確保有work執(zhí)行

 void ensurePrestart() {
        int wc = workerCountOf(ctl.get());
        if (wc < corePoolSize)
            addWorker(null, true);
        else if (wc == 0)
            addWorker(null, false);
   }

ScheduledThreadPoolExecutor.DelayedWorkQueue#take

work運(yùn)行的時(shí)候調(diào)用queue的take方法

public RunnableScheduledFuture<?> take() throws InterruptedException {
            final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
    for (;;) {
        RunnableScheduledFuture<?> first = queue[0];//獲取第一個(gè)對(duì)象
        if (first == null)
            available.await();
        else {
            long delay = first.getDelay(NANOSECONDS);//延遲時(shí)間
            if (delay <= 0)//到時(shí)間了
                return finishPoll(first);
            first = null; // don't retain ref while waiting
            if (leader != null)
                available.await();//因?yàn)闆](méi)有執(zhí)行線程初始化,所以等等什么時(shí)候有了自己被他人喚醒
            else {
                Thread thisThread = Thread.currentThread();
                leader = thisThread;
                try {
                    available.awaitNanos(delay); //各種condition的awaitNanos
                } finally {
                    if (leader == thisThread)
                        leader = null;
                }
            }
        }
    }
} finally {
    if (leader == null && queue[0] != null)
        available.signal();
    lock.unlock();
}

        }

ScheduledThreadPoolExecutor.DelayedWorkQueue#finishPoll

 private RunnableScheduledFuture<?> finishPoll(RunnableScheduledFuture<?> f) {
int s = --size;
RunnableScheduledFuture<?> x = queue[s];  //重排序隊(duì)列
queue[s] = null;
if (s != 0)
    siftDown(0, x);
setIndex(f, -1);
return f
}

ScheduledThreadPoolExecutor.ScheduledFutureTask#run

public void run() {
boolean periodic = isPeriodic();
if (!canRunInCurrentRunState(periodic))
    cancel(false);
else if (!periodic)
    ScheduledFutureTask.super.run();
else if (ScheduledFutureTask.super.runAndReset()) {//有period的要執(zhí)行成功設(shè)置下次執(zhí)行時(shí)間和增加額外任務(wù)
    setNextRunTime();
    reExecutePeriodic(outerTask);
}
}

異步結(jié)果源碼分析

怎么拿到的異步任務(wù)結(jié)果辆床?

FutureTask#awaitDone

  private int awaitDone(boolean timed, long nanos)
        throws InterruptedException {
final long deadline = timed ? System.nanoTime() + nanos : 0L;
WaitNode q = null;
boolean queued = false;
for (;;) {
    if (Thread.interrupted()) { //check線程中斷
        removeWaiter(q);
        throw new InterruptedException();
    }

    int s = state;
    if (s > COMPLETING) {  //判斷是否完成
        if (q != null)
            q.thread = null;
        return s;
    }
    else if (s == COMPLETING) // cannot time out yet
        Thread.yield();
    else if (q == null)
        q = new WaitNode();  //生成一個(gè)waint對(duì)象
    else if (!queued)
        queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
                                             q.next = waiters, q);//鏈表的對(duì)象下一個(gè)置成當(dāng)前的waitNode
    else if (timed) {
        nanos = deadline - System.nanoTime();
        if (nanos <= 0L) {
            removeWaiter(q);
            return state;
        }
        LockSupport.parkNanos(this, nanos); //等待時(shí)間阻塞
    }
    else
        LockSupport.park(this); //一直阻塞
}
  }

什么時(shí)候回填的結(jié)果

FutureTask#run

 public void run() {
   if (state != NEW ||
    !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                 null, Thread.currentThread())) //如果狀態(tài)不是new 或者 runner狀態(tài)置不成功直接退出
    return;
try {
    Callable<V> c = callable;
    if (c != null && state == NEW) {
        V result;
        boolean ran;
        try {
            result = c.call();//運(yùn)行ok 的時(shí)候返回result
            ran = true;
        } catch (Throwable ex) {
            result = null;
            ran = false;
            setException(ex);
        }
        if (ran)//正常成功set result對(duì)象
            set(result);
    }
} finally {
    // runner must be non-null until state is settled to
    // prevent concurrent calls to run()
    runner = null;
    // state must be re-read after nulling runner to prevent
    // leaked interrupts
    int s = state;
    if (s >= INTERRUPTING)
        handlePossibleCancellationInterrupt(s);
}

 }

FutureTask#cancel

 public boolean cancel(boolean mayInterruptIfRunning) {
   if (!(state == NEW &&
      UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
          mayInterruptIfRunning ? INTERRUPTING : CANCELLED))) //CAS 置成stateOffset 的中斷或者取消
    return false;
try {    // in case call to interrupt throws exception
    if (mayInterruptIfRunning) {  //如果線程運(yùn)行中佳晶,可能中斷
        try {
            Thread t = runner;
            if (t != null)
                t.interrupt();
        } finally { // final state
            UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
        }
    }
} finally {
    finishCompletion();
}
return true;

 }

原文地址

http://cbaj.gitee.io/blog/2020/08/22/java%E7%BA%BF%E7%A8%8B%E6%B1%A0%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/#more

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市讼载,隨后出現(xiàn)的幾起案子轿秧,更是在濱河造成了極大的恐慌中跌,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,627評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件菇篡,死亡現(xiàn)場(chǎng)離奇詭異漩符,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)驱还,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)嗜暴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人议蟆,你說(shuō)我怎么就攤上這事闷沥。” “怎么了咐容?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,346評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵舆逃,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我戳粒,道長(zhǎng)路狮,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,097評(píng)論 1 300
  • 正文 為了忘掉前任享郊,我火速辦了婚禮,結(jié)果婚禮上孝鹊,老公的妹妹穿的比我還像新娘炊琉。我一直安慰自己,他們只是感情好又活,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布苔咪。 她就那樣靜靜地躺著,像睡著了一般柳骄。 火紅的嫁衣襯著肌膚如雪团赏。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,696評(píng)論 1 312
  • 那天耐薯,我揣著相機(jī)與錄音舔清,去河邊找鬼。 笑死曲初,一個(gè)胖子當(dāng)著我的面吹牛体谒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播臼婆,決...
    沈念sama閱讀 41,165評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼抒痒,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了颁褂?” 一聲冷哼從身側(cè)響起故响,我...
    開(kāi)封第一講書(shū)人閱讀 40,108評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤傀广,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后彩届,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體伪冰,經(jīng)...
    沈念sama閱讀 46,646評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評(píng)論 3 342
  • 正文 我和宋清朗相戀三年惨缆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了糜值。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,861評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡坯墨,死狀恐怖寂汇,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情捣染,我是刑警寧澤骄瓣,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站耍攘,受9級(jí)特大地震影響榕栏,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蕾各,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評(píng)論 3 336
  • 文/蒙蒙 一扒磁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧式曲,春花似錦妨托、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,698評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至钧排,卻和暖如春敦腔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背恨溜。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,804評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工符衔, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人糟袁。 一個(gè)月前我還...
    沈念sama閱讀 49,287評(píng)論 3 379
  • 正文 我出身青樓柏腻,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親系吭。 傳聞我的和親對(duì)象是個(gè)殘疾皇子五嫂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評(píng)論 2 361