Java并發(fā)編程(一):進(jìn)程和線程

1 概述

下面是維基百科上對進(jìn)程和線程的解釋:

進(jìn)程(英語:process)坐榆,是指計算機(jī)中已運行的程序。進(jìn)程為曾經(jīng)是分時系統(tǒng)的基本運作單位韧掩。在面向進(jìn)程設(shè)計的系統(tǒng)(如早期的UNIX象浑,Linux 2.4及更早的版本)中,進(jìn)程是程序的基本執(zhí)行實體句携;在面向線程設(shè)計的系統(tǒng)(如當(dāng)代多數(shù)操作系統(tǒng)榔幸、Linux 2.6及更新的版本)中,進(jìn)程本身不是基本運行單位务甥,而是線程的容器牡辽。程序本身只是指令、數(shù)據(jù)及其組織形式的描述敞临,進(jìn)程才是程序(那些指令和數(shù)據(jù))的真正運行實例态辛。若干進(jìn)程有可能與同一個程序相關(guān)系,且每個進(jìn)程皆可以同步(循序)或異步(平行)的方式獨立運行⊥δ颍現(xiàn)代計算機(jī)系統(tǒng)可在同一段時間內(nèi)以進(jìn)程的形式將多個程序加載到存儲器中奏黑,并借由時間共享(或稱時分復(fù)用),以在一個處理器上表現(xiàn)出同時(平行性)運行的感覺编矾。同樣的熟史,使用多線程技術(shù)(多線程即每一個線程都代表一個進(jìn)程內(nèi)的一個獨立執(zhí)行上下文)的操作系統(tǒng)或計算機(jī)體系結(jié)構(gòu),同樣程序的平行線程窄俏,可在多CPU主機(jī)或網(wǎng)絡(luò)上真正同時運行(在不同的CPU上)蹂匹。

線程(英語:thread)是操作系統(tǒng)能夠進(jìn)行運算調(diào)度的最小單位。它被包含在進(jìn)程之中凹蜈,是進(jìn)程中的實際運作單位限寞。一條線程指的是進(jìn)程中一個單一順序的控制流,一個進(jìn)程中可以并發(fā)多個線程仰坦,每條線程并行執(zhí)行不同的任務(wù)履植。在Unix System VSunOS中也被稱為輕量進(jìn)程(lightweight processes),但輕量進(jìn)程更多指內(nèi)核線程(kernel thread)悄晃,而把用戶線程(user thread)稱為線程玫霎。

線程是獨立調(diào)度和分派的基本單位。線程可以為操作系統(tǒng)內(nèi)核調(diào)度的內(nèi)核線程,如Win32線程庶近;由用戶進(jìn)程自行調(diào)度的用戶線程翁脆,如Linux平臺的POSIX Thread;或者由內(nèi)核與用戶進(jìn)程拦盹,如Windows 7的線程鹃祖,進(jìn)行混合調(diào)度。

同一進(jìn)程中的多條線程將共享該進(jìn)程中的全部系統(tǒng)資源普舆,如虛擬地址空間恬口,文件描述符信號處理等等。但同一進(jìn)程中的多個線程有各自的調(diào)用棧(call stack)沼侣,自己的寄存器環(huán)境(register context)祖能,自己的線程本地存儲(thread-local storage)。

一個進(jìn)程可以有很多線程蛾洛,每條線程并行執(zhí)行不同的任務(wù)养铸。

在多核或多CPU,或支持Hyper-threading的CPU上使用多線程程序設(shè)計的好處是顯而易見轧膘,即提高了程序的執(zhí)行吞吐率钞螟。在單CPU單核的計算機(jī)上,使用多線程技術(shù)谎碍,也可以把進(jìn)程中負(fù)責(zé)I/O處理鳞滨、人機(jī)交互而常被阻塞的部分與密集計算的部分分開來執(zhí)行,編寫專門的workhorse線程執(zhí)行密集計算蟆淀,從而提高了程序的執(zhí)行效率拯啦。

以上的描述還是有些“學(xué)院派”,可能會讓人有些難以理解熔任。做個類比褒链,把計算機(jī)CPU一個核心看成是一個工廠,多核就是多個工廠疑苔,進(jìn)程就可以看做是工廠里的車間甫匹,但由于電力系統(tǒng)的問題,同一時刻只能給一個車間供電惦费,即同一時刻只能有一個車間在進(jìn)行生產(chǎn)工作赛惩,其他車間只能“閑著”,直到電力系統(tǒng)把電輸送過來趁餐,然后接著干活,這個過程可以看做是進(jìn)程的調(diào)度篮绰。而線程可以看做是車間里的一個一個工人后雷,這些工人共同協(xié)作以完成任務(wù),他們共享整個車間的“公共區(qū)域”,例如走道臀突,休息室等(即同一進(jìn)程內(nèi)的線程可以共享線程的“共享資源”)勉抓,但他們每個人都有自己的狀態(tài),即他們只知道自己處于什么狀態(tài)候学,手里的任務(wù)是什么藕筋,并不知道別人的狀態(tài)(即線程具有自己的堆棧,寄存器)梳码,但由于資源有限隐圾,例如只有一臺設(shè)備,所以同一時刻只能有一個工人對機(jī)器進(jìn)行操作掰茶,當(dāng)允許操作時間結(jié)束之后或者發(fā)生意外情況時暇藏,該工人從設(shè)備中撤出來,并且記錄自己工作到哪了濒蒋,然后調(diào)度中心選擇其他工人盐碱,讓其操作設(shè)備,這個過程即線程的調(diào)度沪伙。

1.1 多線程和多進(jìn)程的好處

多線程或者多進(jìn)程對性能的提升是很有幫助的瓮顽,試想一下,如果僅僅是單進(jìn)程围橡,那么在你使用QQ聊天的時候暖混,就無法使用Word等軟件了,有了多線程以及CPU的線程調(diào)度某饰,QQ和Word就好像是在同時運行一樣(但實際上是因為進(jìn)程的切換非常迅速儒恋,人類無法在那么短的時間里做出反應(yīng),所以看起來就好像兩個進(jìn)程在并行的執(zhí)行)黔漂。多線程也是類似的诫尽,只是多線程的并發(fā)是在進(jìn)程內(nèi)部的并發(fā),如果程序大量涉及磁盤訪問或者網(wǎng)絡(luò)傳輸?shù)炔僮骶媸兀嗑€程就可以非常有效的提高效率牧嫉,簡單理解就是”人多力量大“。

雖然多線程和多進(jìn)程能提高效率减途,但并不是一定的酣藻,因為進(jìn)程切換和線程切換也是有一定開銷的,如果多進(jìn)程或者多線程的收益不足以抵消進(jìn)程切換或者線程切換的開銷鳍置,采用多進(jìn)程或者多線程技術(shù)甚至?xí)?dǎo)致性能降低辽剧,得不償失,所以不要一上來就采用多線程或者多進(jìn)程編程税产,應(yīng)該多多測試怕轿,比較偷崩,最終再確定方案。

在Java并發(fā)編程中撞羽,我們主要關(guān)注的線程以及線程間的調(diào)度阐斜,通信以及線程安全等問題,而不太關(guān)注進(jìn)程诀紊,一個Java程序在啟動運行后谒出,就是一個JVM進(jìn)程,進(jìn)程之間的調(diào)度由JVM負(fù)責(zé)邻奠,一般的開發(fā)人員不會涉及到JVM的開發(fā)笤喳。所以,本文包括本系列后續(xù)的文章惕澎,基本上都是圍繞著線程來介紹各種技術(shù)莉测,例如線程池,鎖等唧喉。

2 創(chuàng)建線程的三種方式

2.1 通過繼承Thread的方式來創(chuàng)建線程

這種方式主要是創(chuàng)建一個類捣卤,該類繼承Thread,并重寫其run方法八孝,在使用的時候董朝,創(chuàng)建該類的實例,調(diào)用start方法即可啟動線程干跛,該線程運行的就是run方法里的邏輯子姜,演示代碼如下所示:

public class MyThread extends Thread {
    
    //重寫run()方法
    @Override
    public void run() {
        System.out.println("hello, world! I'm " + Thread.currentThread().getName());
    }
}

//測試類
public class Main {

    public static void main(String[] args) throws InterruptedException {
        MyThread myThread1 = new MyThread();
        MyThread myThread2 = new MyThread();
        myThread1.start();
        myThread2.start();

        //等待該線程結(jié)束
        myThread1.join();
        myThread2.join();
    }
}

運行可得到類似如下輸出:

hello, world! I'm Thread-0
hello, world! I'm Thread-1

這時候多運行幾次,會發(fā)現(xiàn)有時候Thrad0在Thread1之前楼入,有時候卻是相反哥捕,這說明線程的執(zhí)行順序并不固定,這取決于線程調(diào)度嘉熊。

2.2 通過實現(xiàn)Runnable接口來創(chuàng)建線程

除了繼承Thread類之外遥赚,還可以通過實現(xiàn)Runnable接口來創(chuàng)建線程,Runnable接口只有一個抽象方法阐肤,即public abstract void run();實現(xiàn)Runnable接口的類必須實現(xiàn)該抽象方法凫佛,使用的時候創(chuàng)建Runnable實例,然后將其傳入Thread類的構(gòu)造函數(shù)中孕惜,最后再調(diào)用start方法啟動線程即可愧薛,下面是演示代碼:

public class MyRunnable implements Runnable {

    @Override
    public void run() {
        System.out.println("hello, world! I'm " + Thread.currentThread().getName());
    }
}

public class Main {

    public static void main(String[] args) throws InterruptedException {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread1 = new Thread(myRunnable);
        Thread thread2 = new Thread(myRunnable);

        thread1.start();
        thread2.start();

        thread1.join();
        thread2.join();
    }
}

輸出結(jié)果和之前一樣,不再多說衫画。

2.3 通過實現(xiàn)Callable來創(chuàng)建線程

這種方式需要結(jié)合FutureTask來實現(xiàn)毫炉,因其相對其他兩種方式比較復(fù)雜,所以說一下整個步驟:

  1. 創(chuàng)建一個類削罩,實現(xiàn)Callable接口并實現(xiàn)其call方法碘箍,該方法有返回值遵馆,返回值類型是Callable的泛型參數(shù)的類型,如果不指定丰榴,返回類型可以是Object。
  2. 結(jié)合FutureTask秆撮,將剛剛創(chuàng)建的Callable實現(xiàn)類實例傳遞給構(gòu)造函數(shù)四濒,此時可以獲取到FutureTask實例。
  3. 因為FutureTask實現(xiàn)了Runnable接口职辨,所以可以傳入Thread類的構(gòu)造函數(shù)中盗蟆,然后獲取Thread類實例,并啟動舒裤。
  4. 最后可以調(diào)用FutureTask.get()方法取得call方法的返回值喳资,該方法是阻塞的,如果任務(wù)未完成腾供,調(diào)用該方法的線程會被阻塞仆邓,知道任務(wù)完成。

下面是演示代碼:

public class MyCallable implements Callable<Long> {

    @Override
    public Long call() throws Exception {
        System.out.println("hello, world! I'm " + Thread.currentThread().getName());
        
        //返回線程id
        return Thread.currentThread().getId();
    }
}

public class Main {

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        MyCallable myCallable = new MyCallable();
        
        //創(chuàng)建兩個任務(wù)
        FutureTask<Long> task1 = new FutureTask<>(myCallable);
        FutureTask<Long> task2 = new FutureTask<>(myCallable);


        //分別把兩個任務(wù)交給不同的線程
        Thread thread1 = new Thread(task1);
        Thread thread2 = new Thread(task2);

        thread1.start();
        thread2.start();

        thread1.join();
        thread2.join();

        //調(diào)用get()方法獲取返回值
        System.out.println(task1.get());
        System.out.println(task2.get());
    }
}

這里的FutureTask是JDK1.5才有的東西伴鳖,提供異步的特性节值,關(guān)于異步,本文不會涉及榜聂,后續(xù)會有文章詳細(xì)介紹異步相關(guān)的內(nèi)容搞疗。

2.4 三種方式比較

這三種方式我個人更傾向于第二種,即實現(xiàn)Runnable接口的方式须肆,在Java8中匿乃,使用lambda可以不用顯式的創(chuàng)建Runnable實現(xiàn)類,使得代碼更加簡潔豌汇,編碼效率更高幢炸。如下所示:

Runnable runnable = () -> {
    System.out.println("hello, world! I'm " + Thread.currentThread().getName());
};

而第一種方式因為需要繼承Thread類,所以就不能繼承其他類了瘤礁,這可能影響類的擴(kuò)展性阳懂,不是很推薦。

第三種方式一般在異步編程中使用柜思,是三種方式中最復(fù)雜的岩调,如果沒有異步的需求,一般也不使用這種方式赡盘。

3 Thread類

Thread類是非常重要的類号枕,它是對Java線程的抽象,提供了豐富的操控線程(其實操控空間著實不大)的API陨享,例如sleep()葱淳,join()钝腺,start(),isAlive()等赞厕。Thread類的很多方法都是native方法艳狐,即本地方法,其實現(xiàn)不是用Java語言實現(xiàn)的皿桑,而是用C++語言實現(xiàn)的(對于HotSpot虛擬機(jī)毫目,其他的虛擬機(jī)可能不是用的C++),所以在JDK里無法查看源碼诲侮,需要拿到虛擬機(jī)源碼才能看到這些實現(xiàn)镀虐。所以這里主要是介紹幾個常用的方法的功能,不涉及源碼分析沟绪。

3.1 sleep()方法

sleep()方法即睡眠的意思刮便,其參數(shù)是一個long類型的值,表示毫秒數(shù)绽慈,調(diào)用該方法的線程會停止工作恨旱,直到設(shè)置的時間結(jié)束,在停止工作的過程中久信,不會放棄持有的鎖(如果之前有獲取鎖的話)窖杀,這是和Object.wati()方法的主要區(qū)別之一。下面是一個演示代碼:

public class Main {

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        Runnable runnable = () -> {
            System.out.println("sleep 5s");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("hello, world! I'm " + Thread.currentThread().getName());
        };

        Thread thread = new Thread(runnable);

        thread.start();
        thread.join();
    }
}

運行一下程序裙士,發(fā)現(xiàn)先輸出了sleep 5s的字符入客,過了大概5s之后,才輸出hello, world! I'm***的字符腿椎。這就是sleep()的功能桌硫,很簡單,不多說了啃炸。

3.2 join()方法

在以上的示例代碼中铆隘,我都使用了join()方法,該方法的功能是這樣的:該方法調(diào)用的所在線程需要等待工作線程執(zhí)行完畢才能繼續(xù)執(zhí)行南用。

有點繞口膀钠,什么意思呢移国?例如現(xiàn)在我在main方法里調(diào)用了thread1的join方法显晶,此時main線程就是該方法調(diào)用的所在線程,而工作線程就是thread1次乓,所以此時的結(jié)果就是main線程需要等待thread1執(zhí)行完畢筑公,才能繼續(xù)往下執(zhí)行雳窟。

在上面的示例代碼中,我之所以調(diào)用這個方法匣屡,目的是讓main線程等待工作線程執(zhí)行完畢封救,否則可能無法看到工作線程的輸出拇涤。

3.2 中斷相關(guān)方法

與中斷相關(guān)的方法主要有兩個:interrupt()和isInterrupted()。其中interrupt()的功能是將調(diào)用該方法的線程的中斷標(biāo)志位置位誉结,而isInterrupted()的功能就是檢查線程的中斷標(biāo)志位鹅士,當(dāng)中斷標(biāo)志位被置位時,該方法會返回true搓彻。下面的示例代碼演示了如何使用這兩個方法:

public class Main {

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        Runnable runnable = () -> {
            try {
                for (int i = 0; i < 5000000; i++) {
                    if (Thread.currentThread().isInterrupted()) {
                        System.out.println("interrupt occur!!");
                        throw new InterruptedException();
                    }
                }
                System.out.println("is it execute this statement?");
            } catch (InterruptedException e) {
               //在中斷標(biāo)志位再次置位如绸,即表示重新中斷該線程,方便上層的代碼處理
                Thread.currentThread().interrupt();
            }

        };

        Thread thread = new Thread(runnable);
        thread.start();
        Thread.sleep(10);
        thread.interrupt(); //向thread線程發(fā)送中斷請求

    }
}

在上面的例子中旭贬,我們在main線程調(diào)用了thread線程的interrupt()方法,表示向thread線程發(fā)送中斷請求搪泳,在thread線程的邏輯是輪詢檢查當(dāng)前線程的中斷標(biāo)志位(調(diào)用了isInterrupted()方法)稀轨,當(dāng)檢查到中斷標(biāo)志位的時候,就拋出一個InterruptedException異常岸军,否則會繼續(xù)執(zhí)行System.out.println("is it execute this statement?");該異常被catch捕獲到奋刽,在catch里我們將線程的中斷標(biāo)志位再次置位的目的是將異常傳播給上層代碼,因為在run方法里無法直接拋出異常艰赞,即不能這樣做:

public void run() throws InterruptedException {
//....
}

而如果僅僅是catch了佣谐,而不做一些事情的話,就只是“生吞異撤窖”而已狭魂,這不是一個好的處理方式,比較好的處理方式就交給上層代碼處理党觅,但又無法直接拋出異常雌澄,就只能重新將線程中斷標(biāo)志位置位了,上層代碼可以檢查中斷標(biāo)志位杯瞻,然后在上層處理該異常镐牺。

關(guān)于中斷相關(guān)的知識,建議參考計算機(jī)組成原理或者操作系統(tǒng)相關(guān)資料魁莉。

4 線程狀態(tài)

在Thread類里有一個枚舉內(nèi)部類睬涧,叫State,如下所示:

//省略了注釋
public enum State {
    NEW,

    RUNNABLE,

    BLOCKED,

    WAITING,

    TIMED_WAITING,

    TERMINATED;
}

該類定義了6個枚舉實例旗唁,表示線程的6個狀態(tài)畦浓,下圖是6種狀態(tài)的狀態(tài)轉(zhuǎn)換圖:

該圖來自一篇博客,我會在最后標(biāo)識出來逆皮。

4.1 New

New即初始狀態(tài)宅粥,當(dāng)一個線程被創(chuàng)建時(即new一個線程實例),線程就處于該狀態(tài)电谣。

4.2 RUNNABLE

RUNNABLE即可運行狀態(tài)秽梅,注意該狀態(tài)其實表示兩個狀態(tài)抹蚀,即就緒狀態(tài)和運行狀態(tài)!這是很關(guān)鍵的企垦,因為我相信很多朋友都看過操作系統(tǒng)相關(guān)的書籍环壤,在操作系統(tǒng)中,它將就緒狀態(tài)和運行狀態(tài)用兩個不同的字段表示钞诡,而Java中僅用一個字段表示郑现,我到現(xiàn)在也不知道為什么Java要這樣做,也許是為了實現(xiàn)方便荧降?

4.3 BLOCKED

當(dāng)需要進(jìn)入臨界區(qū)(被鎖鎖住的區(qū)域)時接箫,如果線程沒有爭搶到鎖資源,就進(jìn)入了BLOCKED阻塞狀態(tài)朵诫。

4.4 WAITING

等待狀態(tài)辛友,調(diào)用Object.wait()、Thread.join()或者LockSupport.park()方法的時候會進(jìn)入該狀態(tài)剪返,該狀態(tài)會放棄鎖資源(如果之前有獲取到鎖資源的話)废累。

4.5 TIMED_WAITING

超時等待狀態(tài),調(diào)用Object.wait(long)脱盲、Thread.sleep()邑滨、Thread.join(long)或者LockSupport.parkNanos和LockSupport.parkUntil方法的時候會進(jìn)入該狀態(tài),該狀態(tài)和WAITING的最主要區(qū)別就是該狀態(tài)有一個超時時間钱反,當(dāng)過了設(shè)置的時間掖看,線程會自動的從該狀態(tài)中“蘇醒”過來。

4.6 TERMINATED

即中止?fàn)顟B(tài)诈铛,當(dāng)線程執(zhí)行完畢之后乙各,會切換到該狀態(tài),然后再“死去”幢竹。

這里的6個狀態(tài)并不一定就和操作系統(tǒng)的線程狀態(tài)一一對應(yīng)耳峦,在開始的時候,我就說過Thread類是Java對操作系統(tǒng)線程的一個抽象焕毫,直接的目的是為了提供方便使用的API蹲坷,而不是簡單的把線程一對一映射過來。

5 守護(hù)線程

Java中有兩種類型的線程:普通用戶線程邑飒,守護(hù)線程循签。守護(hù)線程的作用就是“守護(hù)”,通俗的講就是“保姆”疙咸。只要JVM存在一個非守護(hù)線程县匠,那么守護(hù)線程都不會停止,只有當(dāng)JVM所有的非守護(hù)線程都停止時,守護(hù)線程才會隨著JVM停止而停止乞旦。創(chuàng)建守護(hù)線程和創(chuàng)建普通線程是一樣的贼穆,只是在創(chuàng)建完之后調(diào)用Thread.setDaemon(true);即可。下面是一個守護(hù)線程的示例:

public class Main {

    public static void main(String[] args) {

        Thread userThread = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(400);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("user thread finished!");
        });

        Thread daemonThread = new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                try {
                    System.out.println("damon thread : " + i);
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        daemonThread.setDaemon(true);

        userThread.start();
        daemonThread.start();
    }
}

運行一下兰粉,輸出結(jié)果大致如下所示:

daemon thread : 0
daemon thread : 1
daemon thread : 2
daemon thread : 3
daemon thread : 4
daemon thread : 5
daemon thread : 6
daemon thread : 7
user thread finished!

從輸出上看出故痊,daemon thread只運行了7次循環(huán)體,而代碼中設(shè)置的是100次循環(huán)玖姑,那為什么沒有執(zhí)行完畢就結(jié)束了呢愕秫?因為user thread 結(jié)束了,main線程也隨之結(jié)束焰络,還有一些系統(tǒng)線程也隨著結(jié)束戴甩,JVM不會等待守護(hù)線程執(zhí)行完畢,所以看到的現(xiàn)象就好像守護(hù)線程被打斷一樣闪彼。

這里有個概念上的問題等恐,上面說的“只要JVM存在一個非守護(hù)線程,那么守護(hù)線程都不會停止”其實并不準(zhǔn)確备蚓,守護(hù)線程也是線程,只有當(dāng)守護(hù)線程的任務(wù)是那種“永遠(yuǎn)沒有盡頭”的任務(wù)囱稽,上述的說法才會成立郊尝,否則守護(hù)線程執(zhí)行完畢,線程照樣會退出战惊。所以流昏,大多數(shù)守護(hù)線程的業(yè)務(wù)邏輯都是諸如“定時任務(wù),“定時調(diào)度”吞获,”觸發(fā)式任務(wù)“等况凉,例如GC線程就是守護(hù)線程。

注意各拷!setDaemon()方法需要在start()方法之前調(diào)用刁绒,否則會拋出java.lang.IllegalThreadStateException異常。

5 小結(jié)

本文簡單介紹了進(jìn)程和線程烤黍,對于Java開發(fā)者來說知市,更關(guān)注的是線程,所以本文沒有過多的涉及進(jìn)程速蕊,如果想要了解更多關(guān)于進(jìn)程的知識嫂丙,建議參考操作系統(tǒng)經(jīng)典書籍中關(guān)于進(jìn)程的章節(jié)。之后還介紹了創(chuàng)建線程的幾種方式以及Thread類的幾個常用方法规哲,最后還說了一下Java線程的6個狀態(tài)以及其狀態(tài)轉(zhuǎn)換跟啤。本文是Java并發(fā)編程系列的第一篇,所以涉及的知識點不多,希望讀者理解隅肥。

6 參考資料

Java線程的6種狀態(tài)及切換(透徹講解)

Java多線程之中斷機(jī)制

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末竿奏,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子武福,更是在濱河造成了極大的恐慌议双,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,561評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件捉片,死亡現(xiàn)場離奇詭異平痰,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)伍纫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評論 3 385
  • 文/潘曉璐 我一進(jìn)店門宗雇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人莹规,你說我怎么就攤上這事赔蒲。” “怎么了良漱?”我有些...
    開封第一講書人閱讀 157,162評論 0 348
  • 文/不壞的土叔 我叫張陵舞虱,是天一觀的道長。 經(jīng)常有香客問我母市,道長矾兜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,470評論 1 283
  • 正文 為了忘掉前任患久,我火速辦了婚禮椅寺,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蒋失。我一直安慰自己返帕,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,550評論 6 385
  • 文/花漫 我一把揭開白布篙挽。 她就那樣靜靜地躺著荆萤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪嫉髓。 梳的紋絲不亂的頭發(fā)上观腊,一...
    開封第一講書人閱讀 49,806評論 1 290
  • 那天,我揣著相機(jī)與錄音算行,去河邊找鬼梧油。 笑死,一個胖子當(dāng)著我的面吹牛州邢,可吹牛的內(nèi)容都是我干的儡陨。 我是一名探鬼主播褪子,決...
    沈念sama閱讀 38,951評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼骗村!你這毒婦竟也來了嫌褪?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,712評論 0 266
  • 序言:老撾萬榮一對情侶失蹤胚股,失蹤者是張志新(化名)和其女友劉穎笼痛,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體琅拌,經(jīng)...
    沈念sama閱讀 44,166評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡缨伊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,510評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了进宝。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片刻坊。...
    茶點故事閱讀 38,643評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖党晋,靈堂內(nèi)的尸體忽然破棺而出谭胚,到底是詐尸還是另有隱情,我是刑警寧澤未玻,帶...
    沈念sama閱讀 34,306評論 4 330
  • 正文 年R本政府宣布灾而,位于F島的核電站,受9級特大地震影響扳剿,放射性物質(zhì)發(fā)生泄漏绰疤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,930評論 3 313
  • 文/蒙蒙 一舞终、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧癣猾,春花似錦敛劝、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至像捶,卻和暖如春上陕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背拓春。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評論 1 266
  • 我被黑心中介騙來泰國打工释簿, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人硼莽。 一個月前我還...
    沈念sama閱讀 46,351評論 2 360
  • 正文 我出身青樓庶溶,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子偏螺,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,509評論 2 348

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

  • 單任務(wù) 單任務(wù)的特點是排隊執(zhí)行行疏,也就是同步,就像再cmd輸入一條命令后套像,必須等待這條命令執(zhí)行完才可以執(zhí)行下一條命令...
    Steven1997閱讀 1,172評論 0 6
  • 本文是我自己在秋招復(fù)習(xí)時的讀書筆記酿联,整理的知識點,也是為了防止忘記夺巩,尊重勞動成果贞让,轉(zhuǎn)載注明出處哦!如果你也喜歡劲够,那...
    波波波先森閱讀 11,243評論 4 56
  • 進(jìn)程和線程 進(jìn)程 所有運行中的任務(wù)通常對應(yīng)一個進(jìn)程,當(dāng)一個程序進(jìn)入內(nèi)存運行時,即變成一個進(jìn)程.進(jìn)程是處于運行過程中...
    勝浩_ae28閱讀 5,089評論 0 23
  • 本文主要講了java中多線程的使用方法震桶、線程同步、線程數(shù)據(jù)傳遞征绎、線程狀態(tài)及相應(yīng)的一些線程函數(shù)用法蹲姐、概述等。在這之前...
    4ea0af17fd67閱讀 587評論 2 17
  • 要做個年終總結(jié)了人柿。在年末才從無知自在女開始努力轉(zhuǎn)變的我柴墩,2016沒有什么可擺出來說的。匆匆忙忙的寒假凫岖,渾渾噩噩的暑...
    申大喵閱讀 360評論 0 1