Java并發(fā)之線程基礎(chǔ)知識(shí)

0. 序言

  • Java并發(fā)付材,既然重點(diǎn)朦拖,亦是難點(diǎn)。
  • 并發(fā)厌衔,即多線程璧帝,指多個(gè)線程同一時(shí)間去做多個(gè)事情,示例:炒菜哥富寿,一人同時(shí)炒7個(gè)菜睬隶。
  • 并發(fā)相對(duì)的是單線程,指一件事情做完才做其他事情页徐,示例:炒完一個(gè)菜再去炒第二個(gè)菜苏潜。
  • 并發(fā)不同于并行,并行指的是兩個(gè)或更多任務(wù)同時(shí)進(jìn)行变勇,而并發(fā)指的兩個(gè)任務(wù)都請(qǐng)求執(zhí)行恤左,而處理只能接受一個(gè)任務(wù),就把兩個(gè)任務(wù)安排輪流執(zhí)行搀绣,由于時(shí)間間隔較短飞袋,使人感覺兩個(gè)任務(wù)都在運(yùn)行。
  • 本片博文的主要內(nèi)容有:
    • 創(chuàng)建線程常用的三種方式
    • 線程的生命周期
    • 線程的加入
    • 線程的中斷
    • 線程的禮讓
    • 線程的優(yōu)先級(jí)

1. 創(chuàng)建線程常用的三種方式

  • 繼承Thread類
public class Main {

    public static void main(String[] args) {
        new ThreadTest().start();
    }

    public static class ThreadTest extends Thread{
        private int count = 10;
        public void run(){
            while (true){
                System.out.print(count+" ");
                if (--count==0){
                    return;
                }
            }
        }
    }
}

說明:步驟:
① 定義類繼承Thread
② 重寫run方法
③ 把新線程要做的事寫在run方法中
④ 創(chuàng)建線程對(duì)象链患,并自動(dòng)執(zhí)行run方法巧鸭。

  • 實(shí)現(xiàn)Runnable接口
    如果需要繼承其他類(非Thread類),而且還要使當(dāng)前類實(shí)現(xiàn)多線程麻捻,那么可以通過Runnable接口來實(shí)現(xiàn)纲仍。
public class Main {

    public static void main(String[] args) {
        Runnable runnable = new ThreadTest();
        Thread thread = new Thread(runnable);
        thread.start();
    }

    public static class ThreadTest implements Runnable{
        private int count = 10;
        public void run(){
            while (true){
                System.out.print(count+" ");
                if (--count==0){
                    return;
                }
            }
        }
    }
}

說明:步驟:
① 定義類實(shí)現(xiàn)Runnable接口
② 重寫run方法
③ 將要寫的代碼寫在run方法中
④ 使用參數(shù)為Runnable對(duì)象的構(gòu)造方法創(chuàng)建Thread實(shí)例
⑤ 調(diào)用start方法啟動(dòng)線程

  • 實(shí)現(xiàn)Callable接口
    Callable接口屬于Executor框架中的功能類呀袱,Callable接口與Runnable接口的功能類似,但提供了比Runnable更強(qiáng)大的功能郑叠,主要表現(xiàn)為以下3點(diǎn):
    ① Callable可以在任務(wù)結(jié)束后提供一個(gè)返回值夜赵,Runnable無法提供這個(gè)功能。
    ② Callable中的call()方法可以拋出異常锻拘,而Runnable的run()方法不能拋出異常油吭。
    ③ 運(yùn)行Callable可以拿到一個(gè)Future對(duì)象,F(xiàn)uture對(duì)象表示異步計(jì)算的結(jié)果署拟,它提供了檢查計(jì)算是否完成的方法婉宰。由于線程屬于異步計(jì)算模型,因此無法從別的線程中得到函數(shù)的返回值推穷,在這種情況下就可以使用Future來監(jiān)視目標(biāo)線程調(diào)用Call()方法的情況心包。但調(diào)用Future的get()方法以獲取結(jié)果時(shí),當(dāng)前線程就會(huì)阻塞馒铃,直到Call()方法返回結(jié)果蟹腾。
public class Test implements Callable {

    public static void main(String[] args) {
        Test test = new Test();
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        Future submit = executorService.submit(test);
        try {
            Object o = submit.get();
            System.out.println(o);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }finally {
            executorService.shutdown();
        }
    }

    @Override
    public Boolean call() throws Exception {
         return true;
    }
}
true

說明:這里的情況還需要后續(xù)的文章進(jìn)行補(bǔ)充,通過這個(gè)小例子区宇,直到通過Callable接口可以在任務(wù)結(jié)束后得到一個(gè)返回值即可娃殖。

2. 線程的生命周期

  • 出生狀態(tài):New
Thread thread1 = new Thread(instance);
  • 就緒狀態(tài)(可執(zhí)行狀態(tài)):Ready
thread1.start();

說明:用戶調(diào)用start()方法后,線程就處于就緒狀態(tài)议谷。此時(shí)并沒有得到系統(tǒng)資源炉爆。

  • 運(yùn)行狀態(tài):Runnable
    說明:當(dāng)線程得到系統(tǒng)資源后就進(jìn)入運(yùn)行狀態(tài)。
  • 等待狀態(tài):Wating
    try {
            thread1.wait();
        } catch (InterruptedException e) {
            e

說明:等待狀態(tài)的線程必須調(diào)用Thread類中的nofify()方法才能被喚醒卧晓;notifyAll()方法是將所有處于等待狀態(tài)下的線程喚醒芬首。

  • 休眠狀態(tài)(超時(shí)等待狀態(tài)):Time waiting
Thread.sleep(5000);
  • 阻塞狀態(tài):Blocked
    說明:當(dāng)一個(gè)線程在運(yùn)行狀態(tài)下發(fā)出輸入/輸出請(qǐng)求,該線程進(jìn)入阻塞狀態(tài)逼裆;在其等待輸入/輸出結(jié)束時(shí)線程進(jìn)入就緒狀態(tài)郁稍,對(duì)于阻塞的線程來說,即使系統(tǒng)資源空閑胜宇,線程依然不能回到運(yùn)行狀態(tài)耀怜。
  • 終止?fàn)顟B(tài)(死亡狀態(tài)):Terminated
    說明:有兩種情況,分別是
    ① 當(dāng)線程的run方法執(zhí)行完畢時(shí)桐愉。
    ② 因?yàn)橐粋€(gè)沒有捕獲的異常而終止了run方法封寞。
  • 使線程處于就緒狀態(tài)的方法
    ① 調(diào)用sleep()方法
    ② 調(diào)用wati()方法
    ③ 等待輸入輸出完成
  • 使線程處于運(yùn)行狀態(tài)的方法
    ① 線程調(diào)用notify()方法
    ② 線程調(diào)用notifyAll()方法
    ③ 線程調(diào)用interrupt()方法
    ④ 線程的休眠時(shí)間結(jié)束
    ⑤ 輸入/輸出結(jié)束

3. 線程的加入

  • 舉例說明:
public class Test_Join {

    private static int A = 0;
    private static int B = 0;
    private  Thread thread01;
    private  Thread thread02;

    public Test_Join() {
         thread02 = new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                if (B == 99) {
                    System.out.println("B==99");
                }
                B++;
            }
        });

          thread01 = new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                if (A == 99) {
                    System.out.println("A == 99");
                }
                A++;
//                try {
//                    thread02.join();
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
            }
        });
    }

    private Thread getThread01() {
        return thread01;
    }

    private Thread getThread02() {
        return thread02;
    }

    public static void main(String[] args) {
        new Test_Join().getThread01().start();
        new Test_Join().getThread02().start();
    }
}

說明:
① 兩個(gè)線程分別給A或B++的操作,線程01先執(zhí)行仅财,應(yīng)該是線程01先到99。
② 添加thread02.join();以后碗淌,線程1在執(zhí)行了一個(gè)A++以后盏求,線程2就開始執(zhí)行抖锥,直到執(zhí)行結(jié)束,線程1才執(zhí)行碎罚。

4. 線程的中斷

  • 布爾值標(biāo)記的運(yùn)用
public class Test_Interrupt implements Runnable {

    private static boolean isContinue = false;
    private static int num = 0;
    static Test_Interrupt runnable = new Test_Interrupt();

    @Override
    public void run() {
        while (true){
            if (isContinue){
                break;
            }else{
                num++;
            }
        }
    }

    private static void setContinue(){
        isContinue = true;
    }

    public static void main(String[] args) {
        Thread thread = new Thread(runnable);
        thread.start();
        try {
            Thread.sleep(50);
            setContinue();
            System.out.println(num);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

說明:以往有的時(shí)候會(huì)使用stop()方法來停止線程磅废,但現(xiàn)在的JDK早就廢除了stop()方法,不建議使用【A遥現(xiàn)在提倡在run()方法中使用無限循環(huán)的形式拯勉,然后使用一個(gè)布爾型標(biāo)記控制循環(huán)的停止。

  • interrupt()方法的運(yùn)用
    如果線程是因?yàn)槭褂昧藄leep()或wait()方法進(jìn)入了就緒狀態(tài)憔购,可以使用Thread類的interrupt()方法使線程離開run()方法宫峦,同時(shí)結(jié)束線程,但程序會(huì)拋出InterruptedException異常玫鸟,用戶可以在處理該異常時(shí)完成線程的中斷業(yè)務(wù)處理导绷,如終止while循環(huán)。在項(xiàng)目中經(jīng)常在這里執(zhí)行關(guān)閉數(shù)據(jù)庫連接和關(guān)閉Socket連接等操作屎飘。
public class Test_Interrupt implements Runnable {

    private static boolean isContinue = false;
    private static int num = 0;
    static Test_Interrupt runnable = new Test_Interrupt();

    @Override
    public void run() {
        while (true) {
            if (isContinue) {
                break;
            } else {
                num++;
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    System.out.println("線程被中斷");
                    setContinue();
                }
            }
        }
    }

    private static void setContinue() {
        isContinue = true;
    }

    public static void main(String[] args) {
        Thread thread = new Thread(runnable);
        thread.start();
        thread.interrupt();
    }
}

說明:由于調(diào)用了interrupt()方法妥曲,所以拋出了InterruptedException異常,在異常中我們關(guān)閉while循環(huán)钦购。

5. 線程的禮讓

  • Thread類提供了一共禮讓方法yield()表示檐盟,不過它只是給當(dāng)前正處于運(yùn)行狀態(tài)下的線程一個(gè)提醒,告知它可以將資源禮讓給其他線程押桃,但這僅僅只是一個(gè)暗示葵萎,沒有任何一種機(jī)制保證當(dāng)前線程會(huì)將資源禮讓。
  • 對(duì)于支持多任務(wù)的操作系統(tǒng)來說怨规,不需要調(diào)用yield()方法陌宿,因?yàn)椴僮飨到y(tǒng)會(huì)為線程自動(dòng)分配CPU時(shí)間片來執(zhí)行。

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

  • 現(xiàn)在操作系統(tǒng)采用時(shí)分的形式調(diào)度運(yùn)行的線程波丰,操作系統(tǒng)會(huì)分出一個(gè)個(gè)時(shí)間片壳坪,線程會(huì)分配到若干時(shí)間片,當(dāng)線程的時(shí)間片用完了就會(huì)發(fā)生線程調(diào)度掰烟,并等待著下次分配爽蝴。線程分配到的時(shí)間片多少也決定了線程使用處理器資源的多少,而線程的優(yōu)先級(jí)就是決定線程需要多或者少分配一些處理器資源的線程屬性纫骑。
  • 在Java線程中蝎亚,通過整型成員變量priority來控制優(yōu)先級(jí),范圍是1~10先馆,線程創(chuàng)建的時(shí)候用setPriority(int)方法來修改優(yōu)先級(jí)发框,默認(rèn)優(yōu)先級(jí)是5,優(yōu)先級(jí)高的線程分配時(shí)間片的數(shù)量要多于優(yōu)先級(jí)低的線程煤墙。針對(duì)頻繁阻塞(休眠或者I/O操作)的線程需要設(shè)置較高優(yōu)先級(jí)梅惯,而偏重計(jì)算(需要較多CPU時(shí)間或者偏運(yùn)算)的線程則設(shè)置澆地的優(yōu)先級(jí)宪拥,確保處理器不會(huì)被獨(dú)占。
  • 然而在不同的JVM以及操作系統(tǒng)上铣减,線程規(guī)劃會(huì)存在差異她君,有些操作系統(tǒng)甚至?xí)雎詫?duì)線程優(yōu)先級(jí)的設(shè)定。所以程序正確性不能依賴線程的優(yōu)先級(jí)高低葫哗。

7. 后續(xù)

如果大家喜歡這篇文章缔刹,歡迎點(diǎn)贊!
如果想看更多 Java并發(fā) 方面的技術(shù)劣针,歡迎關(guān)注!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末校镐,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子酿秸,更是在濱河造成了極大的恐慌灭翔,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,451評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件辣苏,死亡現(xiàn)場離奇詭異肝箱,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)稀蟋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門煌张,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人退客,你說我怎么就攤上這事骏融。” “怎么了萌狂?”我有些...
    開封第一講書人閱讀 164,782評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵档玻,是天一觀的道長。 經(jīng)常有香客問我茫藏,道長误趴,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,709評(píng)論 1 294
  • 正文 為了忘掉前任务傲,我火速辦了婚禮凉当,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘售葡。我一直安慰自己看杭,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評(píng)論 6 392
  • 文/花漫 我一把揭開白布挟伙。 她就那樣靜靜地躺著楼雹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上烘豹,一...
    開封第一講書人閱讀 51,578評(píng)論 1 305
  • 那天瓜贾,我揣著相機(jī)與錄音,去河邊找鬼携悯。 笑死,一個(gè)胖子當(dāng)著我的面吹牛筷笨,可吹牛的內(nèi)容都是我干的憔鬼。 我是一名探鬼主播,決...
    沈念sama閱讀 40,320評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼胃夏,長吁一口氣:“原來是場噩夢啊……” “哼轴或!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起仰禀,我...
    開封第一講書人閱讀 39,241評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤照雁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后答恶,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體饺蚊,經(jīng)...
    沈念sama閱讀 45,686評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評(píng)論 3 336
  • 正文 我和宋清朗相戀三年悬嗓,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了污呼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,992評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡包竹,死狀恐怖燕酷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情周瞎,我是刑警寧澤苗缩,帶...
    沈念sama閱讀 35,715評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站声诸,受9級(jí)特大地震影響酱讶,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜双絮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評(píng)論 3 330
  • 文/蒙蒙 一浴麻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧囤攀,春花似錦软免、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春榛泛,著一層夾襖步出監(jiān)牢的瞬間蝌蹂,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評(píng)論 1 270
  • 我被黑心中介騙來泰國打工曹锨, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留孤个,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,173評(píng)論 3 370
  • 正文 我出身青樓沛简,卻偏偏與公主長得像齐鲤,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子椒楣,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評(píng)論 2 355

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

  • 進(jìn)程和線程 進(jìn)程 所有運(yùn)行中的任務(wù)通常對(duì)應(yīng)一個(gè)進(jìn)程,當(dāng)一個(gè)程序進(jìn)入內(nèi)存運(yùn)行時(shí),即變成一個(gè)進(jìn)程.進(jìn)程是處于運(yùn)行過程中...
    勝浩_ae28閱讀 5,108評(píng)論 0 23
  • 單任務(wù) 單任務(wù)的特點(diǎn)是排隊(duì)執(zhí)行给郊,也就是同步,就像再cmd輸入一條命令后捧灰,必須等待這條命令執(zhí)行完才可以執(zhí)行下一條命令...
    Steven1997閱讀 1,178評(píng)論 0 6
  • 進(jìn)程和線程 進(jìn)程 所有運(yùn)行中的任務(wù)通常對(duì)應(yīng)一個(gè)進(jìn)程,當(dāng)一個(gè)程序進(jìn)入內(nèi)存運(yùn)行時(shí),即變成一個(gè)進(jìn)程.進(jìn)程是處于運(yùn)行過程中...
    小徐andorid閱讀 2,808評(píng)論 3 53
  • Java多線程學(xué)習(xí) [-] 一擴(kuò)展javalangThread類 二實(shí)現(xiàn)javalangRunnable接口 三T...
    影馳閱讀 2,957評(píng)論 1 18
  • 本文主要講了java中多線程的使用方法淆九、線程同步、線程數(shù)據(jù)傳遞毛俏、線程狀態(tài)及相應(yīng)的一些線程函數(shù)用法炭庙、概述等。 首先講...
    李欣陽閱讀 2,456評(píng)論 1 15