多線程呕诉、并發(fā)問(wèn)題甩挫、鎖編程基本概念

注:本文主要是總結(jié)下多線程椿每、并發(fā)編程、鎖編程相關(guān)概念挖诸,內(nèi)容相對(duì)簡(jiǎn)略法精。

注:如有侵權(quán)亿虽,請(qǐng)聯(lián)系刪除洛勉。

1收毫、什么是多線程

線程是程序執(zhí)行的最小單位此再,多個(gè)線程并發(fā)或并行執(zhí)行就是多線程。多線程下需要保證執(zhí)行結(jié)果的最終正確性玲销。

  • 并發(fā):兩個(gè)及兩個(gè)以上的作業(yè)在同一 時(shí)間段 內(nèi)執(zhí)行输拇。

  • 并行:兩個(gè)及兩個(gè)以上的作業(yè)在同一 時(shí)刻 執(zhí)行。

2贤斜、為什么使用多線程

  • 充分發(fā)揮多核性能優(yōu)勢(shì)

  • 單一線程同步執(zhí)行IO操作時(shí)策吠,存在長(zhǎng)時(shí)間的阻塞,無(wú)法充分使用CPU

3瘩绒、多線程下可能導(dǎo)致什么問(wèn)題

根本問(wèn)題:最終結(jié)果與單線程執(zhí)行結(jié)果不一致猴抹。

常見(jiàn)衍生問(wèn)題:

  • 死鎖

  • 內(nèi)存泄漏

  • 線程不安全

  • ...

4、線程模型:用戶線程和內(nèi)核線程之間的關(guān)聯(lián)方式

多對(duì)一蟀给、一對(duì)一、多對(duì)多

three-types-of-thread-models.png

5阳堕、線程生命周期和狀態(tài):

  • 初始狀態(tài)

  • 運(yùn)行狀態(tài)

  • 阻塞狀態(tài)

  • 等待狀態(tài)

  • 超時(shí)等待狀態(tài)

  • 結(jié)束狀態(tài)

threadStatus.png

6跋理、線程間通信

  • 管道流

  • 等待/通知機(jī)制

  • 共享內(nèi)存

  • threadLocal

7、線程上下文切換是什么恬总,什么場(chǎng)景下發(fā)生前普?

線程上下文切換是指在特定場(chǎng)景下,在CPU上執(zhí)行的線程發(fā)生變化越驻,需要記錄上個(gè)線程的執(zhí)行狀態(tài)汁政, 以及恢復(fù)新線程之前的執(zhí)行狀態(tài)道偷。

  • 線程主動(dòng)讓出cpu

  • 線程CPU時(shí)間片用盡,系統(tǒng)調(diào)度防止其他線程餓死记劈。

  • 系統(tǒng)中斷

  • 線程任務(wù)執(zhí)行完成

8勺鸦、死鎖四個(gè)必要條件:

1、互斥條件

2目木、不可剝奪條件

3换途、請(qǐng)求與保持條件

4、循環(huán)等待

9刽射、JMM

指令重排序:JIT編譯優(yōu)化 + CPU指令重排序

happenBefore原則

JMM.png

線程安全三大特性:原子性军拟、可見(jiàn)性、有序性

10誓禁、CAS(Compare-And-Swap, 比較并交換)

在 Java 中懈息,實(shí)現(xiàn) CAS(Compare-And-Swap, 比較并交換)操作的一個(gè)關(guān)鍵類是Unsafe

CAS 算法存在以下問(wèn)題
  • ABA 問(wèn)題是 CAS 算法最常見(jiàn)的問(wèn)題摹恰。

    ABA 問(wèn)題的解決思路是在變量前面追加上版本號(hào)或者時(shí)間戳辫继。JDK 1.5 以后的 AtomicStampedReference 類就是用來(lái)解決 ABA 問(wèn)題的,其中的 compareAndSet() 方法就是首先檢查當(dāng)前引用是否等于預(yù)期引用俗慈,并且當(dāng)前標(biāo)志是否等于預(yù)期標(biāo)志姑宽,如果全部相等,則以原子方式將該引用和該標(biāo)志的值設(shè)置為給定的更新值闺阱。

  • 循環(huán)時(shí)間長(zhǎng)開(kāi)銷大

    依照使用場(chǎng)景來(lái)選擇是否使用CAS炮车,寫多讀少,用鎖酣溃,讀多寫少瘦穆, 用CAS

  • 只能保證一個(gè)共享變量的原子操作

    CAS 操作僅能對(duì)單個(gè)共享變量有效。當(dāng)需要操作多個(gè)共享變量時(shí)救拉,CAS 就顯得無(wú)能為力难审。不過(guò),從 JDK 1.5 開(kāi)始亿絮,Java 提供了AtomicReference類告喊,這使得我們能夠保證引用對(duì)象之間的原子性。通過(guò)將多個(gè)變量封裝在一個(gè)對(duì)象中派昧,我們可以使用AtomicReference來(lái)執(zhí)行 CAS 操作黔姜。

11、synchronized 關(guān)鍵字

在 Java 6 之后蒂萎, synchronized 引入了大量的優(yōu)化如自旋鎖秆吵、適應(yīng)性自旋鎖、鎖消除五慈、鎖粗化纳寂、偏向鎖主穗、輕量級(jí)鎖等技術(shù)來(lái)減少鎖操作的開(kāi)銷,實(shí)現(xiàn)核心原理是對(duì)象monitor的獲取毙芜,對(duì)象頭中有鎖標(biāo)志位忽媒。

12、ReentrantLock

ReentrantLock 比 synchronized 增加了一些高級(jí)功能
  • 公平與非公平實(shí)現(xiàn)

  • 可中斷

  • 可選擇通知

13腋粥、ThreadLocal

ThreadLocal原理

最終的變量是放在了當(dāng)前線程的 ThreadLocalMap 中晦雨,并不是存在 ThreadLocal 上,ThreadLocal 可以理解為只是ThreadLocalMap的封裝隘冲,傳遞了變量值闹瞧。 ThrealLocal 類中可以通過(guò)Thread.currentThread()獲取到當(dāng)前線程對(duì)象后,直接通過(guò)getMap(Thread t)可以訪問(wèn)到該線程的ThreadLocalMap對(duì)象展辞。

每個(gè)Thread中都具備一個(gè)ThreadLocalMap奥邮,而ThreadLocalMap可以存儲(chǔ)以ThreadLocal為 key ,Object 對(duì)象為 value 的鍵值對(duì)罗珍。

ThreadLocal 內(nèi)存泄露問(wèn)題

ThreadLocalMap 中使用的 key 為 ThreadLocal 的弱引用漠烧,而 value 是強(qiáng)引用。所以靡砌,如果 ThreadLocal 沒(méi)有被外部強(qiáng)引用的情況下,在垃圾回收的時(shí)候珊楼,key 會(huì)被清理掉通殃,而 value 不會(huì)被清理掉。

這樣一來(lái)厕宗,ThreadLocalMap 中就會(huì)出現(xiàn) key 為 null 的 Entry画舌。假如我們不做任何措施的話,value 永遠(yuǎn)無(wú)法被 GC 回收已慢,這個(gè)時(shí)候就可能會(huì)產(chǎn)生內(nèi)存泄露曲聂。ThreadLocalMap 實(shí)現(xiàn)中已經(jīng)考慮了這種情況,在調(diào)用 set()佑惠、get()朋腋、remove() 方法的時(shí)候,會(huì)清理掉 key 為 null 的記錄膜楷。使用完 ThreadLocal方法后最好手動(dòng)調(diào)用remove()方法

14旭咽、線程池

池化技術(shù)

優(yōu)點(diǎn):

  • 降低資源消耗。通過(guò)重復(fù)利用已創(chuàng)建的線程降低線程創(chuàng)建和銷毀造成的消耗赌厅。

  • 提高響應(yīng)速度穷绵。當(dāng)任務(wù)到達(dá)時(shí),任務(wù)可以不需要等到線程創(chuàng)建就能立即執(zhí)行特愿。

  • 提高線程的可管理性仲墨。線程是稀缺資源勾缭,如果無(wú)限制的創(chuàng)建,不僅會(huì)消耗系統(tǒng)資源目养,還會(huì)降低系統(tǒng)的穩(wěn)定性俩由,使用線程池可以進(jìn)行統(tǒng)一的分配,調(diào)優(yōu)和監(jiān)控混稽。

Java創(chuàng)建線程池參數(shù):核心線程數(shù)采驻、最大線程數(shù)、空線程存活時(shí)間匈勋、時(shí)間單位礼旅、任務(wù)隊(duì)列、丟棄策略洽洁、線程工廠痘系。

線程池的拒絕策略

如果當(dāng)前同時(shí)運(yùn)行的線程數(shù)量達(dá)到最大線程數(shù)量并且隊(duì)列也已經(jīng)被放滿了任務(wù)時(shí),ThreadPoolExecutor 定義一些策略:

  • ThreadPoolExecutor.AbortPolicy:拋出 RejectedExecutionException來(lái)拒絕新任務(wù)的處理饿自。

  • ThreadPoolExecutor.CallerRunsPolicy:調(diào)用執(zhí)行自己的線程運(yùn)行任務(wù)汰翠,也就是直接在調(diào)用execute方法的線程中運(yùn)行(run)被拒絕的任務(wù),如果執(zhí)行程序已關(guān)閉昭雌,則會(huì)丟棄該任務(wù)复唤。因此這種策略會(huì)降低對(duì)于新任務(wù)提交速度,影響程序的整體性能烛卧。如果你的應(yīng)用程序可以承受此延遲并且你要求任何一個(gè)任務(wù)請(qǐng)求都要被執(zhí)行的話佛纫,你可以選擇這個(gè)策略。

  • ThreadPoolExecutor.DiscardPolicy:不處理新任務(wù)总放,直接丟棄掉呈宇。

  • ThreadPoolExecutor.DiscardOldestPolicy:此策略將丟棄最早的未處理的任務(wù)請(qǐng)求。

拓展:

如果服務(wù)器資源以達(dá)到可利用的極限局雄,這就意味我們要在設(shè)計(jì)策略上改變線程池的調(diào)度了甥啄,我們都知道,導(dǎo)致主線程卡死的本質(zhì)就是因?yàn)槲覀儾幌M魏我粋€(gè)任務(wù)被丟棄炬搭。換個(gè)思路蜈漓,有沒(méi)有辦法既能保證任務(wù)不被丟棄且在服務(wù)器有余力時(shí)及時(shí)處理呢?

這里提供的一種任務(wù)持久化的思路尚蝌,這里所謂的任務(wù)持久化迎变,包括但不限于:

  1. 設(shè)計(jì)一張任務(wù)表將任務(wù)存儲(chǔ)到 MySQL 數(shù)據(jù)庫(kù)中。

  2. Redis 緩存任務(wù)飘言。

  3. 將任務(wù)提交到消息隊(duì)列中衣形。

這里以方案一為例,簡(jiǎn)單介紹一下實(shí)現(xiàn)邏輯:

  1. 實(shí)現(xiàn)RejectedExecutionHandler接口自定義拒絕策略,自定義拒絕策略負(fù)責(zé)將線程池暫時(shí)無(wú)法處理(此時(shí)阻塞隊(duì)列已滿)的任務(wù)入庫(kù)(保存到 MySQL 中)谆吴。注意:線程池暫時(shí)無(wú)法處理的任務(wù)會(huì)先被放在阻塞隊(duì)列中倒源,阻塞隊(duì)列滿了才會(huì)觸發(fā)拒絕策略。

  2. 繼承BlockingQueue實(shí)現(xiàn)一個(gè)混合式阻塞隊(duì)列句狼,該隊(duì)列包含 JDK 自帶的ArrayBlockingQueue笋熬。另外,該混合式阻塞隊(duì)列需要修改取任務(wù)處理的邏輯腻菇,也就是重寫take()方法胳螟,取任務(wù)時(shí)優(yōu)先從數(shù)據(jù)庫(kù)中讀取最早的任務(wù),數(shù)據(jù)庫(kù)中無(wú)任務(wù)時(shí)再?gòu)?ArrayBlockingQueue中去取任務(wù)筹吐。

常用阻塞隊(duì)列
  • LinkedBlockingQueue

  • ArrayBlockingQueue

  • SynchronousQueue

  • DelayedWorkedQueue

線程池中線程異常是復(fù)用還是銷毀糖耸?
  • execute 銷毀

  • submit 復(fù)用

核心線程數(shù)參數(shù)確定

CPU密集型 (N+1)

IO密集型(2N)

如果有資源的話 ,結(jié)合實(shí)際情況具體壓測(cè)下丘薛。

動(dòng)態(tài)線程池

https://mp.weixin.qq.com/s/9HLuPcoWmTqAeFKa1kj-_A

15嘉竟、CompletableFuture

引用:CompletableFuture從入門、踩坑洋侨、迷茫舍扰、到精通(全網(wǎng)看這一篇夠了)_completablefuture.get()坑-CSDN博客

16、AQS

引用:AQS 詳解 | JavaGuide

17希坚、為什么 wait() 方法不定義在 Thread 中边苹?

wait() 是讓獲得對(duì)象鎖的線程實(shí)現(xiàn)等待,會(huì)自動(dòng)釋放當(dāng)前線程占有的對(duì)象鎖裁僧。每個(gè)對(duì)象(Object)都擁有對(duì)象鎖勾给,既然要釋放當(dāng)前線程占有的對(duì)象鎖并讓其進(jìn)入 WAITING 狀態(tài),自然是要操作對(duì)應(yīng)的對(duì)象(Object)而非當(dāng)前的線程(Thread)锅知。

類似的問(wèn)題:為什么 sleep() 方法定義在 Thread 中?

因?yàn)?sleep() 是讓當(dāng)前線程暫停執(zhí)行脓钾,不涉及到對(duì)象類售睹,也不需要獲得對(duì)象鎖。

18可训、如何理解線程安全和不安全昌妹?

線程安全和不安全是在多線程環(huán)境下對(duì)于同一份數(shù)據(jù)的訪問(wèn)是否能夠保證其正確性和一致性的描述。

  • 線程安全指的是在多線程環(huán)境下握截,對(duì)于同一份數(shù)據(jù)飞崖,不管有多少個(gè)線程同時(shí)訪問(wèn),都能保證這份數(shù)據(jù)的正確性和一致性谨胞。

  • 線程不安全則表示在多線程環(huán)境下固歪,對(duì)于同一份數(shù)據(jù),多個(gè)線程同時(shí)訪問(wèn)時(shí)可能會(huì)導(dǎo)致數(shù)據(jù)混亂、錯(cuò)誤或者丟失牢裳。

19逢防、如何預(yù)防死鎖? 破壞死鎖的產(chǎn)生的必要條件即可:

  1. 破壞請(qǐng)求與保持條件:一次性申請(qǐng)所有的資源蒲讯。

  2. 破壞不剝奪條件:占用部分資源的線程進(jìn)一步申請(qǐng)其他資源時(shí)忘朝,如果申請(qǐng)不到,可以主動(dòng)釋放它占有的資源判帮。

  3. 破壞循環(huán)等待條件:靠按序申請(qǐng)資源來(lái)預(yù)防局嘁。按某一順序申請(qǐng)資源,釋放資源則反序釋放晦墙。破壞循環(huán)等待條件悦昵。

這個(gè)讓我想起了經(jīng)典的哲學(xué)家進(jìn)餐問(wèn)題:

如上有三種解法:

1、設(shè)置臨界區(qū)偎痛,一個(gè)人一次性申請(qǐng)左右兩個(gè)叉子旱捧。

2、設(shè)置信號(hào)量踩麦,最多 4人同時(shí)持有叉子枚赡。

3、奇數(shù)位申請(qǐng)順序谓谦,先左后右贫橙;偶數(shù)位先右后左。

關(guān)于多線程反粥,多考量下業(yè)務(wù)場(chǎng)景

引用目錄

AQS 詳解 | JavaGuide

CompletableFuture從入門卢肃、踩坑、迷茫才顿、到精通(全網(wǎng)看這一篇夠了)_completablefuture.get()坑-CSDN博客

https://mp.weixin.qq.com/s/9HLuPcoWmTqAeFKa1kj-_A

Java并發(fā)常見(jiàn)面試題總結(jié)(下) | JavaGuide

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末莫湘,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子郑气,更是在濱河造成了極大的恐慌幅垮,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,589評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件尾组,死亡現(xiàn)場(chǎng)離奇詭異忙芒,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)讳侨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門呵萨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人跨跨,你說(shuō)我怎么就攤上這事潮峦。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,933評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵跑杭,是天一觀的道長(zhǎng)铆帽。 經(jīng)常有香客問(wèn)我,道長(zhǎng)德谅,這世上最難降的妖魔是什么爹橱? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,976評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮窄做,結(jié)果婚禮上愧驱,老公的妹妹穿的比我還像新娘。我一直安慰自己椭盏,他們只是感情好组砚,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,999評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著掏颊,像睡著了一般糟红。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上乌叶,一...
    開(kāi)封第一講書(shū)人閱讀 51,775評(píng)論 1 307
  • 那天盆偿,我揣著相機(jī)與錄音,去河邊找鬼准浴。 笑死事扭,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的乐横。 我是一名探鬼主播求橄,決...
    沈念sama閱讀 40,474評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼葡公!你這毒婦竟也來(lái)了罐农?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,359評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤催什,失蹤者是張志新(化名)和其女友劉穎啃匿,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體蛆楞,經(jīng)...
    沈念sama閱讀 45,854評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,007評(píng)論 3 338
  • 正文 我和宋清朗相戀三年夹厌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了豹爹。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,146評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡矛纹,死狀恐怖臂聋,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤孩等,帶...
    沈念sama閱讀 35,826評(píng)論 5 346
  • 正文 年R本政府宣布艾君,位于F島的核電站,受9級(jí)特大地震影響肄方,放射性物質(zhì)發(fā)生泄漏冰垄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,484評(píng)論 3 331
  • 文/蒙蒙 一权她、第九天 我趴在偏房一處隱蔽的房頂上張望虹茶。 院中可真熱鬧,春花似錦隅要、人聲如沸蝴罪。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,029評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)要门。三九已至,卻和暖如春廓啊,著一層夾襖步出監(jiān)牢的瞬間欢搜,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,153評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工崖瞭, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留狂巢,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,420評(píng)論 3 373
  • 正文 我出身青樓书聚,卻偏偏與公主長(zhǎng)得像唧领,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子雌续,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,107評(píng)論 2 356

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

  • 前言目前CPU的運(yùn)算速度已經(jīng)達(dá)到了百億次每秒斩个,所以為了提高生產(chǎn)率和高效地完成任務(wù),基本上都采用多線程和并發(fā)的運(yùn)作方...
    Lemonrel閱讀 556評(píng)論 0 0
  • 參考鏈接:CS-Notes/notes/Java 并發(fā).md [https://github.com/CyC201...
    senzx閱讀 222評(píng)論 0 0
  • 1.并行和并發(fā)有什么區(qū)別 并行:同一時(shí)刻執(zhí)行多條指令驯杜,物理上的同時(shí)發(fā)生受啥。 并發(fā):同一時(shí)刻只能執(zhí)行一條指令,但是多條...
    下一杯清淡若水_78db閱讀 1,088評(píng)論 0 0
  • 1. 什么是線程和進(jìn)程? 1.1 進(jìn)程 進(jìn)程是程序的一次執(zhí)行過(guò)程鸽心,是系統(tǒng)運(yùn)行程序的基本單位滚局,因此進(jìn)程是動(dòng)態(tài)的。系統(tǒng)...
    ficca閱讀 128評(píng)論 0 0
  • 個(gè)人博客http://www.milovetingting.cn Java多線程(四) 前言 本文為學(xué)習(xí)Java相...
    milovetingting閱讀 415評(píng)論 0 1