Java 線程

本文主要摘取自Java 線程簡介


線程基礎

什么是線程?

幾乎每種操作系統(tǒng)都支持進程的概念 ―― 進程就是在某種程度上相互隔離的、獨立運行的程序。
線程化是允許多個活動共存于一個進程中的工具。大多數(shù)現(xiàn)代的操作系統(tǒng)都支持線程及塘,而且線程的概念以各種形式已存在了好多年。Java 是第一個在語言本身中顯式地包含線程的主流編程語言锐极,它沒有把線程化看作是底層操作系統(tǒng)的工具笙僚。

每個 Java 程序都使用線程

每個 Java 程序都至少有一個線程 ― 主線程。當一個 Java 程序啟動時灵再,JVM 會創(chuàng)建主線程肋层,并在該線程中調用程序的 main() 方法。

JVM 還創(chuàng)建了其它線程檬嘀,您通常都看不到它們 ― 例如槽驶,與垃圾收集责嚷、對象終止和其它 JVM 內務處理任務相關的線程鸳兽。其它工具也創(chuàng)建線程,如 AWT(抽象窗口工具箱(Abstract Windowing Toolkit))或 Swing UI 工具箱罕拂、servlet 容器揍异、應用程序服務器和 RMI(遠程方法調用(Remote Method Invocation))。

為什么使用線程爆班?

在 Java 程序中使用線程有許多原因衷掷。如果您使用 Swing、servlet柿菩、RMI 或 Enterprise JavaBeans(EJB)技術戚嗅,您也許沒有意識到您已經在使用線程了。
使用線程的一些原因是它們可以幫助:

  • 使 UI 響應更快
  • 利用多處理器系統(tǒng)
  • 簡化建模
  • 執(zhí)行異步或后臺處理

線程的生命周期

創(chuàng)建線程

在 Java 程序中創(chuàng)建線程有幾種方法枢舶。每個 Java 程序至少包含一個線程:主線程懦胞。其它線程都是通過 Thread 構造器或實例化繼承類 Thread 的類來創(chuàng)建的。

Java 線程可以通過直接實例化 Thread 對象或實例化繼承 Thread 的對象來創(chuàng)建其它線程凉泄。在線程基礎 中的示例(其中躏尉,我們在十秒鐘之內計算盡量多的素數(shù))中,我們通過實例化 CalculatePrimes 類型的對象(它繼承了 Thread)后众,創(chuàng)建了一個線程胀糜。

當我們討論 Java 程序中的線程時颅拦,也許會提到兩個相關實體:完成工作的實際線程或代表線程的 Thread 對象。正在運行的線程通常是由操作系統(tǒng)創(chuàng)建的教藻;Thread 對象是由 Java VM 創(chuàng)建的距帅,作為控制相關線程的一種方式。

結束線程

線程會以以下三種方式之一結束:

  • 線程到達其 run() 方法的末尾怖竭。
  • 線程拋出一個未捕獲到的 ExceptionError锥债。
  • 另一個線程調用一個棄用的 stop() 方法。棄用是指這些方法仍然存在痊臭,但是您不應該在新代碼中使用它們哮肚,并且應該盡量從現(xiàn)有代碼中除去它們。

當 Java 程序中的所有線程都完成時广匙,程序就退出了允趟。

加入線程

Thread API 包含了等待另一個線程完成的方法:join() 方法。當調用 Thread.join() 時鸦致,調用線程將阻塞潮剪,直到目標線程完成為止。

Thread.join() 通常由使用線程的程序使用分唾,以將大問題劃分成許多小問題抗碰,每個小問題分配一個線程。本章結尾處的示例創(chuàng)建了十個線程绽乔,啟動它們弧蝇,然后使用 Thread.join() 等待它們全部完成。

調度

除了使用 Thread.join()Object.wait() 的時候折砸,線程調度和執(zhí)行的計時是不確定的看疗。如果兩個線程同時運行,而且都不等待睦授,您必須假設在任何兩個指令之間两芳,其它線程都可以運行并修改程序變量。如果線程要訪問其它線程可以看見的變量去枷,如從靜態(tài)字段(全局變量)直接或間接引用的數(shù)據怖辆,則必須使用同步以確保數(shù)據一致性。

在以下的簡單示例中删顶,我們將創(chuàng)建并啟動兩個線程竖螃,每個線程都打印兩行到 System.out

public class TwoThreads {
 
    public static class Thread1 extends Thread {
        public void run() {
            System.out.println("A");
            System.out.println("B");
        }
    }
 
    public static class Thread2 extends Thread {
        public void run() {
            System.out.println("1");
            System.out.println("2");
        }
    }
 
    public static void main(String[] args) {
        new Thread1().start();
        new Thread2().start();
    }
}

我們并不知道這些行按什么順序執(zhí)行,只知道“1”在“2”之前打印翼闹,以及“A”在“B”之前打印斑鼻。輸出可能是以下結果中的任何一種:

  • 1 2 A B
  • 1 A 2 B
  • 1 A B 2
  • A 1 2 B
  • A 1 B 2
  • A B 1 2

不僅不同機器之間的結果可能不同,而且在同一機器上多次運行同一程序也可能生成不同結果猎荠。永遠不要假設一個線程會在另一個線程之前執(zhí)行某些操作坚弱,除非您已經使用了同步以強制一個特定的執(zhí)行順序蜀备。

休眠

Thread API 包含了一個 sleep() 方法,它將使當前線程進入等待狀態(tài)荒叶,直到過了一段指定時間碾阁,或者直到另一個線程對當前線程的 Thread 對象調用了 Thread.interrupt(),從而中斷了線程些楣。當過了指定時間后脂凶,線程又將變成可運行的,并且回到調度程序的可運行線程隊列中愁茁。

如果線程是由對 Thread.interrupt() 的調用而中斷的蚕钦,那么休眠的線程會拋出 InterruptedException,這樣線程就知道它是由中斷喚醒的鹅很,就不必查看計時器是否過期嘶居。

Thread.yield() 方法就象 Thread.sleep() 一樣,但它并不引起休眠促煮,而只是暫停當前線程片刻邮屁,這樣其它線程就可以運行了供置。在大多數(shù)實現(xiàn)中韩玩,當較高優(yōu)先級的線程調用 Thread.yield() 時,較低優(yōu)先級的線程就不會運行鳖擒。

CalculatePrimes 示例使用了一個后臺線程計算素數(shù)绳匀,然后休眠十秒鐘芋忿。當計時器過期后,它就會設置一個標志襟士,表示已經過了十秒盗飒。

守護程序線程

我們提到過當 Java 程序的所有線程都完成時嚷量,該程序就退出陋桂,但這并不完全正確。隱藏的系統(tǒng)線程蝶溶,如垃圾收集線程和由 JVM 創(chuàng)建的其它線程會怎么樣嗜历?我們沒有辦法停止這些線程。如果那些線程正在運行抖所,那么 Java 程序怎么退出呢梨州?

這些系統(tǒng)線程稱作守護程序線程。Java 程序實際上是在它的所有非守護程序線程完成后退出的田轧。

任何線程都可以變成守護程序線程暴匠。可以通過調用 Thread.setDaemon() 方法來指明某個線程是守護程序線程傻粘。您也許想要使用守護程序線程作為在程序中創(chuàng)建的后臺線程每窖,如計時器線程或其它延遲的事件線程帮掉,只有當其它非守護程序線程正在運行時,這些線程才有用窒典。

小結

就象程序一樣蟆炊,線程有生命周期:它們啟動、執(zhí)行瀑志,然后完成涩搓。一個程序或進程也許包含多個線程,而這些線程看來互相單獨地執(zhí)行劈猪。

線程是通過實例化 Thread 對象或實例化繼承 Thread 的對象來創(chuàng)建的昧甘,但在對新的 Thread 對象調用 start() 方法之前,這個線程并沒有開始執(zhí)行战得。當線程運行到其 run() 方法的末尾或拋出未經處理的異常時疾层,它們就結束了。

sleep() 方法可以用于等待一段特定時間贡避;而 join() 方法可能用于等到另一個線程完成痛黎。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市刮吧,隨后出現(xiàn)的幾起案子湖饱,更是在濱河造成了極大的恐慌,老刑警劉巖杀捻,帶你破解...
    沈念sama閱讀 219,589評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件井厌,死亡現(xiàn)場離奇詭異,居然都是意外死亡致讥,警方通過查閱死者的電腦和手機仅仆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評論 3 396
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來垢袱,“玉大人墓拜,你說我怎么就攤上這事∏肫酰” “怎么了咳榜?”我有些...
    開封第一講書人閱讀 165,933評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長爽锥。 經常有香客問我涌韩,道長,這世上最難降的妖魔是什么氯夷? 我笑而不...
    開封第一講書人閱讀 58,976評論 1 295
  • 正文 為了忘掉前任臣樱,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘雇毫。我一直安慰自己奢啥,他們只是感情好,可當我...
    茶點故事閱讀 67,999評論 6 393
  • 文/花漫 我一把揭開白布嘴拢。 她就那樣靜靜地躺著桩盲,像睡著了一般。 火紅的嫁衣襯著肌膚如雪席吴。 梳的紋絲不亂的頭發(fā)上赌结,一...
    開封第一講書人閱讀 51,775評論 1 307
  • 那天,我揣著相機與錄音孝冒,去河邊找鬼柬姚。 笑死,一個胖子當著我的面吹牛庄涡,可吹牛的內容都是我干的量承。 我是一名探鬼主播,決...
    沈念sama閱讀 40,474評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼穴店,長吁一口氣:“原來是場噩夢啊……” “哼撕捍!你這毒婦竟也來了?” 一聲冷哼從身側響起泣洞,我...
    開封第一講書人閱讀 39,359評論 0 276
  • 序言:老撾萬榮一對情侶失蹤忧风,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后球凰,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體狮腿,經...
    沈念sama閱讀 45,854評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,007評論 3 338
  • 正文 我和宋清朗相戀三年呕诉,在試婚紗的時候發(fā)現(xiàn)自己被綠了缘厢。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,146評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡甩挫,死狀恐怖贴硫,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情捶闸,我是刑警寧澤夜畴,帶...
    沈念sama閱讀 35,826評論 5 346
  • 正文 年R本政府宣布拖刃,位于F島的核電站删壮,受9級特大地震影響,放射性物質發(fā)生泄漏兑牡。R本人自食惡果不足惜央碟,卻給世界環(huán)境...
    茶點故事閱讀 41,484評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧亿虽,春花似錦菱涤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至收毫,卻和暖如春攻走,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背此再。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評論 1 272
  • 我被黑心中介騙來泰國打工昔搂, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人输拇。 一個月前我還...
    沈念sama閱讀 48,420評論 3 373
  • 正文 我出身青樓摘符,卻偏偏與公主長得像,于是被迫代替她去往敵國和親策吠。 傳聞我的和親對象是個殘疾皇子逛裤,可洞房花燭夜當晚...
    茶點故事閱讀 45,107評論 2 356

推薦閱讀更多精彩內容

  • 進程和線程 進程 所有運行中的任務通常對應一個進程,當一個程序進入內存運行時,即變成一個進程.進程是處于運行過程中...
    勝浩_ae28閱讀 5,113評論 0 23
  • 下面是我自己收集整理的Java線程相關的面試題,可以用它來好好準備面試猴抹。 參考文檔:-《Java核心技術 卷一》-...
    阿呆變Geek閱讀 14,842評論 14 507
  • 前言:雖然自己平時都在用多線程别凹,也能完成基本的工作需求,但總覺得洽糟,還是對線程沒有一個系統(tǒng)的概念炉菲,所以,查閱了一些資...
    justCode_閱讀 708評論 0 9
  • 【JAVA 線程】 線程 進程:是一個正在執(zhí)行中的程序坤溃。每一個進程執(zhí)行都有一個執(zhí)行順序拍霜。該順序是一個執(zhí)行路徑,或者...
    Rtia閱讀 2,768評論 2 20
  • 參考:① Tensorflow的可視化工具Tensorboard的初步使用Link: https://blog.c...
    李2狗子閱讀 752評論 0 0