Java 并發(fā)編程和高并發(fā)解決方案

基本概念

并發(fā):同時(shí)擁有兩個(gè)或多個(gè)線程献汗,如果程序在單核處理器上運(yùn)行暇赤,多個(gè)線程將交替的換入或者換出內(nèi)存耙蔑,這些線程是同時(shí)“存在”的,每個(gè)線程都處于執(zhí)行過程中的某個(gè)狀態(tài)疟赊,如果運(yùn)行在多核處理器上郊供,此時(shí),程序中的每個(gè)線程都將分配到一個(gè)處理器核上近哟,因此可以同時(shí)運(yùn)行驮审。(多個(gè)線程操作相同的資源,保證線程安全吉执,合理使用資源)

高并發(fā):高并發(fā)(High Concurrency)是互聯(lián)網(wǎng)分布式系統(tǒng)架構(gòu)設(shè)計(jì)中必須考慮的因素之一疯淫,它通常是指,通過設(shè)計(jì)保證系統(tǒng)能夠同時(shí)并行處理很多請(qǐng)求戳玫。(服務(wù)能同時(shí)處理很多請(qǐng)求熙掺,提高程序性能)

Java內(nèi)存模型(Java Memory Model,JMM)

image.png
image.png

Java內(nèi)存模型-同步八種操作

lock(鎖定):作用與主內(nèi)存的變量咕宿,把一個(gè)變量表示為一條線程獨(dú)占狀態(tài)币绩。
unlock(解鎖):作用與主內(nèi)存的變量,把一個(gè)鎖定狀態(tài)的變量釋放出來府阀,釋放后的變量才可以被其他線程鎖定缆镣。
read(讀取):作用與主內(nèi)存的變量试浙,把一個(gè)變量值從主內(nèi)存?zhèn)鬏數(shù)骄€程的工作內(nèi)存中董瞻,以便隨后的load動(dòng)作使用。
load(載入):作用于工作內(nèi)存的變量川队,它把read操作從主內(nèi)存中得到的變量值放入工作內(nèi)存的變量副本中力细。
use(使用):作用于工作內(nèi)存的變量,把工作內(nèi)存中的一個(gè)變量值傳遞給執(zhí)行引擎固额。
assign(賦值):作用于工作內(nèi)存的變量,它把一個(gè)從執(zhí)行引擎接收到的值賦給工作內(nèi)存的變量煞聪。
store(存儲(chǔ)):作用于工作內(nèi)存的變量斗躏,把工作內(nèi)存中的一個(gè)變量的值傳送到主內(nèi)存中,以便隨后的write操作昔脯。
write(寫入):作用與主內(nèi)存的變量啄糙,它把store操作從工作內(nèi)存中一個(gè)變量的值傳送到主內(nèi)存的變量中。

image.png

線程安全性

當(dāng)多個(gè)線程訪問某個(gè)類時(shí)云稚,不管運(yùn)行時(shí)環(huán)境采用何種調(diào)度方式或者這些進(jìn)程將如何交替執(zhí)行隧饼,并且在主調(diào)代碼中不需要任何額外的同步或協(xié)同,這個(gè)類都能表現(xiàn)出正確的行為静陈,那么就成這個(gè)類是線程安全的绊茧。
原子性:提供了互斥訪問,同一時(shí)刻只能有一個(gè)線程來對(duì)它進(jìn)行操作
可見性:一個(gè)線程對(duì)于主內(nèi)存的修改可以及時(shí)的被其他線程觀察到
有序性:一個(gè)線程觀察其他線程中的指令執(zhí)行順序嫁佳,由于指令重排序的存在恬试,該觀察結(jié)果一般雜亂無序。

原子性對(duì)比

synchronized:不可中斷鎖七兜,適合競(jìng)爭(zhēng)不激烈,可讀性好。
Lock:可中斷鎖懂衩,多樣化同步,競(jìng)爭(zhēng)激烈時(shí)能維持常態(tài)金踪。
Atomic:競(jìng)爭(zhēng)激烈時(shí)能維持常態(tài)浊洞,比Lock性能好;只能同步一個(gè)值胡岔。

可見性

導(dǎo)致共享變量在線程間不可見的原因:

  1. 線程交叉執(zhí)行
  2. 重排序結(jié)合線程交叉執(zhí)行
  3. 共享變量更新后的值沒有在工作內(nèi)存與主存間及時(shí)更新

JMM關(guān)于synchronized的兩條規(guī)定:

  1. 線程解鎖前沛申,必須把共享變量的最新值刷新到主內(nèi)存。
  2. 線程加鎖時(shí)姐军,將清空工作內(nèi)存中共享變量的值铁材,從而使用共享變量時(shí)需要從主內(nèi)存中重新讀取最新的值(加鎖與解鎖是同一把鎖)

可見性-volatile
通過加入內(nèi)存屏障和禁止重排序優(yōu)化來實(shí)現(xiàn)

  1. 對(duì)volatile變量寫操作時(shí),會(huì)在寫操作后加入一條store屏障指令奕锌,將本地內(nèi)存中的共享變量值刷新到主內(nèi)存著觉。
  2. 對(duì)volatile變量讀操作時(shí),會(huì)在讀操作前加入一條load屏障指令惊暴,從主內(nèi)存中讀取共享變量饼丘。
可見性-volatile寫
可見性-volatile讀
// volatile 適用場(chǎng)景
        volatile boolean inited = false;

        // 線程1:
        context = loadContext();
        inited = true;

        // 線程2:
        while (!inited){
            sleep();
        }
        doSomethingWithConfig(context);

有序性

Java內(nèi)存模型中,允許編譯器和處理器對(duì)指令進(jìn)行重排序辽话,但是重排序過程不會(huì)影響到單線程程序的執(zhí)行肄鸽,卻會(huì)影響到多線程并發(fā)執(zhí)行的正確性。

有序性-happens-before原則

  1. 程序次序規(guī)則:一個(gè)線程內(nèi)油啤,按照代碼順序典徘,書寫在前面的操作先行發(fā)生于書寫在后面的操作(指令重排序不影響單線程內(nèi)的結(jié)果)。
  2. 鎖定規(guī)則:一個(gè)unlock操作先行發(fā)生于后面對(duì)同一個(gè)鎖的lock操作益咬。
  3. volatile變量規(guī)則:對(duì)一個(gè)變量的寫操作先行發(fā)生于后面對(duì)這個(gè)變量的讀操作逮诲。
  4. 傳遞規(guī)則:如果操作A先行發(fā)生于操作B,而操作B又先行發(fā)生于操作C幽告,則可以得出操作A先行發(fā)生于操作C梅鹦。

  1. 線程啟動(dòng)規(guī)則:Thread對(duì)象的start()方法先行發(fā)生于此線程的每一個(gè)動(dòng)作
  2. 線程中斷規(guī)則:對(duì)線程interrupt()方法的調(diào)用先行發(fā)生于被中斷線程的代碼檢測(cè)到中斷事件的發(fā)生
  3. 線程終結(jié)規(guī)則:線程中所有的操作都先行發(fā)生于線程的終止檢測(cè),我們可以通過Thread.join()方法結(jié)束冗锁、Thread.isAlive()的返回值手段檢測(cè)到線程已經(jīng)終止執(zhí)行
  4. 對(duì)象終結(jié)規(guī)則:一個(gè)對(duì)象的初始化完成先行發(fā)生于他的finalize()方法的開始

發(fā)布對(duì)象

使一個(gè)對(duì)象能夠被當(dāng)前范圍之外的代碼所使用齐唆。
在我們的日常開發(fā)中,我們經(jīng)常要發(fā)布一些對(duì)象冻河,比如通過類的非私有方法返回對(duì)象的引用箍邮,或者通過公有靜態(tài)變量發(fā)布對(duì)象茉帅。

對(duì)象逸出

一種錯(cuò)誤的發(fā)布。當(dāng)一個(gè)對(duì)象還沒有構(gòu)造完成時(shí)媒殉,就使它被其他線程所見担敌。

不可變對(duì)象

有一種對(duì)象只要它發(fā)布了就是安全的,它就是不可變對(duì)象廷蓉。一個(gè)不可變對(duì)象需要滿足的條件:

對(duì)象創(chuàng)建以后其狀態(tài)不能修改
對(duì)象所有域都是final類型
對(duì)象是正確創(chuàng)建的(在對(duì)象創(chuàng)建期間全封,this引用沒有逸出)

final關(guān)鍵字

final關(guān)鍵字可以修飾類、修飾方法桃犬、修飾變量

修飾類:類不能被集成刹悴。
基礎(chǔ)類型的包裝類都是final類型的類。final類中的成員變量可以根據(jù)需要設(shè)置為final攒暇,但是要注意的是土匀,final類中的所有成員方法都會(huì)被隱式的指定為final方法
修飾方法:
(1)把方法鎖定,以防任何繼承類修改它的含義
(2)效率:在早期的java實(shí)現(xiàn)版本中形用,會(huì)將final方法轉(zhuǎn)為內(nèi)嵌調(diào)用就轧。但是如果方法過于龐大,可能看不見效果田度。一個(gè)private方法會(huì)被隱式的指定為final方法
修飾變量:
基本數(shù)據(jù)類型變量妒御,在初始化之后,它的值就不能被修改了镇饺。如果是引用類型變量乎莉,在它初始化之后便不能再指向另外的對(duì)象。

死鎖-必要條件

  • 互斥條件:進(jìn)程對(duì)鎖分配的資源進(jìn)行排他性使用
  • 請(qǐng)求和保持條件:線程已經(jīng)保持了一個(gè)資源奸笤,但是又提出了其他請(qǐng)求惋啃,而該資源已被其他線程占用
  • 不剝奪條件:在使用時(shí)不能被剝奪,只能自己用完釋放
  • 環(huán)路等待條件:資源調(diào)用是一個(gè)環(huán)形的鏈

多線程并發(fā)最佳實(shí)踐

  • 使用本地變量
  • 使用不可變類
  • 最小化鎖的作用域范圍:S=1/(1-a+a/n)
  • 使用線程池的Executor监右,而不是直接new Thread執(zhí)行
  • 寧可使用同步也不要使用線程的wait和notify
  • 使用BlockingQueue實(shí)現(xiàn)生產(chǎn)-消費(fèi)模式
  • 使用并發(fā)集合而不是加了鎖的同步集合
  • 使用Semaphore創(chuàng)建有界的訪問
  • 寧可使用同步代碼塊也不使用同步的方法
  • 避免使用靜態(tài)變量

限流算法

計(jì)數(shù)器法
滑動(dòng)窗口
漏桶
令牌桶

高可用的一些手段

  • 任務(wù)調(diào)度系統(tǒng)分布式:elastic-job+zookeeper
  • 主備切換:apache curator+zookeeper分布式鎖實(shí)現(xiàn)
  • 監(jiān)控報(bào)警機(jī)制
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末边灭,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子秸侣,更是在濱河造成了極大的恐慌存筏,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件味榛,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡予跌,警方通過查閱死者的電腦和手機(jī)搏色,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來券册,“玉大人频轿,你說我怎么就攤上這事垂涯。” “怎么了航邢?”我有些...
    開封第一講書人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵耕赘,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我膳殷,道長(zhǎng)操骡,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任赚窃,我火速辦了婚禮册招,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘勒极。我一直安慰自己是掰,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開白布辱匿。 她就那樣靜靜地躺著键痛,像睡著了一般。 火紅的嫁衣襯著肌膚如雪匾七。 梳的紋絲不亂的頭發(fā)上絮短,一...
    開封第一講書人閱讀 51,688評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音乐尊,去河邊找鬼戚丸。 笑死,一個(gè)胖子當(dāng)著我的面吹牛扔嵌,可吹牛的內(nèi)容都是我干的限府。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼痢缎,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼胁勺!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起独旷,我...
    開封第一講書人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤署穗,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后嵌洼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體案疲,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年麻养,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了褐啡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡鳖昌,死狀恐怖备畦,靈堂內(nèi)的尸體忽然破棺而出低飒,到底是詐尸還是另有隱情,我是刑警寧澤懂盐,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布褥赊,位于F島的核電站,受9級(jí)特大地震影響莉恼,放射性物質(zhì)發(fā)生泄漏拌喉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一类垫、第九天 我趴在偏房一處隱蔽的房頂上張望司光。 院中可真熱鬧,春花似錦悉患、人聲如沸残家。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽坞淮。三九已至,卻和暖如春陪捷,著一層夾襖步出監(jiān)牢的瞬間回窘,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來泰國(guó)打工市袖, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留啡直,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓苍碟,卻偏偏與公主長(zhǎng)得像酒觅,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子微峰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

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

  • 每個(gè)人都在渴望一段可遇而不可求的感情舷丹。 誠(chéng)如張愛玲所說:“于千萬人之中遇見你所遇見的人,于千萬年之中蜓肆,在時(shí)間的無涯...
    瀟湘子閱讀 728評(píng)論 0 6
  • 最近洋洋的自我意識(shí)提升了颜凯,他現(xiàn)在希望自己可以為自己做主任何事情,如果我提出不同的意見仗扬,他就會(huì)生氣症概,會(huì)告訴我他很生氣...
    王翠英閱讀 68評(píng)論 0 0
  • 在開始之前,我們?cè)囅脒@樣一個(gè)場(chǎng)景:一個(gè)對(duì)你來說非常重要的客戶需要和你進(jìn)行商務(wù)會(huì)談早芭,第一次會(huì)談時(shí)穴豫,客戶遲到了;第二次...
    小墨魚天天很開心閱讀 418評(píng)論 0 1
  • 最近《我不是藥神》火的一塌糊涂,各種刷屏各種點(diǎn)贊帜乞,網(wǎng)絡(luò)評(píng)分也相當(dāng)高司抱。就這樣一部沒有豪華演員陣容,沒有先進(jìn)特效的普劇...
    似悅閱讀 269評(píng)論 0 1
  • 今天是我每天一篇文章的第146篇黎烈。 今天岔開一下話題习柠,下午連續(xù)了解了兩個(gè)小伙伴團(tuán)隊(duì)的內(nèi)部項(xiàng)目的進(jìn)展情況。一...
    很溫暖閱讀 2,757評(píng)論 0 0