JAVA并發(fā)編程(二):線程知識


1. 線程和進程

  • 進程是代碼在數(shù)據(jù)集合上的一次運行活動, 是系統(tǒng)進行資源分配和調度的基本單位。
  • 線程則是進程的一個執(zhí)行路徑, 一個進程中至少有一個線程肥卡,進程中的線程共享進程的資源。線程是CPU 分配的基本單位事镣。
  • Java中步鉴,多個線程共享進程的堆和方法區(qū)資源,每個線程有自己的程序計數(shù)器和棧區(qū)域璃哟。
  • 程序計數(shù)器
    (1) 記錄了該線程讓出CPU時的執(zhí)行地址氛琢,待再次分配到時間片時線程就可以從計數(shù)器指定的地址繼續(xù)執(zhí)行。
    (2) 只有執(zhí)行的是Java 代碼時記錄的才是下一條指令的地址随闪,而對于native方法記錄的是undefined 地址阳似。
  • 棧資源
    (1) 存儲該線程的局部變量
    (2) 存放線程的調用棧幀

  • (1) 堆里面主要存放使用new 操作創(chuàng)建的對象實例
    (2) 堆是被進程中的所有線程共享的
  • 方法區(qū)用來存放JVM加載的類、常量及靜態(tài)變量等信息铐伴,是線程共享的撮奏。

2. 線程創(chuàng)建

  • 繼承Thread 類并重寫run方法
    (1) 創(chuàng)建完thread對象后該線程并沒有被啟動執(zhí)行,調用了start 方法后才真正啟動了線程当宴。
    (2) start 方法后線程處于就緒狀態(tài)畜吊,等待獲取CPU 資源。
    (3) 在run()方法內(nèi)可以使用this獲取當前線程户矢。
  //創(chuàng)建線程
  MyThread thread= new MyThread();
  // 啟動線程
  thread .start();
  • 實現(xiàn)Runnable接口的run 方法
    (1) 多個線程可共用一個task 代碼邏輯玲献。
    (2) 在實現(xiàn)接口的同時可以繼承其他類。
  RunableTask task =new RunableTask();
  new Thread(task).start() ;
  new Thread(task).start() ;
  • 使用FutureTask 方式
    (1) 實現(xiàn)Callable 接口的call()方法。
    (2) 可以拿到任務的返回結果捌年。
  static class CallerTask implements Callable<String>{
    @Override
    public String call() throws Exception{}
  }
  //創(chuàng)建異步任務
  FutureTask<String> futureTask =new FutureTask<>(new CallerTask()) ;
  //啟動線程
  new Thread(futureTask).start () ;
  try {
    //等待任務執(zhí)行完畢瓢娜,并返回結果
    String result = futureTask.get ();
  } catch (ExecutionException e) {}

3. 線程通知與等待

  • wait()函數(shù)
    當一個線程調用一個共享變量的wait()方法時,該調用線程會被阻塞掛起延窜,直到發(fā)生以下情況才返回:
    (1) 其他線程調用了該共享對象的notify()或者notifyAll()方法恋腕;
    (2) 其他線程調用了該線程的interrupt()方法抹锄,該線程拋出InterruptedException異常返回逆瑞。

    調用wait()方法的線程需要先獲取該對象的監(jiān)視器鎖,否則會拋出IllegalMonitorStateException異常
    通過以下方式獲取監(jiān)視器鎖
    (1) 執(zhí)行synchronized 同步代碼塊時伙单, 使用該共享變量作為參數(shù)获高。
    (2) 調用該共享變量的方法,并且該方法使用了synchronized 修飾吻育。


4. 線程睡眠

  • sleep方法:
    (1) 當一個執(zhí)行中的線程調用了Thread 的sleep方法后念秧,會暫時讓出指定時間的執(zhí)行權,不參與CPU的調度
    (2) 該線程擁有的監(jiān)視器資源布疼,比如鎖還是持有不會讓出摊趾。
    (3) 睡眠時間到了后該線程處于就緒狀態(tài),等待獲取cpu資源游两。
    (4) 在睡眠期間其他線程調用了該線程的interrupt方法中斷了該線程砾层,則該線程會在調用sleep方法的地方拋出IntermptedException異常而返回。
  • yield方法:
    (1) 線程調用yield 方法時贱案,是在暗示線程調度器當前線程請求讓出自己的CPU 使用肛炮,讓線程調度器現(xiàn)在就可以進行下一輪的線程調度,但是線程調度器可以無條件忽略這個暗示宝踪。
    (2) 調用yield 方法時后侨糟,當前線程會讓出CPU 使用權,然后處于就緒狀態(tài)瘩燥,線程調度器下一次調度時就有可能調度到當前線程執(zhí)行秕重。

5. 線程中斷

  • Java 中的線程中斷是一種線程間的協(xié)作模式,通過設置線程的中斷標志并不能直接終止該線程的執(zhí)行厉膀, 而是被中斷的線程根據(jù)中斷狀態(tài)自行處理溶耘。

  • interrupt方法:中斷線程
    (1) 線程B可以調用線程A的interrupt方法來設置線程A 的中斷標志為true并立即返回。
    (2) 如果線程A 因為調用了wait 系列函數(shù)站蝠、join 方法或者sleep 方法而被阻塞掛起汰具,會在調用這些方法的地方拋出InterruptedException 異常而返回。

  • 線程上下文切換時機有:
    (1) 當前線程的CPU 時間片使用完處于就緒狀態(tài)時
    (2) 當前線程被其他線程中斷時


6. 線程死鎖

  • 死鎖是指兩個或兩個以上的線程在執(zhí)行過程中菱魔,因爭奪對方已經(jīng)持有的資源而造成的互相等待的現(xiàn)象留荔。

  • 死鎖的產(chǎn)生必須具備四個條件:
    互斥條件:該資源同時只由一個線程占用。
    請求并持有條件: 指一個線程己經(jīng)持有了至少一個資源, 但又提出了新的資源請求聚蝶,而新資源己被其他線程占有杰妓,所以當前線程會被阻塞,但阻塞的同時并不釋放自己已經(jīng)獲取的資源碘勉。
    不可剝奪條件: 指線程獲取到的資源在自己使用完之前不能被其他線程搶占巷挥。
    環(huán)路等待條件:發(fā)生死鎖時, 必然存在一個線程-資源的環(huán)形鏈验靡。

  • 避免死鎖:
    (1) 只有請求并持有和環(huán)路等待條件是可以被破壞的倍宾。
    (2) 造成死鎖的原因其實和申請資源的順序有很大關系, 使用資源申請的有序性原則就可以避免死鎖胜嗓。
    (3) 資源申請的有序性:假如線程A 和線程B 都需要資源1, 2, 3, ... , n 時高职,對資源進行排序,線程A 和線程B 只有在獲取了資源n-1 時才能去獲取資源n 辞州。


6. 守護線程與用戶線程

  • Java 中的線程分為兩類怔锌,daemon 線程(守護線程〉和user 線程(用戶線程)。
  • 守護線程
    (1) 在JVM啟動的同時变过,啟動了好多守護線程埃元, 比如垃圾回收線程
    (2) 守護線程是否結束并不影響JVM的退出,只要用戶線程都退出了媚狰,就會終止JVM進程岛杀。如果你希望在主線程結束后JVM進程馬上結束,那么在創(chuàng)建線程時可以將其設置為守護線程哈雏。
    (3) 設置守護線程: thread.setDaemon(true) ;
    (4) main線程運行結束后楞件, JVM會自動啟動一個叫作DestroyJava VM 的線程, 該線程會等待所有用戶線程結束后終止JVM進程裳瘪。
    (5) 在默認情況下土浸, tomcat的接受線程和處理線程都是守護線程, 這意味著當tomcat收到shutdown 命令后并且沒有其他用戶線程存在的情況下tomcat 進程會馬上消亡彭羹,而不會等待處理線程處理完當前的請求黄伊。

7. ThreadLocal

  • 提供了線程本地變量,如果創(chuàng)建了一個ThreadLocal 變量派殷,那么訪問這個變量的每個線程都會有這個變量的一個本地副本还最。
  • 使用
//創(chuàng)建ThreadLocal 變量
ThreadLocal<String> localVariable = new ThreadLocal<> () ;
//在線程1中
localVariable.set("threadOne local variable");
//在線程2中
localVariable.set("threadTwo local variable");
//在某個線程中獲取變量
localVariable.get()
  • 原理
    (1) 在每個線程內(nèi)部都有一個名為threadLocals 的成員變量, 該變量的類型為HashMap毡惜,用于存儲線程本地變量拓轻。key 為我們定義的ThreadLocal變量的this引用, value 則為我們使用set 方法設置的值经伙。
    (2) ThreadLocal只是相當于一個工具類扶叉,它通過set 方法把value 值放入調用線程的threadLocals 里面并存放起來, 當調用線程調用它的get 方法時,再從當前線程的threadLocals 變量里面將其拿出來使用枣氧。
    (3) 為了防止內(nèi)存溢出溢十,在使用完后,記得通過ThreadLocal的remove方法移除變量达吞。
    (4) 同一個ThreadLocal 變量在父線程中被設置值后张弛, 在子線程中是獲取不到的。

  • InheritableThreadLocal: 讓子線程能訪問到父線程中的值
    (1) InheritabIeThreadLocal 繼承了ThreadLocal酪劫,set和get操作的是該線程的成員變量inheritableThreadLocals吞鸭。
    (2) 在創(chuàng)建線程時,會判斷當前線程(父線程)中的inheritableThreadLocals變量是否為空契耿,如果不為空瞒大,會把父線程的inheritableThreadLocals 成員變量的值復制到子線程的inheritableThreadLocals變量中。這樣子線程就擁有了一份父線程的可繼承的變量的副本搪桂。
    (3) 父線程和子線程的相互影響關系可以查看https://blog.csdn.net/v123411739/article/details/79117430
    對于可變對象:父線程初始化, 因為Thread Construct淺拷貝, 共用索引, 子線程修改父線程跟著變; 父線程不初始化, 子線程初始化, 無Thread Construct淺拷貝, 子線程和父線程都是單獨引用, 不同對象, 子線程修改父線程不跟著變。
    對于不可變對象:不可變對象由于每次都是新對象, 所以無論父線程初始化與否盯滚,子線程和父線程都互不影響踢械。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市魄藕,隨后出現(xiàn)的幾起案子内列,更是在濱河造成了極大的恐慌,老刑警劉巖背率,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件话瞧,死亡現(xiàn)場離奇詭異,居然都是意外死亡寝姿,警方通過查閱死者的電腦和手機交排,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來饵筑,“玉大人埃篓,你說我怎么就攤上這事「剩” “怎么了架专?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長玄帕。 經(jīng)常有香客問我部脚,道長,這世上最難降的妖魔是什么裤纹? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任委刘,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘钱雷。我一直安慰自己骂铁,他們只是感情好,可當我...
    茶點故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布罩抗。 她就那樣靜靜地躺著拉庵,像睡著了一般。 火紅的嫁衣襯著肌膚如雪套蒂。 梳的紋絲不亂的頭發(fā)上钞支,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天,我揣著相機與錄音操刀,去河邊找鬼烁挟。 笑死,一個胖子當著我的面吹牛骨坑,可吹牛的內(nèi)容都是我干的撼嗓。 我是一名探鬼主播,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼欢唾,長吁一口氣:“原來是場噩夢啊……” “哼且警!你這毒婦竟也來了?” 一聲冷哼從身側響起礁遣,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤斑芜,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后祟霍,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體杏头,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年沸呐,在試婚紗的時候發(fā)現(xiàn)自己被綠了醇王。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,650評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡垂谢,死狀恐怖厦画,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情滥朱,我是刑警寧澤根暑,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站徙邻,受9級特大地震影響排嫌,放射性物質發(fā)生泄漏。R本人自食惡果不足惜缰犁,卻給世界環(huán)境...
    茶點故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一淳地、第九天 我趴在偏房一處隱蔽的房頂上張望怖糊。 院中可真熱鬧,春花似錦颇象、人聲如沸伍伤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽扰魂。三九已至,卻和暖如春蕴茴,著一層夾襖步出監(jiān)牢的瞬間劝评,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工倦淀, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蒋畜,地道東北人。 一個月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓撞叽,卻偏偏與公主長得像姻成,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子能扒,可洞房花燭夜當晚...
    茶點故事閱讀 43,527評論 2 349