多線程

一.進(jìn)程和線程區(qū)別

Java線程的5種狀態(tài)及切換(透徹講解) - CSDN博客

二.輕量級鎖與偏向鎖

三.CAS

Java中CAS詳解 - CSDN博客

在JDK 5之前Java語言是靠synchronized關(guān)鍵字保證同步的衬衬,這會(huì)導(dǎo)致有鎖

鎖機(jī)制存在以下問題:

(1)在多線程競爭下,加鎖毙替、釋放鎖會(huì)導(dǎo)致比較多的上下文切換和調(diào)度延時(shí),引起性能問題价捧。

(2)一個(gè)線程持有鎖會(huì)導(dǎo)致其它所有需要此鎖的線程掛起次坡。

(3)如果一個(gè)優(yōu)先級高的線程等待一個(gè)優(yōu)先級低的線程釋放鎖會(huì)導(dǎo)致優(yōu)先級倒置,引起性能風(fēng)險(xiǎn)阱飘。

volatile是不錯(cuò)的機(jī)制怔锌,但是volatile不能保證原子性炕置。因此對于同步最終還是要回到鎖機(jī)制上來诚些。

獨(dú)占鎖是一種悲觀鎖,synchronized就是一種獨(dú)占鎖氢哮,會(huì)導(dǎo)致其它所有需要鎖的線程掛起袋毙,等待持有鎖的線程釋放鎖。而另一個(gè)更加有效的鎖就是樂觀鎖冗尤。所謂樂觀鎖就是听盖,每次不加鎖而是假設(shè)沒有沖突而去完成某項(xiàng)操作,如果因?yàn)闆_突失敗就重試裂七,直到成功為止皆看。樂觀鎖用到的機(jī)制就是CAS,Compare and Swap背零。

二悬蔽、CAS的目的

利用CPU的CAS指令,同時(shí)借助JNI來完成Java的非阻塞算法捉兴。其它原子操作都是利用類似的特性完成的。而整個(gè)J.U.C都是建立在CAS之上的录语,因此對于synchronized阻塞算法倍啥,J.U.C在性能上有了很大的提升。

三澎埠、CAS存在的問題

CAS雖然很高效的解決原子操作虽缕,但是CAS仍然存在三大問題。ABA問題蒲稳,循環(huán)時(shí)間長開銷大和只能保證一個(gè)共享變量的原子操作

1.ABA問題氮趋。因?yàn)镃AS需要在操作值的時(shí)候檢查下值有沒有發(fā)生變化,如果沒有發(fā)生變化則更新江耀,但是如果一個(gè)值原來是A剩胁,變成了B,又變成了A祥国,那么使用CAS進(jìn)行檢查時(shí)會(huì)發(fā)現(xiàn)它的值沒有發(fā)生變化昵观,但是實(shí)際上卻變化了。ABA問題的解決思路就是使用版本號舌稀。在變量前面追加上版本號啊犬,每次變量更新的時(shí)候把版本號加一,那么A-B-A 就會(huì)變成1A-2B-3A壁查。

從Java1.5開始JDK的atomic包里提供了一個(gè)類AtomicStampedReference來解決ABA問題觉至。這個(gè)類的compareAndSet方法作用是首先檢查當(dāng)前引用是否等于預(yù)期引用,并且當(dāng)前標(biāo)志是否等于預(yù)期標(biāo)志睡腿,如果全部相等语御,則以原子方式將該引用和該標(biāo)志的值設(shè)置為給定的更新值峻贮。

關(guān)于ABA問題參考文檔:?http://blog.hesey.net/2011/09/resolve-aba-by-atomicstampedreference.html

2. 循環(huán)時(shí)間長開銷大。自旋CAS如果長時(shí)間不成功沃暗,會(huì)給CPU帶來非常大的執(zhí)行開銷月洛。如果JVM能支持處理器提供的pause指令那么效率會(huì)有一定的提升,pause指令有兩個(gè)作用孽锥,第一它可以延遲流水線執(zhí)行指令(de-pipeline),使CPU不會(huì)消耗過多的執(zhí)行資源嚼黔,延遲的時(shí)間取決于具體實(shí)現(xiàn)的版本,在一些處理器上延遲時(shí)間是零惜辑。第二它可以避免在退出循環(huán)的時(shí)候因內(nèi)存順序沖突(memory order violation)而引起CPU流水線被清空(CPU pipeline flush)唬涧,從而提高CPU的執(zhí)行效率。


3. 只能保證一個(gè)共享變量的原子操作盛撑。當(dāng)對一個(gè)共享變量執(zhí)行操作時(shí)碎节,我們可以使用循環(huán)CAS的方式來保證原子操作,但是對多個(gè)共享變量操作時(shí)抵卫,循環(huán)CAS就無法保證操作的原子性狮荔,這個(gè)時(shí)候就可以用鎖,或者有一個(gè)取巧的辦法介粘,就是把多個(gè)共享變量合并成一個(gè)共享變量來操作殖氏。比如有兩個(gè)共享變量i=2,j=a,合并一下ij=2a姻采,然后用CAS來操作ij雅采。從Java1.5開始JDK提供了AtomicReference類來保證引用對象之間的原子性,你可以把多個(gè)變量放在一個(gè)對象里來進(jìn)行CAS操作慨亲。

四婚瓜、concurrent包的實(shí)現(xiàn)

由于java的CAS同時(shí)具有 volatile 讀和volatile寫的內(nèi)存語義,因此Java線程之間的通信現(xiàn)在有了下面四種方式:

A線程寫volatile變量刑棵,隨后B線程讀這個(gè)volatile變量巴刻。

A線程寫volatile變量,隨后B線程用CAS更新這個(gè)volatile變量蛉签。

A線程用CAS更新一個(gè)volatile變量冈涧,隨后B線程用CAS更新這個(gè)volatile變量。

A線程用CAS更新一個(gè)volatile變量正蛙,隨后B線程讀這個(gè)volatile變量督弓。

Java的CAS會(huì)使用現(xiàn)代處理器上提供的高效機(jī)器級別原子指令,這些原子指令以原子方式對內(nèi)存執(zhí)行讀-改-寫操作乒验,這是在多處理器中實(shí)現(xiàn)同步的關(guān)鍵(從本質(zhì)上來說愚隧,能夠支持原子性讀-改-寫指令的計(jì)算機(jī)器,是順序計(jì)算圖靈機(jī)的異步等價(jià)機(jī)器,因此任何現(xiàn)代的多處理器都會(huì)去支持某種能對內(nèi)存執(zhí)行原子性讀-改-寫操作的原子指令)狂塘。同時(shí)录煤,volatile變量的讀/寫和CAS可以實(shí)現(xiàn)線程之間的通信。把這些特性整合在一起荞胡,就形成了整個(gè)concurrent包得以實(shí)現(xiàn)的基石妈踊。如果我們仔細(xì)分析concurrent包的源代碼實(shí)現(xiàn),會(huì)發(fā)現(xiàn)一個(gè)通用化的實(shí)現(xiàn)模式:

首先泪漂,聲明共享變量為volatile廊营;

然后,使用CAS的原子條件更新來實(shí)現(xiàn)線程之間的同步萝勤;

同時(shí)露筒,配合以volatile的讀/寫和CAS所具有的volatile讀和寫的內(nèi)存語義來實(shí)現(xiàn)線程之間的通信。

AQS敌卓,非阻塞數(shù)據(jù)結(jié)構(gòu)和原子變量類(java.util.concurrent.atomic包中的類)慎式,這些concurrent包中的基礎(chǔ)類都是使用這種模式來實(shí)現(xiàn)的,而concurrent包中的高層類又是依賴于這些基礎(chǔ)類來實(shí)現(xiàn)的趟径。從整體來看瘪吏,concurrent包的實(shí)現(xiàn)示意圖如下:


四.CAS自旋

五.自旋

六.java并發(fā)編程中CountDownLatch和CyclicBarrier的使用?

在多線程程序設(shè)計(jì)中,經(jīng)常會(huì)遇到一個(gè)線程等待一個(gè)或多個(gè)線程的場景蜗巧,遇到這樣的場景應(yīng)該如何解決肪虎?

如果是一個(gè)線程等待一個(gè)線程,則可以通過await()和notify()來實(shí)現(xiàn)惧蛹;

如果是一個(gè)線程等待多個(gè)線程,則就可以使用CountDownLatch和CyclicBarrier來實(shí)現(xiàn)比較好的控制刑枝。

下面來詳細(xì)描述下CountDownLatch的應(yīng)用場景:

例如:百米賽跑:8名運(yùn)動(dòng)員同時(shí)起跑香嗓,由于速度的快慢,肯定有會(huì)出現(xiàn)先到終點(diǎn)和晚到終點(diǎn)的情況装畅,而終點(diǎn)有個(gè)統(tǒng)計(jì)成績的儀器靠娱,當(dāng)所有選手到達(dá)終點(diǎn)時(shí),它會(huì)統(tǒng)計(jì)所有人的成績并進(jìn)行排序掠兄,然后把結(jié)果發(fā)送到匯報(bào)成績的系統(tǒng)像云。

其實(shí)這就是一個(gè)CountDownLatch的應(yīng)用場景:一個(gè)線程或多個(gè)線程等待其他線程運(yùn)行達(dá)到某一目標(biāo)后進(jìn)行自己的下一步工作,而被等待的“其他線程”達(dá)到這個(gè)目標(biāo)后繼續(xù)自己下面的任務(wù)蚂夕。

這個(gè)場景中:

1. 被等待的“其他線程”------>8名運(yùn)動(dòng)員

2. 等待“其他線程”的這個(gè)線程------>終點(diǎn)統(tǒng)計(jì)成績的儀器

那么迅诬,如何來通過CountDownLatch來實(shí)現(xiàn)上述場景的線程控制和調(diào)度呢?

jdk中CountDownLatch類有一個(gè)常用的構(gòu)造方法:CountDownLatch(int count)婿牍;

????????????????????????兩個(gè)常用的方法:await()和countdown()?

其 中count是一個(gè)計(jì)數(shù)器中的初始化數(shù)字侈贷,比如初始化的數(shù)字是2,當(dāng)一個(gè)線程里調(diào)用了countdown()等脂,則這個(gè)計(jì)數(shù)器就減一俏蛮,當(dāng)線程調(diào)用了 await()撑蚌,則這個(gè)線程就等待這個(gè)計(jì)數(shù)器變?yōu)?,當(dāng)這個(gè)計(jì)數(shù)器變?yōu)?時(shí)搏屑,這個(gè)線程繼續(xù)自己下面的工作争涌。下面是上述CountDownLatch場景的 實(shí)現(xiàn):

Work類(運(yùn)動(dòng)員):

import?Java.util.concurrent.CountDownLatch;

public class Work implements Runnable {

?private int id;

?private CountDownLatch beginSignal;

?private CountDownLatch endSignal;


?public Work(int id, CountDownLatch begin, CountDownLatch end) {

??this.id = id;

??this.beginSignal = begin;

??this.endSignal = end;

?}

?@Override

?public void run() {

??try {

???beginSignal.await();

???System.out.println("起跑...");

???System.out.println("work" + id + "到達(dá)終點(diǎn)");

???endSignal.countDown();

???System.out.println("work" + id + "繼續(xù)干其他事情");

??} catch (InterruptedException e) {

???// TODO Auto-generated catch block

???e.printStackTrace();

??}

?}

}

Main類(終點(diǎn)統(tǒng)計(jì)儀器):

import java.util.concurrent.CountDownLatch;

public class Main {


?public static void main(String[] args) {

??CountDownLatch begSignal = new CountDownLatch(1);

??CountDownLatch endSignal = new CountDownLatch(8);


??for (int i = 0; i < 8; i++) {

???new Thread(new Work(i, begSignal, endSignal)).start();

??}


??try {

???begSignal.countDown();? //統(tǒng)一起跑

???endSignal.await();????? //等待運(yùn)動(dòng)員到達(dá)終點(diǎn)

???System.out.println("結(jié)果發(fā)送到匯報(bào)成績的系統(tǒng)");

??} catch (InterruptedException e) {

???e.printStackTrace();

??}

?}

}

下面詳細(xì)描述下CyclicBarrier的應(yīng)用場景:

有四個(gè)游戲玩家玩游戲,游戲有三個(gè)關(guān)卡辣恋,每個(gè)關(guān)卡必須要所有玩家都到達(dá)后才能允許通關(guān)亮垫。

其 實(shí)這個(gè)場景里的玩家中如果有玩家A先到了關(guān)卡1,他必須等待其他所有玩家都到達(dá)關(guān)卡1時(shí)才能通過抑党,也就是說線程之間需要互相等待包警,這和 CountDownLatch的應(yīng)用場景有區(qū)別,CountDownLatch里的線程是到了運(yùn)行的目標(biāo)后繼續(xù)干自己的其他事情底靠,而這里的線程需要等待其 他線程后才能繼續(xù)完成下面的工作害晦。

jdk中CyclicBarrier類有兩個(gè)常用的構(gòu)造方法:

1. CyclicBarrier(int parties)

這里的parties也是一個(gè)計(jì)數(shù)器,例如暑中,初始化時(shí)parties里的計(jì)數(shù)是3壹瘟,于是擁有該CyclicBarrier對象的線程當(dāng)parties的計(jì)數(shù)為3時(shí)就喚醒,注:這里parties里的計(jì)數(shù)在運(yùn)行時(shí)當(dāng)調(diào)用CyclicBarrier:await()時(shí),計(jì)數(shù)就加1鳄逾,一直加到初始的值

2. CyclicBarrier(int parties, Runnable barrierAction)

這里的parties與上一個(gè)構(gòu)造方法的解釋是一樣的稻轨,這里需要解釋的是第二個(gè)入?yún)ⅲ≧unnable barrierAction),這個(gè)參數(shù)是一個(gè)實(shí)現(xiàn)Runnable接口的類的對象,也就是說當(dāng)parties加到初始值時(shí)就出發(fā)barrierAction的內(nèi)容雕凹。

下面來實(shí)現(xiàn)上述的應(yīng)用場景:

?Player類(玩家類)

[java]?view plain?copy

import?java.util.concurrent.BrokenBarrierException;??

import?java.util.concurrent.CyclicBarrier;??

public?class?Player?implements?Runnable?{??


?private?CyclicBarrier?cyclicBarrier;??

?private?int?id;??


?public?Player(int?id,?CyclicBarrier?cyclicBarrier)?{??

??this.cyclicBarrier?=?cyclicBarrier;??

??this.id?=?id;??

?}??

?@Override??

?public?void?run()?{??

??try?{??

???System.out.println("玩家"?+?id?+?"正在玩第一關(guān)...");??

???cyclicBarrier.await();??

???System.out.println("玩家"?+?id?+?"進(jìn)入第二關(guān)...");??

??}?catch?(InterruptedException?e)?{??

???e.printStackTrace();??

??}?catch?(BrokenBarrierException?e)?{??

???e.printStackTrace();??

??}??

?}??

}??

GameBarrier類(關(guān)卡類殴俱,這里控制玩家必須全部到達(dá)第一關(guān)結(jié)束的關(guān)口才能進(jìn)入第二關(guān))

import java.util.concurrent.CyclicBarrier;

public class GameBarrier {


?public static void main(String[] args) {

??CyclicBarrier cyclicBarrier = new CyclicBarrier(4, new Runnable() {


???@Override

???public void run() {

????System.out.println("所有玩家進(jìn)入第二關(guān)!");

???}

??});


??for (int i = 0; i < 4; i++) {

???new Thread(new Player(i, cyclicBarrier)).start();

??}

?}

}

七.線程池

Java并發(fā)編程:線程池的使用 - 海 子 - 博客園

八.ThreadLocal

Java并發(fā)編程:深入剖析ThreadLocal - 海 子 - 博客園

九.50到j(luò)ava多線程面試題

Java線程面試題 Top 50 (轉(zhuǎn)載) - 海 子 - 博客園

JAVA多線程和并發(fā)基礎(chǔ)面試問答(轉(zhuǎn)載) - 海 子 - 博客園

JAVA多線程和并發(fā)基礎(chǔ)面試問答(轉(zhuǎn)載) - 海 子 - 博客園

Java并發(fā)編程:Timer和TimerTask(轉(zhuǎn)載) - 海 子 - 博客園

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末枚抵,一起剝皮案震驚了整個(gè)濱河市线欲,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌汽摹,老刑警劉巖李丰,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異逼泣,居然都是意外死亡趴泌,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進(jìn)店門拉庶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來嗜憔,“玉大人,你說我怎么就攤上這事氏仗”陨福” “怎么了?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長帚稠。 經(jīng)常有香客問我谣旁,道長,這世上最難降的妖魔是什么滋早? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任榄审,我火速辦了婚禮,結(jié)果婚禮上杆麸,老公的妹妹穿的比我還像新娘搁进。我一直安慰自己,他們只是感情好昔头,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布饼问。 她就那樣靜靜地躺著,像睡著了一般揭斧。 火紅的嫁衣襯著肌膚如雪莱革。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天讹开,我揣著相機(jī)與錄音盅视,去河邊找鬼。 笑死旦万,一個(gè)胖子當(dāng)著我的面吹牛闹击,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播成艘,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼赏半,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了淆两?” 一聲冷哼從身側(cè)響起断箫,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎琼腔,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體踱葛,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡丹莲,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了尸诽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片甥材。...
    茶點(diǎn)故事閱讀 39,711評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖性含,靈堂內(nèi)的尸體忽然破棺而出洲赵,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布叠萍,位于F島的核電站芝发,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏苛谷。R本人自食惡果不足惜辅鲸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望腹殿。 院中可真熱鬧独悴,春花似錦、人聲如沸锣尉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽自沧。三九已至坟奥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間暂幼,已是汗流浹背筏勒。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留旺嬉,地道東北人管行。 一個(gè)月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像邪媳,于是被迫代替她去往敵國和親捐顷。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評論 2 353

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

  • Java-Review-Note——4.多線程 標(biāo)簽: JavaStudy PS:本來是分開三篇的雨效,后來想想還是整...
    coder_pig閱讀 1,648評論 2 17
  • 作者:月的倉頡文章源自:http://www.cnblogs.com/xrq730/p/5060921.html ...
    IT程序獅閱讀 1,583評論 2 73
  • [轉(zhuǎn)自網(wǎng)絡(luò)] 心理學(xué)解析:“三歲定八十”背后讓人震驚的真相迅涮。3歲定80,已經(jīng)有了科學(xué)依據(jù)徽龟。你的孩子前三歲是如何度過...
    鈺嬌榮閱讀 350評論 0 0
  • 睡個(gè)覺好累叮姑,昨晚夢到和渣男吵吵打打了一晚上。 如果婚姻不幸福据悔,請果斷選擇單身~ 怎么過不是一輩子传透,莫要委屈了自己~...
    呆丫閱讀 109評論 0 0
  • ?披星戴月地奔波 只為一扇窗 當(dāng)你迷失在路上 能夠看見那燈光 不知不覺把他鄉(xiāng) 當(dāng)作了故鄉(xiāng) 只是偶爾難過時(shí) 不經(jīng)意遙...
    琉璃掛閱讀 458評論 7 3