JAVA之多線程

? 進程莽囤、線程和多線程

進程:

定義:進程是一個具有一定獨立功能的程序關(guān)于某個數(shù)據(jù)集合的一次運行活動。它是操作系統(tǒng)動態(tài)執(zhí)行的基本單元,在傳統(tǒng)的操作系統(tǒng)中羡宙,進程既是基本的分配單元,也是基本的執(zhí)行單元掐隐。

  • 第一狗热,進程是一個實體。每一個進程都有它自己的地址空間虑省,一般情況下匿刮,包括文本區(qū)域(text region)、數(shù)據(jù)區(qū)域(data region)和堆棧(stack region)探颈。文本區(qū)域存儲處理器執(zhí)行的代碼熟丸;數(shù)據(jù)區(qū)域存儲變量和進程執(zhí)行期間使用的動態(tài)分配的內(nèi)存;堆棧區(qū)域存儲著活動過程調(diào)用的指令和本地變量伪节。
  • 第二光羞,進程是一個“執(zhí)行中的程序”。程序是一個沒有生命的實體怀大,只有處理器賦予程序生命時纱兑,它才能成為一個活動的實體,我們稱其為進程化借。

狀態(tài):就緒潜慎、運行和阻塞
就緒狀態(tài)其實就是獲取了出cpu外的所有資源,在隊列中等待蓖康;運行就是獲得了處理器分配的資源铐炫,程序開始執(zhí)行;阻塞態(tài)蒜焊,當(dāng)程序條件不夠時候倒信,需要等待條件滿足時候才能執(zhí)行。

線程:

一個進程中可以包含若干個線程泳梆,當(dāng)然一個進程中至少有一個線程鳖悠,把線程作為獨立運行和獨立調(diào)度的基本單位唆迁,由于線程比進程更小,基本上不擁有系統(tǒng)資源竞穷,故對它的調(diào)度所付出的開銷就會小得多唐责,能更高效的提高系統(tǒng)多個程序間并發(fā)執(zhí)行的程度。
java創(chuàng)建線程三種方式:

  • 繼承Thread類創(chuàng)建線程
  • 實現(xiàn)Runnable接口創(chuàng)建線程
  • 使用Callable和Future創(chuàng)建線程
    1.創(chuàng)建Callable接口的實現(xiàn)類瘾带,并實現(xiàn)call()方法鼠哥,該call()方法將作為線程執(zhí)行體,且該call()方法沒有返回值看政,再創(chuàng)建Callable實現(xiàn)類的實例朴恳。(從java8開始,可以直接使用Lambda表達式創(chuàng)建Callable對象)允蚣。
    2.使用FutureTask類來包裝Callable對象于颖,該FutureTask對象封裝了該Callable對象的call()方法的返回值。
    3.使用FutureTask作為Thread對象的target創(chuàng)建并啟動新線程嚷兔。
    4.調(diào)用FutureTask對象的get方法來獲得子線程執(zhí)行結(jié)束后的返回值森渐。
多線程:

定義:指的是這個程序(一個進程)運行時產(chǎn)生了不止一個線程。

  • 并行:多個cpu實例或者多臺機器同時執(zhí)行一段處理邏輯冒晰,是真正的同時同衣。
  • 并發(fā):通過cpu調(diào)度算法,讓用戶看上去同時執(zhí)行壶运,實際上從cpu操作層面不是真正的同時耐齐。并發(fā)往往在場景中有公用的資源,那么針對這個公用的資源往往產(chǎn)生瓶頸蒋情,我們會用TPS或者QPS來反應(yīng)這個系統(tǒng)的處理能力埠况。
  • 線程安全:經(jīng)常用來描繪一段代碼。指在并發(fā)的情況之下棵癣,該代碼經(jīng)過多線程使用辕翰,線程的調(diào)度順序不影響任何結(jié)果。這個時候使用多線程浙巫,我們只需要關(guān)注系統(tǒng)的內(nèi)存金蜀,cpu是不是夠用即可刷后。反過來的畴,線程不安全就意味著線程的調(diào)度順序會影響最終結(jié)果,如不加事務(wù)的轉(zhuǎn)賬代碼尝胆。
  • 同步:Java中的同步指的是通過人為的控制和調(diào)度丧裁,保證共享資源的多線程訪問成為線程安全,來保證結(jié)果的準(zhǔn)確含衔。如上面的代碼簡單加入@synchronized關(guān)鍵字煎娇。在保證結(jié)果準(zhǔn)確的同時二庵,提高性能,才是優(yōu)秀的程序缓呛。線程安全的優(yōu)先級高于性能催享。
線程的狀態(tài):
  1. 新建狀態(tài)(New) : 線程對象被創(chuàng)建后,就進入了新建狀態(tài)哟绊。例如因妙,Thread thread = new Thread()。
  2. 就緒狀態(tài)(Runnable): 也被稱為“可執(zhí)行狀態(tài)”票髓。線程對象被創(chuàng)建后攀涵,其它線程調(diào)用了該對象的start()方法,從而來啟動該線程洽沟。例如以故,thread.start()。處于就緒狀態(tài)的線程裆操,隨時可能被CPU調(diào)度執(zhí)行怒详。
  3. 運行狀態(tài)(Running) : 線程獲取CPU權(quán)限進行執(zhí)行。需要注意的是踪区,線程只能從就緒狀態(tài)進入到運行狀態(tài)棘利。
  4. 阻塞狀態(tài)(Blocked) : 阻塞狀態(tài)是線程因為某種原因放棄CPU使用權(quán),暫時停止運行朽缴。直到線程進入就緒狀態(tài)善玫,才有機會轉(zhuǎn)到運行狀態(tài)。阻塞的情況分三種:
    (01) 等待阻塞 -- 通過調(diào)用線程的wait()方法密强,讓線程等待某工作的完成茅郎。
    (02) 同步阻塞 -- 線程在獲取synchronized同步鎖失敗(因為鎖被其它線程所占用),它會進入同步阻塞狀態(tài)或渤。
    (03) 其他阻塞 -- 通過調(diào)用線程的sleep()或join()或發(fā)出了I/O請求時饰剥,線程會進入到阻塞狀態(tài)喜爷。當(dāng)sleep()狀態(tài)超時、join()等待線程終止或者超時、或者I/O處理完畢時濒旦,線程重新轉(zhuǎn)入就緒狀態(tài)。
  5. 死亡狀態(tài)(Dead) : 線程執(zhí)行完了或者因異常退出了run()方法平窘,該線程結(jié)束生命周期炉旷。
高級多線程控制類:
  1. ThreadLocal類
    用處:保存線程的獨立變量。對一個線程類(繼承自Thread)
    當(dāng)使用ThreadLocal維護變量時地熄,ThreadLocal為每個使用該變量的線程提供獨立的變量副本华临,所以每一個線程都可以獨立地改變自己的副本,而不會影響其它線程所對應(yīng)的副本端考。常用于用戶登錄控制雅潭,如記錄session信息揭厚。
    實現(xiàn):每個Thread都持有一個TreadLocalMap類型的變量(該類是一個輕量級的Map,功能與map一樣扶供,區(qū)別是桶里放的是entry而不是entry的鏈表筛圆。功能還是一個map。)以本身為key椿浓,以目標(biāo)為value顽染。
    主要方法是get()和set(T a),set之后在map里維護一個threadLocal -> a轰绵,get時將a返回粉寞。ThreadLocal是一個特殊的容器。
  2. Lock類
    三個實現(xiàn):
    ReentrantLock:
    可重入的意義在于持有鎖的線程可以繼續(xù)持有左腔,并且要釋放對等的次數(shù)后才真正釋放該鎖唧垦。
    ReentrantReadWriteLock.ReadLock
    ReentrantReadWriteLock.WriteLock
    lock更靈活,可以自由定義多把鎖的加鎖解鎖順序(synchronized要按照先加的后解順序)
    提供多種加鎖方案液样,lock 阻塞式, trylock 無阻塞式, lockInterruptily 可打斷式振亮, 還有trylock的帶超時時間版本。和Condition類的結(jié)合鞭莽。
  3. BlockingQueue類
    阻塞隊列坊秸。該類是java.util.concurrent包下的重要類,通過對Queue的學(xué)習(xí)可以得知澎怒,這個queue是單向隊列褒搔,可以在隊列頭添加元素和在隊尾刪除或取出元素。類似于一個管  道喷面,特別適用于先進先出策略的一些應(yīng)用場景星瘾。普通的queue接口主要實現(xiàn)有PriorityQueue(優(yōu)先隊列)。
獲取線程異常:

線程無法通過try/catch獲取到異常惧辈。
寫的時候最好要設(shè)置線程名稱 Thread.name琳状,并設(shè)置線程組 ThreadGroup,目的是方便管理盒齿。在出現(xiàn)問題的時候念逞,打印線程棧 (jstack -pid) 一眼就可以看出是哪個線程出的問題,這個線程是干什么的边翁。

線程池:

線程池作用就是限制系統(tǒng)中執(zhí)行線程的數(shù)量翎承。
ThreadPoolExecutor:
常用的有四種:

  • newSingleThreadExecutor (創(chuàng)建一個單線程的線程池。)
  • newFixedThreadPool (創(chuàng)建固定大小的線程池倒彰。)
  • newCachedThreadPool (創(chuàng)建一個可緩存的線程池审洞。)
  • newScheduledThreadPool (創(chuàng)建一個支持定時以及周期性執(zhí)行任務(wù)的線程池。)
    設(shè)置線程池:限制最大線程待讳,如果是CPU密集型的任務(wù)芒澜,核心線程就用核數(shù),最大線程就用核數(shù)的N倍
什么時候出現(xiàn)僵死進程

當(dāng)一個進程創(chuàng)建了一個子進程時创淡,他們的運行時異步的痴晦。即父進程無法預(yù)知子進程會在什么時候結(jié)束,那么如果父進程很繁忙來不及wait 子進程時琳彩,那么當(dāng)子進程結(jié)束時誊酌,會不會丟失子進程的結(jié)束時的狀態(tài)信息呢?處于這種考慮unix提供了一種機制可以保證只要父進程想知道子進程結(jié)束時的信息露乏,它就可以得到碧浊。

這種機制是:在每個進程退出的時候,內(nèi)核釋放該進程所有的資源瘟仿,包括打開的文件箱锐,占用的內(nèi)存。但是仍然保留了一些信息(如進程號pid 退出狀態(tài) 運行時間等)劳较。這些保留的信息直到進程通過調(diào)用wait/waitpid時才會釋放驹止。這樣就導(dǎo)致了一個問題,如果沒有調(diào)用wait/waitpid的話观蜗,那么保留的信息就不會釋放臊恋。比如進程號就會被一直占用了。但系統(tǒng)所能使用的進程號的有限的墓捻,如果產(chǎn)生大量的僵尸進程抖仅,將導(dǎo)致系統(tǒng)沒有可用的進程號而導(dǎo)致系統(tǒng)不能創(chuàng)建進程。

如果父進程先結(jié)束砖第,而子進程后結(jié)束岸售,且沒有調(diào)用wait/waitpid來等待子進程的結(jié)束,每個進程結(jié)束時厂画,系統(tǒng)都會掃描當(dāng)前系統(tǒng)中運行的所有進程凸丸,看看有沒有哪個進程時剛剛結(jié)束的這個進程的子進程,如果有袱院,就有init來接管它屎慢,成為它的父進程。

  • 即:如果子進程先結(jié)束而父進程后結(jié)束忽洛,即子進程結(jié)束后腻惠,父進程還在繼續(xù)運行但是并未調(diào)用wait/waitpid那子進程就會成為僵尸進程。
如何實現(xiàn)線程安全:

基本上所有的并發(fā)模式在解決線程安全問題上欲虚,都采用“序列化訪問臨界資源”的方案集灌,即在同一時刻,只能有一個線程訪問臨界資源,也稱同步互斥訪問欣喧。通常來說腌零,是在訪問臨界資源的代碼前面加上一個鎖,當(dāng)訪問完臨界資源后釋放鎖唆阿,讓其他線程繼續(xù)訪問益涧。
用Synchronization或者Lock

CAS原子鎖:

CAS有3個操作數(shù),內(nèi)存值V驯鳖,舊的預(yù)期值A(chǔ)闲询,要修改的新值B。當(dāng)且僅當(dāng)預(yù)期值A(chǔ)和內(nèi)存值V相同時浅辙,將內(nèi)存值V修改為B扭弧,否則什么都不做。
TODO:具體還需要研究

ThreadLocal什么時候會出現(xiàn)OOM的情況?為什么?

ThreadLocalMap使用ThreadLocal的弱引用作為key记舆,如果一個ThreadLocal沒有外部強引用來引用它鸽捻,那么系統(tǒng) GC 的時候,這個ThreadLocal勢必會被回收氨淌,這樣一來泊愧,ThreadLocalMap中就會出現(xiàn)key為null的Entry,就沒有辦法訪問這些key為null的Entry的value盛正,如果當(dāng)前線程再遲遲不結(jié)束的話删咱,這些key為null的Entry的value就會一直存在一條強引用鏈:Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value永遠無法回收,造成內(nèi)存泄漏豪筝。

其實痰滋,ThreadLocalMap的設(shè)計中已經(jīng)考慮到這種情況,也加上了一些防護措施:在ThreadLocal的get(),set(),remove()的時候都會清除線程ThreadLocalMap里所有key為null的value续崖。

  1. 使用static的ThreadLocal敲街,延長了ThreadLocal的生命周期,可能導(dǎo)致內(nèi)存泄漏严望。
  2. 分配使用了ThreadLocal又不再調(diào)用get(),set(),remove()方法多艇,那么就會導(dǎo)致內(nèi)存泄漏,因為這塊內(nèi)存一直存在像吻。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末峻黍,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子拨匆,更是在濱河造成了極大的恐慌姆涩,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件惭每,死亡現(xiàn)場離奇詭異骨饿,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進店門宏赘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來绒北,“玉大人,你說我怎么就攤上這事置鼻≌蛞” “怎么了蜓竹?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵箕母,是天一觀的道長。 經(jīng)常有香客問我俱济,道長嘶是,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任蛛碌,我火速辦了婚禮聂喇,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蔚携。我一直安慰自己希太,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布酝蜒。 她就那樣靜靜地躺著誊辉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪亡脑。 梳的紋絲不亂的頭發(fā)上堕澄,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天,我揣著相機與錄音霉咨,去河邊找鬼蛙紫。 笑死,一個胖子當(dāng)著我的面吹牛途戒,可吹牛的內(nèi)容都是我干的坑傅。 我是一名探鬼主播,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼喷斋,長吁一口氣:“原來是場噩夢啊……” “哼唁毒!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起继准,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤枉证,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后移必,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體室谚,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了秒赤。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片猪瞬。...
    茶點故事閱讀 40,498評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖入篮,靈堂內(nèi)的尸體忽然破棺而出陈瘦,到底是詐尸還是另有隱情,我是刑警寧澤潮售,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布痊项,位于F島的核電站,受9級特大地震影響酥诽,放射性物質(zhì)發(fā)生泄漏鞍泉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一肮帐、第九天 我趴在偏房一處隱蔽的房頂上張望咖驮。 院中可真熱鬧,春花似錦训枢、人聲如沸托修。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽睦刃。三九已至,卻和暖如春仗处,著一層夾襖步出監(jiān)牢的瞬間眯勾,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工婆誓, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留吃环,地道東北人。 一個月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓洋幻,卻偏偏與公主長得像郁轻,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子文留,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,507評論 2 359

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

  • 進程和線程 進程 所有運行中的任務(wù)通常對應(yīng)一個進程,當(dāng)一個程序進入內(nèi)存運行時,即變成一個進程.進程是處于運行過程中...
    勝浩_ae28閱讀 5,117評論 0 23
  • 進程和線程 進程 所有運行中的任務(wù)通常對應(yīng)一個進程,當(dāng)一個程序進入內(nèi)存運行時,即變成一個進程.進程是處于運行過程中...
    小徐andorid閱讀 2,814評論 3 53
  • ??一個任務(wù)通常就是一個程序好唯,每個運行中的程序就是一個進程。當(dāng)一個程序運行時燥翅,內(nèi)部可能包含了多個順序執(zhí)行流骑篙,每個順...
    OmaiMoon閱讀 1,680評論 0 12
  • Thread(耦合,不推薦) Runnable(解耦森书,推薦) Executors ExecutorService ...
    如果仲有聽日閱讀 707評論 0 0
  • 生完寶寶后靶端,媽媽們見面第一句話往往就是:“你長了妊娠紋谎势,看來,妊娠紋真的很恐怖!那么杨名,我們產(chǎn)后如何去掉妊娠紋呢? ...
    paiqi2993閱讀 301評論 0 0