Android性能優(yōu)化篇之多線程并發(fā)優(yōu)化

image

引言

1. Android性能優(yōu)化篇之內(nèi)存優(yōu)化--內(nèi)存泄漏

2.Android性能優(yōu)化篇之內(nèi)存優(yōu)化--內(nèi)存優(yōu)化分析工具

3.Android性能優(yōu)化篇之UI渲染性能優(yōu)化

4.Android性能優(yōu)化篇之計(jì)算性能優(yōu)化

5.Android性能優(yōu)化篇之電量?jī)?yōu)化(1)——電量消耗分析

6.Android性能優(yōu)化篇之電量?jī)?yōu)化(2)

7.Android性能優(yōu)化篇之網(wǎng)絡(luò)優(yōu)化

8.Android性能優(yōu)化篇之Bitmap優(yōu)化

9.Android性能優(yōu)化篇之圖片壓縮優(yōu)化

10.Android性能優(yōu)化篇之多線程并發(fā)優(yōu)化

11.Android性能優(yōu)化篇之?dāng)?shù)據(jù)傳輸效率優(yōu)化

12.Android性能優(yōu)化篇之程序啟動(dòng)時(shí)間性能優(yōu)化

13.Android性能優(yōu)化篇之安裝包性能優(yōu)化

14.Android性能優(yōu)化篇之服務(wù)優(yōu)化

介紹

在程序開發(fā)的實(shí)踐當(dāng)中恋沃,為了讓程序表現(xiàn)得更加流暢痴鳄,我們肯定會(huì)需要使用到多線程來(lái)提升程序的并發(fā)執(zhí)行性能。但是編寫多線程并發(fā)的代碼一直以來(lái)都是一個(gè)相對(duì)棘手的問題很泊,所以想要獲得更佳的程序性能武通,我們非常有必要掌握多線程并發(fā)編程的基礎(chǔ)技能。

一.Thread 使用

在講解多線程之前,我們先來(lái)講解Thread使用幾個(gè)需要注意的點(diǎn):

1.Thread 中斷
常用的有兩種方式:
(1).通過拋出InterruptedException來(lái)中斷線程
    public  static  class  MyThread extends Thread{
        private  int count=0;
        @Override
        public void run() {
            super.run();
            try{
                while(true){
                        count++;
                        System.out.println("count value:"+count);
                        if (this.interrupted() || this.isInterrupted()){
                            System.out.println("check interrupted show!");
                            throw new InterruptedException();
                        }
                }
            }catch ( InterruptedException e) {
                System.out.println("thread is stop!");
                e.printStackTrace();
            }
        }
        
    } 
(2).通過變量來(lái)中斷(常用)
    public  static  class  CustomThread extends Thread{
        private  int count=0;
        private boolean isCancel = false;
        @Override
        public void run() {
            super.run();
            while(!isCancel){
                    count++;
                    System.out.println("count value:"+count);
            }
        }
        
        public synchronized void cancel(){
            isCancel = true;
        }
    } 
2.同步

我們分變量同步和代碼塊同步兩個(gè)方面來(lái)講解

(1).變量同步
使用volatile關(guān)鍵字
    /**
     * 主內(nèi)存和線程內(nèi)存緩存進(jìn)行同步
     */
    volatile int val = 5;
    public int getVal() {
        return val;
    }
    public void setVal(int val) {
        this.val = val;
    }
使用synchronized關(guān)鍵字
    int val2 = 5;
    /**
     * 使用一個(gè)motinor來(lái)監(jiān)聽(實(shí)現(xiàn)資源由一個(gè)線程進(jìn)行操作)
     * 主內(nèi)存和線程內(nèi)存緩存進(jìn)行同步
     * @return
     */
    public synchronized int getVal2() {
        return val2;
    }
    public synchronized int setVal2(int val) {
        this.val2 = val;
    }
使用關(guān)鍵字AtomicXXXXX
    AtomicInteger mAtomicValue = new  AtomicInteger(0);
    public void setAtomicValue(int value){
        mAtomicValue.getAndSet(value);
    }
    public int getAtomicValue(){
        return mAtomicValue.get();
    }
(2).代碼塊同步

代碼塊同步分樂觀鎖和悲觀鎖來(lái)講解

使用悲觀鎖時(shí),其他線程等待刃榨,進(jìn)入睡眠,頻繁切換任務(wù)双仍,消耗cpu資源
    synchronized (this) {
        .....   
    }
使用樂觀鎖時(shí),失敗重試桌吃,避免任務(wù)重復(fù)切換朱沃,減少cpu消耗
    ReentrantLock lock = new  ReentrantLock();
    lock.lock();
    ......
    lock.unlock();

Thread注意點(diǎn)就講到這里,下面讓我們進(jìn)入今天的主題茅诱,多線程并發(fā)優(yōu)化逗物。

二.Android Threading

android中很多操作需要在主線程中執(zhí)行,比如UI的操作瑟俭,點(diǎn)擊事件等等翎卓,但是如果主線程操作太多,占有的執(zhí)行時(shí)間過長(zhǎng)就會(huì)出現(xiàn)前面我們說的卡頓現(xiàn)象:


image1.jpg

為了減輕主線程操作過多摆寄,避免出現(xiàn)卡頓的現(xiàn)象失暴,我們把一些操作復(fù)雜的消耗時(shí)間長(zhǎng)的任務(wù)放到線程池中去執(zhí)行。下面我們就來(lái)介紹android中幾種線程的類微饥。

1.AsyncTask

為UI線程與工作線程之間進(jìn)行快速的切換提供一種簡(jiǎn)單便捷的機(jī)制逗扒。適用于當(dāng)下立即需要啟動(dòng),但是異步執(zhí)行的生命周期短暫的使用場(chǎng)景欠橘。
它提供了一種簡(jiǎn)便的異步處理機(jī)制矩肩,但是它又同時(shí)引入了一些令人厭惡的麻煩。一旦對(duì)AsyncTask使用不當(dāng)肃续,很可能對(duì)程序的性能帶來(lái)負(fù)面影響黍檩,同時(shí)還可能導(dǎo)致內(nèi)存泄露叉袍。(關(guān)于內(nèi)存泄漏在上面已經(jīng)講過)

使用AsyncTask需要注意的問題?
(1).在AsyncTask中所有的任務(wù)都是被線性調(diào)度執(zhí)行的,他們處在同一個(gè)任務(wù)隊(duì)列當(dāng)中刽酱,按順序逐個(gè)執(zhí)行喳逛。一旦有任務(wù)執(zhí)行時(shí)間過長(zhǎng),隊(duì)列中其他任務(wù)就會(huì)阻塞肛跌。
image3.jpg

對(duì)于上面的問題艺配,我們可以使用AsyncTask.executeOnExecutor()讓AsyncTask變成并發(fā)調(diào)度。

(2).AsyncTask對(duì)正在執(zhí)行的任務(wù)不具備取消的功能衍慎,所以我們要在任務(wù)代碼中添加取消的邏輯(和上面Thread類似)
(3).AsyncTask使用不當(dāng)會(huì)導(dǎo)致內(nèi)存泄漏(可以參考內(nèi)存泄漏一章)
2.HandlerThread

為某些回調(diào)方法或者等待某些任務(wù)的執(zhí)行設(shè)置一個(gè)專屬的線程转唉,并提供線程任務(wù)的調(diào)度機(jī)制。
先來(lái)了解下Looper稳捆,Handler赠法,MessageQueue
Looper: 能夠確保線程持續(xù)存活并且可以不斷的從任務(wù)隊(duì)列中獲取任務(wù)并進(jìn)行執(zhí)行。
Handler: 能夠幫助實(shí)現(xiàn)隊(duì)列任務(wù)的管理乔夯,不僅僅能夠把任務(wù)插入到隊(duì)列的頭部砖织,尾部,還可以按照一定的時(shí)間延遲來(lái)確保任務(wù)從隊(duì)列中能夠來(lái)得及被取消掉末荐。
MessageQueue: 使用Intent侧纯,Message,Runnable作為任務(wù)的載體在不同的線程之間進(jìn)行傳遞甲脏。
把上面三個(gè)組件打包到一起進(jìn)行協(xié)作眶熬,這就是HandlerThread


image2.jpg

我們先來(lái)看下源碼:

    public class HandlerThread extends Thread {
        public HandlerThread(String name, int priority) {
            super(name);
            mPriority = priority;
        }

        @Override
        public void run() {
            mTid = Process.myTid();
            Looper.prepare();
            synchronized (this) {
                mLooper = Looper.myLooper();
                notifyAll();
            }
            Process.setThreadPriority(mPriority);
            onLooperPrepared();
            Looper.loop();
            mTid = -1;
        }

        public Looper getLooper() {
            if (!isAlive()) {
                return null;
            }
            // If the thread has been started, wait until the looper has been created.
            synchronized (this) {
                while (isAlive() && mLooper == null) {
                    try {
                        wait();
                    } catch (InterruptedException e) {
                    }
                }
            }
            return mLooper;
        }
    }
從上面的源碼發(fā)現(xiàn),HandlerThread其實(shí)就是在線程中維持一個(gè)消息循環(huán)隊(duì)列块请。下面我們看下使用:
    HandlerThread mHanderThread = new HandlerThread("hanlderThreadTest", Process.THREAD_PRIORITY_BACKGROUND);
    mHanderThread.run();
    Looper mHanderThreadLooper = mHanderThread.getLooper();

    Handler mHandler = new Handler(mHanderThreadLooper){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            //子線程中執(zhí)行
            ...
        }
    };
    //發(fā)送消息
    mHandler.post(new Runnable() {
        @Override
        public void run() {
            ...
        }
    });  
3.IntentService

適合于執(zhí)行由UI觸發(fā)的后臺(tái)Service任務(wù)娜氏,并可以把后臺(tái)任務(wù)執(zhí)行的情況通過一定的機(jī)制反饋給UI。
默認(rèn)的Service是執(zhí)行在主線程的墩新,可是通常情況下贸弥,這很容易影響到程序的繪制性能(搶占了主線程的資源)。除了前面介紹過的AsyncTask與HandlerThread海渊,我們還可以選擇使用IntentService來(lái)實(shí)現(xiàn)異步操作绵疲。IntentService繼承自普通Service同時(shí)又在內(nèi)部創(chuàng)建了一個(gè)HandlerThread,在onHandlerIntent()的回調(diào)里面處理扔到IntentService的任務(wù)切省。所以IntentService就不僅僅具備了異步線程的特性最岗,還同時(shí)保留了Service不受主頁(yè)面生命周期影響的特點(diǎn)。


image5.jpg
使用IntentService需要特別注意的點(diǎn):
(1).因?yàn)镮ntentService內(nèi)置的是HandlerThread作為異步線程朝捆,所以每一個(gè)交給IntentService的任務(wù)都將以隊(duì)列的方式逐個(gè)被執(zhí)行到般渡,一旦隊(duì)列中有某個(gè)任務(wù)執(zhí)行時(shí)間過長(zhǎng),那么就會(huì)導(dǎo)致后續(xù)的任務(wù)都會(huì)被延遲處理。
(2).通常使用到IntentService的時(shí)候驯用,我們會(huì)結(jié)合使用BroadcastReceiver把工作線程的任務(wù)執(zhí)行結(jié)果返回給主UI線程脸秽。使用廣播容易引起性能問題,我們可以使用LocalBroadcastManager來(lái)發(fā)送只在程序內(nèi)部傳遞的廣播蝴乔,從而提升廣播的性能记餐。我們也可以使用runOnUiThread()快速回調(diào)到主UI線程。
(3).包含正在運(yùn)行的IntentService的程序相比起純粹的后臺(tái)程序更不容易被系統(tǒng)殺死薇正,該程序的優(yōu)先級(jí)是介于前臺(tái)程序與純后臺(tái)程序之間的片酝。
4.Loader

對(duì)于3.0后ContentProvider中的耗時(shí)操作,推薦使用Loader異步加載數(shù)據(jù)機(jī)制挖腰。相對(duì)其他加載機(jī)制雕沿,Loader有那些優(yōu)點(diǎn)呢?

  • 提供異步加載數(shù)據(jù)機(jī)制
  • 對(duì)數(shù)據(jù)源變化進(jìn)行監(jiān)聽猴仑,實(shí)時(shí)更新數(shù)據(jù)
  • 在Activity配置發(fā)生變化(如橫豎屏切換)時(shí)不用重復(fù)加載數(shù)據(jù)
  • 適用于任何Activity和Fragment
    下面我們來(lái)看下Loader的具體使用:
    我們以獲得手機(jī)中所有的圖片為例:
    getLoaderManager().initLoader(LOADER_TYPE, null, mLoaderCallback);
    LoaderManager.LoaderCallbacks<Cursor> mLoaderCallback = new LoaderManager.LoaderCallbacks<Cursor>() {
        private final String[] IMAGE_COLUMNS={
                MediaStore.Images.Media.DATA,//圖片路徑
                MediaStore.Images.Media.DISPLAY_NAME,//顯示的名字
                MediaStore.Images.Media.DATE_ADDED,//添加時(shí)間
                MediaStore.Images.Media.MIME_TYPE,//圖片擴(kuò)展類型
                MediaStore.Images.Media.SIZE,//圖片大小
                MediaStore.Images.Media._ID,//圖片id
        };

        @Override
        public Loader<Cursor> onCreateLoader(int id, Bundle args) {
            toggleShowLoading(true,getString(R.string.common_loading));

            CursorLoader cursorLoader = new CursorLoader(ImageSelectActivity.this,                 MediaStore.Images.Media.EXTERNAL_CONTENT_URI,IMAGE_COLUMNS,
                    IMAGE_COLUMNS[4] + " > 0 AND "+IMAGE_COLUMNS[3] + " =? OR " +IMAGE_COLUMNS[3] + " =? ",
                    new String[]{"image/jpeg","image/png"},IMAGE_COLUMNS[2] + " DESC");
            return cursorLoader;
        }

        @Override
        public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
            if(data != null && data.getCount() > 0){
                ArrayList<String> imageList = new ArrayList<>();

                if(mShowCamera){
                    imageList.add("");
                }
                while (data.moveToNext()){
                    String path = data.getString(data.getColumnIndexOrThrow(IMAGE_COLUMNS[0]));
                    imageList.add(path);
                    Log.e("ImageSelect", "IIIIIIIIIIIIIIIIIIII=====>"+path);
                }
                //顯示數(shù)據(jù)
                showListData(imageList);
                toggleShowLoading(false,getString(R.string.common_loading));
            }
        }

        @Override
        public void onLoaderReset(Loader<Cursor> loader) {  
        }   

onCreateLoader() 實(shí)例化并返回一個(gè)新創(chuàng)建給定ID的Loader對(duì)象
onLoadFinished() 當(dāng)創(chuàng)建好的Loader完成了數(shù)據(jù)的load之后回調(diào)此方法
onLoaderReset() 當(dāng)創(chuàng)建好的Loader被reset時(shí)調(diào)用此方法审轮,這樣保證它的數(shù)據(jù)無(wú)效
LoaderManager會(huì)對(duì)查詢的操作進(jìn)行緩存,只要對(duì)應(yīng)Cursor上的數(shù)據(jù)源沒有發(fā)生變化辽俗,在配置信息發(fā)生改變的時(shí)候(例如屏幕的旋轉(zhuǎn))疾渣,Loader可以直接把緩存的數(shù)據(jù)回調(diào)到onLoadFinished(),從而避免重新查詢數(shù)據(jù)崖飘。另外系統(tǒng)會(huì)在Loader不再需要使用到的時(shí)候(例如使用Back按鈕退出當(dāng)前頁(yè)面)回調(diào)onLoaderReset()方法榴捡,我們可以在這里做數(shù)據(jù)的清除等等操作。

5.ThreadPool

把任務(wù)分解成不同的單元朱浴,分發(fā)到各個(gè)不同的線程上薄疚,進(jìn)行同時(shí)并發(fā)處理。
線程池適合用在把任務(wù)進(jìn)行分解赊琳,并發(fā)進(jìn)行執(zhí)行的場(chǎng)景。
系統(tǒng)提供ThreadPoolExecutor幫助類來(lái)幫助我們簡(jiǎn)化實(shí)現(xiàn)線程池砰碴。


image4.jpg

使用線程池需要特別注意同時(shí)并發(fā)線程數(shù)量的控制躏筏,理論上來(lái)說,我們可以設(shè)置任意你想要的并發(fā)數(shù)量呈枉,但是這樣做非常的不好趁尼。因?yàn)镃PU只能同時(shí)執(zhí)行固定數(shù)量的線程數(shù),一旦同時(shí)并發(fā)的線程數(shù)量超過CPU能夠同時(shí)執(zhí)行的閾值猖辫,CPU就需要花費(fèi)精力來(lái)判斷到底哪些線程的優(yōu)先級(jí)比較高酥泞,需要在不同的線程之間進(jìn)行調(diào)度切換。
一旦同時(shí)并發(fā)的線程數(shù)量達(dá)到一定的量級(jí)啃憎,這個(gè)時(shí)候CPU在不同線程之間進(jìn)行調(diào)度的時(shí)間就可能過長(zhǎng)芝囤,反而導(dǎo)致性能嚴(yán)重下降。另外需要關(guān)注的一點(diǎn)是,每開一個(gè)新的線程悯姊,都會(huì)耗費(fèi)至少64K+的內(nèi)存羡藐。為了能夠方便的對(duì)線程數(shù)量進(jìn)行控制,ThreadPoolExecutor為我們提供了初始化的并發(fā)線程數(shù)量悯许,以及最大的并發(fā)數(shù)量進(jìn)行設(shè)置仆嗦。

    /**
     * 核心線程數(shù)
     * 最大線程數(shù)
     * 保活時(shí)間
     * 時(shí)間單位
     * 任務(wù)隊(duì)列
     * 線程工廠
     */
    threadPoolExecutor = new ThreadPoolExecutor(
            CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
            linkedBlockingQueue, sThreadFactory);
    threadPoolExecutor.execute(runnable);
我們知道系統(tǒng)還提供了Executors類中幾種線程池先壕,下面我們來(lái)看下這些線程池的缺點(diǎn):

newFixedThreadPool 和 newSingleThreadExecutor:主要問題是堆積的請(qǐng)求處理隊(duì)列可能會(huì)耗費(fèi)非常大的內(nèi)存瘩扼,甚至 OOM。
newCachedThreadPool 和 newScheduledThreadPool:主要問題是線程數(shù)最大數(shù)是 Integer.MAX_VALUE垃僚,可能會(huì)創(chuàng)建數(shù)量非常多的線程集绰,甚至 OOM

我們看到這些線程池但是有缺點(diǎn)的,所以具體使用那種方式實(shí)現(xiàn)要根據(jù)我們的需求來(lái)選擇冈在。

如果想要避開上面的問題倒慧,可以參考OKHttp中線程池的實(shí)現(xiàn),OKHttp中隊(duì)線程調(diào)度又封裝了一層包券,使用安全且方便纫谅,有興趣的可以去看看源碼。

三.線程優(yōu)先級(jí)

Android系統(tǒng)會(huì)根據(jù)當(dāng)前運(yùn)行的可見的程序和不可見的后臺(tái)程序?qū)€程進(jìn)行歸類溅固,劃分為forground的那部分線程會(huì)大致占用掉CPU的90%左右的時(shí)間片付秕,background的那部分線程就總共只能分享到5%-10%左右的時(shí)間片。之所以設(shè)計(jì)成這樣是因?yàn)閒orground的程序本身的優(yōu)先級(jí)就更高侍郭,理應(yīng)得到更多的執(zhí)行時(shí)間询吴。


image6.jpg

默認(rèn)情況下,新創(chuàng)建的線程的優(yōu)先級(jí)默認(rèn)和創(chuàng)建它的母線程保持一致亮元。如果主UI線程創(chuàng)建出了幾十個(gè)工作線程猛计,這些工作線程的優(yōu)先級(jí)就默認(rèn)和主線程保持一致了,為了不讓新創(chuàng)建的工作線程和主線程搶占CPU資源,需要把這些線程的優(yōu)先級(jí)進(jìn)行降低處理,這樣才能給幫組CPU識(shí)別主次歌溉,提高主線程所能得到的系統(tǒng)資源喇闸。

在Android系統(tǒng)里面,我們可以通過android.os.Process.setThreadPriority(int)設(shè)置線程的優(yōu)先級(jí),參數(shù)范圍從-20到24,數(shù)值越小優(yōu)先級(jí)越高。Android系統(tǒng)還為我們提供了以下的一些預(yù)設(shè)值卖局,我們可以通過給不同的工作線程設(shè)置不同數(shù)值的優(yōu)先級(jí)來(lái)達(dá)到更細(xì)粒度的控制。


image7.jpg
大多數(shù)情況下双霍,新創(chuàng)建的線程優(yōu)先級(jí)會(huì)被設(shè)置為默認(rèn)的0砚偶,主線程設(shè)置為0的時(shí)候批销,新創(chuàng)建的線程還可以利用THREAD_PRIORITY_LESS_FAVORABLE或者THREAD_PRIORITY_MORE_FAVORABLE來(lái)控制線程的優(yōu)先級(jí)。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蟹演,一起剝皮案震驚了整個(gè)濱河市风钻,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌酒请,老刑警劉巖骡技,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異羞反,居然都是意外死亡布朦,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門昼窗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)是趴,“玉大人,你說我怎么就攤上這事澄惊∷敉荆” “怎么了?”我有些...
    開封第一講書人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵掸驱,是天一觀的道長(zhǎng)肛搬。 經(jīng)常有香客問我,道長(zhǎng)毕贼,這世上最難降的妖魔是什么温赔? 我笑而不...
    開封第一講書人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮鬼癣,結(jié)果婚禮上陶贼,老公的妹妹穿的比我還像新娘。我一直安慰自己待秃,他們只是感情好拜秧,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著章郁,像睡著了一般腹纳。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上驱犹,一...
    開封第一講書人閱讀 49,071評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音足画,去河邊找鬼雄驹。 笑死,一個(gè)胖子當(dāng)著我的面吹牛淹辞,可吹牛的內(nèi)容都是我干的医舆。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蔬将!你這毒婦竟也來(lái)了爷速?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤霞怀,失蹤者是張志新(化名)和其女友劉穎惫东,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體毙石,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡廉沮,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了徐矩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片滞时。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖滤灯,靈堂內(nèi)的尸體忽然破棺而出坪稽,到底是詐尸還是另有隱情,我是刑警寧澤鳞骤,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布窒百,位于F島的核電站,受9級(jí)特大地震影響弟孟,放射性物質(zhì)發(fā)生泄漏贝咙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一拂募、第九天 我趴在偏房一處隱蔽的房頂上張望庭猩。 院中可真熱鬧,春花似錦陈症、人聲如沸蔼水。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)趴腋。三九已至,卻和暖如春论咏,著一層夾襖步出監(jiān)牢的瞬間优炬,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工厅贪, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蠢护,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓养涮,卻偏偏與公主長(zhǎng)得像葵硕,于是被迫代替她去往敵國(guó)和親眉抬。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345

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