并發(fā)編程-看完這篇棋蚌,所有Java并發(fā)編程的問題你都能應(yīng)對(duì)自如

1嫁佳、synchronized修飾普通方法和靜態(tài)方法的區(qū)別?什么是可見性谷暮?

對(duì)象鎖是用于對(duì)象實(shí)例方法蒿往,或者一個(gè)對(duì)象實(shí)例上的, 類鎖 是用于類的靜態(tài)方法或者一個(gè)類的class對(duì)象上的湿弦。我們知道瓤漏,類的對(duì)象實(shí)例可以有很多個(gè),但是每個(gè)類只有一個(gè)class對(duì)象颊埃,所以不同對(duì)象實(shí)例的對(duì)象鎖是互不干擾的蔬充,但是每個(gè)類只有一個(gè)類鎖。

但是有一點(diǎn)必須注意的是班利,其實(shí)類鎖只是一個(gè)概念上的東西饥漫,并不是真實(shí)存在的,類鎖其實(shí)鎖的是每個(gè)類的對(duì)應(yīng)的class對(duì)象罗标。類鎖和對(duì)象鎖之間也是互不干擾的庸队。

對(duì)象鎖:

/**
* 對(duì)象鎖 synchronized修飾普通方法 鎖的是當(dāng)前類實(shí)例對(duì)象
*/
public synchronized void syncMethod1() {
    //do working...
}
復(fù)制代碼
private final Object o = new Object();

/**
* 對(duì)象鎖 鎖的是Object對(duì)象實(shí)例
*/
public void syncMethod2() {
    synchronized (o) {
        //do working...
    }
}
復(fù)制代碼

類鎖:

/**
* 類鎖 synchronized修飾靜態(tài)方法 鎖的是當(dāng)前類唯一的.class對(duì)象,也就是SynchronizedType.class馒稍,等同于下面的syncMethod3()
*/
public static synchronized void syncMethod3() {
    //do working...
}
復(fù)制代碼
/**
* 類鎖 鎖的是當(dāng)前類唯一的.class對(duì)象皿哨。
*/
public void syncMethod4() {
    synchronized (SynchronizedType.class) {
        //do working...
    }
}
復(fù)制代碼

可見性是指當(dāng)多個(gè)線程訪問同一個(gè)變量時(shí)浅侨,一個(gè)線程修改了這個(gè)變量的值纽谒,其他線程能夠立即看得到修改的值。

由于線程對(duì)變量的所有操作都必須在工作內(nèi)存中進(jìn)行如输,而不能直接讀寫主內(nèi)存中的變量鼓黔,那么對(duì)于共享變量V,它們首先是在自己的工作內(nèi)存不见,之后再同步到主內(nèi)存澳化。可是并不會(huì)及時(shí)的刷到主存中稳吮,而是會(huì)有一定時(shí)間差缎谷。很明顯,這個(gè)時(shí)候線程A對(duì)變量V的操作對(duì)于線程B而言就不具備可見性了 灶似。

要解決共享對(duì)象可見性這個(gè)問題列林,我們可以使用 volatile 關(guān)鍵字或者是加鎖瑞你。

2、鎖分哪幾類希痴?

image.png

3者甲、CAS無鎖編程的原理。

使用當(dāng)前的處理器基本都支持CAS()的指令,只不過每個(gè)廠家所實(shí)現(xiàn)的算法并不一樣,每一個(gè)CAS操作過程都包含三個(gè)運(yùn)算符:一個(gè)內(nèi)存地址V捂蕴,一個(gè)期望的值A(chǔ)和一個(gè)新值B悔捶,操作的時(shí)候如果這個(gè)地址上存放的值等于這個(gè)期望的值A(chǔ),則將地址上的值賦為新值B勺爱,否則不做任何操作。

CAS的基本思路就是,如果這個(gè)地址上的值和期望的值相等扫倡,則給其賦予新值,否則不做任何事兒竟纳,但是要返回原值是多少撵溃。循環(huán)CAS就是在一個(gè)循環(huán)里不斷的做CAS操作,直到成功為止锥累。

還可以說說CAS的三大問題缘挑。

4、ReentrantLock的實(shí)現(xiàn)原理桶略。

線程可以重復(fù)進(jìn)入任何一個(gè)它已經(jīng)擁有的鎖所同步著的代碼塊语淘, synchronized 、 ReentrantLock 都是可重入的鎖际歼。在實(shí)現(xiàn)上惶翻,就是線程每次獲取鎖時(shí)判定如果獲得鎖的線程是它自己時(shí),簡單將計(jì)數(shù)器累積即可鹅心,每 釋放一次鎖吕粗,進(jìn)行計(jì)數(shù)器累減,直到計(jì)算器歸零旭愧,表示線程已經(jīng)徹底釋放鎖颅筋。

底層則是利用了JUC中的AQS來實(shí)現(xiàn)的。

5输枯、AQS原理议泵。

是用來構(gòu)建鎖或者其他同步組件的基礎(chǔ)框架,比如 ReentrantLock 桃熄、 ReentrantReadWriteLock 和 CountDownLatch 就是基于AQS實(shí)現(xiàn)的先口。它使用了一個(gè)int成員變量表示同步狀態(tài),通過內(nèi)置的FIFO隊(duì)列來完成資源獲取線程的排隊(duì)工作。它是CLH隊(duì)列鎖的一種變體實(shí)現(xiàn)碉京。它可以實(shí)現(xiàn)2種同步方式:獨(dú)占式桩引,共享式。

AQS的主要使用方式是繼承收夸,子類通過繼承AQS并實(shí)現(xiàn)它的抽象方法來管理同步狀態(tài)坑匠,同步器的設(shè)計(jì)基于模板方法模式,所以如果要實(shí)現(xiàn)我們自己的同步工具類就需要覆蓋其中幾個(gè)可重寫的方法卧惜,如 tryAcquire 厘灼、 tryReleaseShared 等等。

這樣設(shè)計(jì)的目的是同步組件(比如鎖)是面向使用者的咽瓷,它定義了使用者與同步組件交互的接口(比如可以允許兩個(gè)線程并行訪問)设凹,隱藏了實(shí)現(xiàn)細(xì)節(jié);同步器面向的是鎖的實(shí)現(xiàn)者茅姜,它簡化了鎖的實(shí)現(xiàn)方式闪朱,屏蔽了同步狀態(tài)管理、線程的排隊(duì)钻洒、等待與喚醒等底層操作奋姿。這樣就很好地隔離了使用者和實(shí)現(xiàn)者所需關(guān)注的領(lǐng)域。

在內(nèi)部素标,AQS維護(hù)一個(gè)共享資源state称诗,通過內(nèi)置的FIFO來完成獲取資源線程的排隊(duì)工作。該隊(duì)列由一個(gè)一個(gè)的Node結(jié)點(diǎn)組成头遭,每個(gè)Node結(jié)點(diǎn)維護(hù)一個(gè)prev引用和next引用寓免,分別指向自己的前驅(qū)和后繼結(jié)點(diǎn),構(gòu)成一個(gè)雙端雙向鏈表计维。

6袜香、synchronized的原理以及與ReentrantLock的區(qū)別。

synchronized (this) 原理:涉及兩條指令: monitorenter 鲫惶, monitorexit 蜈首;再說同步方法,從同步方法反編譯的結(jié)果來看剑按,方法的同步并沒有通過指令 monitorenter 和 monitorexit 來實(shí)現(xiàn)疾就,相對(duì)于普通方法澜术,其常量池中多了 ACC_SYNCHRONIZED 標(biāo)示符艺蝴。

JVM就是根據(jù)該標(biāo)示符來實(shí)現(xiàn)方法的同步的:當(dāng)方法被調(diào)用時(shí),調(diào)用指令將會(huì)檢查方法的 ACC_SYNCHRONIZED 訪問標(biāo)志是否被設(shè)置鸟废,如果設(shè)置了猜敢,執(zhí)行線程將先獲取monitor,獲取成功之后才能執(zhí)行方法體,方法執(zhí)行完后再釋放monitor缩擂。在方法執(zhí)行期間鼠冕,其他任何線程都無法再獲得同一個(gè)monitor對(duì)象。

7胯盯、synchronized鎖了那些優(yōu)化懈费?

引入如自旋鎖、適應(yīng)性自旋鎖博脑、鎖消除憎乙、鎖粗化、偏向鎖叉趣、輕量級(jí)鎖泞边、逃逸分析等技術(shù)來減少鎖操作的開銷。

逃逸分析

如果證明一個(gè)對(duì)象不會(huì)逃逸方法外或者線程外疗杉,則可針對(duì)此變量進(jìn)行優(yōu)化:

同步消除 synchronization Elimination 阵谚,如果一個(gè)對(duì)象不會(huì)逃逸出線程,則對(duì)此變量的同步措施可消除烟具。

鎖消除和粗化

鎖消除:虛擬機(jī)的運(yùn)行時(shí)編譯器在運(yùn)行時(shí)如果檢測到一些要求同步的代碼上不可能發(fā)生共享數(shù)據(jù)競爭梢什,則會(huì)去掉這些鎖。

鎖粗化:將臨近的代碼塊用同一個(gè)鎖合并起來朝聋。消除無意義的鎖獲取和釋放绳矩,可以提高程序運(yùn)行性能。

8玖翅、synchronized static與非static鎖的區(qū)別和范圍翼馆。

對(duì)象鎖是用于對(duì)象實(shí)例方法,或者一個(gè)對(duì)象實(shí)例上的金度,類鎖是用于類的靜態(tài)方法或者一個(gè)類的class對(duì)象上的应媚。我們知道,類的對(duì)象實(shí)例可以有很多個(gè)猜极,但是每個(gè)類只有一個(gè)class對(duì)象中姜,所以不同對(duì)象實(shí)例的對(duì)象鎖是互不干擾的,但是每個(gè)類只有一個(gè)類鎖跟伏。

但是有一點(diǎn)必須注意的是丢胚,其實(shí)類鎖只是一個(gè)概念上的東西,并不是真實(shí)存在的受扳,類鎖其實(shí)鎖的是每個(gè)類的對(duì)應(yīng)的class對(duì)象携龟。類鎖和對(duì)象鎖之間也是互不干擾的。

9勘高、volatile 能否保證線程安全峡蟋?在DCL上的作用是什么坟桅?

不能保證,在DCL的作用是: volatile 是會(huì)保證被修飾的變量的可見性和 有序性蕊蝗,保證了單例模式下仅乓,保證在創(chuàng)建對(duì)象的時(shí)候的執(zhí)行順序一定是

1.分配內(nèi)存空間

2.實(shí)例化對(duì)象instance

3.把instance引用指向已分配的內(nèi)存空間,此時(shí)instance有了內(nèi)存地址,不再為null了的步驟, 從而保證了instance要么為null 要么是已經(jīng)完全初始化好的對(duì)象。

10蓬戚、volatile和synchronize有什么區(qū)別夸楣?

volatile 是最輕量的同步機(jī)制。

volatile 保證了不同線程對(duì)這個(gè)變量進(jìn)行操作時(shí)的可見性子漩,即一個(gè)線程修改了某個(gè)變量的值裕偿,這新值對(duì)其他線程來說是立即可見的。但是 volatile 不能保證操作的原子性痛单,因此多線程下的寫復(fù)合操作會(huì)導(dǎo)致線程安全問題嘿棘。

關(guān)鍵字 synchronized 可以修飾方法或者以同步塊的形式來進(jìn)行使用,它主要確保多個(gè)線程在同一個(gè)時(shí)刻旭绒,只能有一個(gè)線程處于方法或者同步塊中鸟妙,它保證了線程對(duì)變量訪問的可見性和排他性,又稱為內(nèi)置鎖機(jī)制挥吵。

11重父、什么是守護(hù)線程?你是如何退出一個(gè)線程的忽匈?

Daemon(守護(hù))線程是一種支持型線程房午,因?yàn)樗饕挥米鞒绦蛑泻笈_(tái)調(diào)度以及支持性工作。這意味著丹允,當(dāng)一個(gè)Java虛擬機(jī)中不存在非Daemon線程的時(shí)候郭厌,Java虛擬機(jī)將會(huì)退出〉癖危可以通過調(diào)用 Thread.setDaemon(true) 將線程設(shè)置為Daemon線程折柠。我們一般用不上,比如垃圾回收線程就是Daemon線程批狐。

線程的中止:

要么是 run() 執(zhí)行完成了扇售,要么是拋出了一個(gè)未處理的異常導(dǎo)致線程提前結(jié)束。

暫停嚣艇、恢復(fù)和停止操作對(duì)應(yīng)在線程 Thread 的API就是 suspend() 承冰、 resume() 和 stop() 。但是這些API是過期的食零,也就是不建議使用的困乒。因?yàn)闀?huì)導(dǎo)致程序可能工作在不確定狀態(tài)下。

安全的中止則是其他線程通過調(diào)用某個(gè)線程A的 interrupt() 方法對(duì)其進(jìn)行中斷操作慌洪,被中斷的線程則是通過線程通過方法 isInterrupted() 來進(jìn)行判斷是否被中斷顶燕,也可以調(diào)用靜態(tài)方法 Thread.interrupted() 來進(jìn)行判斷當(dāng)前線程是否被中斷,不過 Thread.interrupted() 會(huì)同時(shí)將中斷標(biāo)識(shí)位改寫為false冈爹。

12涌攻、sleep 、wait频伤、yield 的區(qū)別恳谎,wait 的線程如何喚醒它?

yield() 方法:使當(dāng)前線程讓出CPU占有權(quán)憋肖,但讓出的時(shí)間是不可設(shè)定的因痛。也不會(huì)釋放鎖資源。所有執(zhí)行yield()的線程有可能在進(jìn)入到就緒狀態(tài)后會(huì)被操作系統(tǒng)再次選中馬上又被執(zhí)行岸更。

yield() 鸵膏、 sleep() 被調(diào)用后,都不會(huì)釋放當(dāng)前線程所持有的鎖怎炊。

調(diào)用 wait() 方法后谭企,會(huì)釋放當(dāng)前線程持有的鎖,而且當(dāng)前被喚醒后评肆,會(huì)重新去競爭鎖债查,鎖競爭到后才會(huì)執(zhí)行 wait() 方法后面的代碼。

wait通常被用于線程間交互瓜挽, sleep() 通常被用于暫停執(zhí)行盹廷, yield() 方法使當(dāng)前線程讓出CPU占有權(quán)。wait的線程使用 notify/notifyAll() 進(jìn)行喚醒久橙。

13俄占、sleep是可中斷的么?

sleep 本身就支持中斷淆衷,如果線程在 sleep 期間被中斷颠放,則會(huì)拋出一個(gè)中斷異常。

14吭敢、線程生命周期碰凶。

Java中線程的狀態(tài)分為6種:

  1. 初始(NEW):新創(chuàng)建了一個(gè)線程對(duì)象,但還沒有調(diào)用start()方法鹿驼。
  2. 運(yùn)行(RUNNABLE):Java線程中將就緒(ready)和運(yùn)行中(running)兩種狀態(tài)籠統(tǒng)的稱為“運(yùn)行”欲低。

線程對(duì)象創(chuàng)建后,其他線程(比如main線程)調(diào)用了該對(duì)象的start()方法畜晰。該狀態(tài)的線程位于可運(yùn)行線程池中砾莱,等待被線程調(diào)度選中,獲取CPU的使用權(quán)凄鼻,此時(shí)處于就緒狀態(tài)(ready)腊瑟。就緒狀態(tài)的線程在獲得CPU時(shí)間片后變?yōu)檫\(yùn)行中狀態(tài)(running)聚假。

3. 阻塞(BLOCKED):表示線程阻塞于鎖。

4. 等待(WAITING):進(jìn)入該狀態(tài)的線程需要等待其他線程做出一些特定動(dòng)作(通知或中斷)闰非。

5. 超時(shí)等待(TIMED_WAITING):該狀態(tài)不同于WAITING膘格,它可以在指定的時(shí)間后自行返回。

  1. 終止(TERMINATED):表示該線程已經(jīng)執(zhí)行完畢财松。
image.png

15瘪贱、ThreadLocal是什么?

ThreadLocal 是Java里一種特殊的變量辆毡。 ThreadLocal 為每個(gè)線程都提供了變量的副本菜秦,使得每個(gè)線程在某一時(shí)間訪問到的并非同一個(gè)對(duì)象,這樣就隔離了多個(gè)線程對(duì)數(shù)據(jù)的數(shù)據(jù)共享舶掖。

在內(nèi)部實(shí)現(xiàn)上球昨,每個(gè)線程內(nèi)部都有一個(gè) ThreadLocalMap ,用來保存每個(gè)線程所擁有的變量副本眨攘。

16褪尝、線程池基本原理。

在開發(fā)過程中期犬,合理地使用線程池能夠帶來3個(gè)好處河哑。

第一:降低資源消耗。

第二:提高響應(yīng)速度龟虎。

第三:提高線程的可管理性璃谨。

1)如果當(dāng)前運(yùn)行的線程少于 corePoolSize ,則創(chuàng)建新線程來執(zhí)行任務(wù)(注意鲤妥,執(zhí)行這一步驟需要獲取全局鎖)佳吞。

2)如果運(yùn)行的線程等于或多于 corePoolSize ,則將任務(wù)加入 BlockingQueue 棉安。

3)如果無法將任務(wù)加入 BlockingQueue (隊(duì)列已滿)底扳,則創(chuàng)建新的線程來處理任務(wù)。

4)如果創(chuàng)建新線程將使當(dāng)前運(yùn)行的線程超出 maximumPoolSize 贡耽,任務(wù)將被拒絕衷模,并調(diào)用 RejectedExecutionHandler.rejectedExecution() 方法。

17蒲赂、有三個(gè)線程T1阱冶,T2,T3滥嘴,怎么確保它們按順序執(zhí)行木蹬?

使用join()實(shí)現(xiàn)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末若皱,一起剝皮案震驚了整個(gè)濱河市镊叁,隨后出現(xiàn)的幾起案子尘颓,更是在濱河造成了極大的恐慌,老刑警劉巖晦譬,帶你破解...
    沈念sama閱讀 211,348評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疤苹,死亡現(xiàn)場離奇詭異,居然都是意外死亡蛔添,警方通過查閱死者的電腦和手機(jī)痰催,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門兜辞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來迎瞧,“玉大人,你說我怎么就攤上這事逸吵⌒坠瑁” “怎么了?”我有些...
    開封第一講書人閱讀 156,936評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵扫皱,是天一觀的道長足绅。 經(jīng)常有香客問我,道長韩脑,這世上最難降的妖魔是什么氢妈? 我笑而不...
    開封第一講書人閱讀 56,427評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮段多,結(jié)果婚禮上首量,老公的妹妹穿的比我還像新娘。我一直安慰自己进苍,他們只是感情好加缘,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,467評(píng)論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著觉啊,像睡著了一般拣宏。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上杠人,一...
    開封第一講書人閱讀 49,785評(píng)論 1 290
  • 那天勋乾,我揣著相機(jī)與錄音,去河邊找鬼嗡善。 笑死市俊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的滤奈。 我是一名探鬼主播摆昧,決...
    沈念sama閱讀 38,931評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蜒程!你這毒婦竟也來了绅你?” 一聲冷哼從身側(cè)響起伺帘,我...
    開封第一講書人閱讀 37,696評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎忌锯,沒想到半個(gè)月后伪嫁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,141評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡偶垮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,483評(píng)論 2 327
  • 正文 我和宋清朗相戀三年张咳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片似舵。...
    茶點(diǎn)故事閱讀 38,625評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡脚猾,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出砚哗,到底是詐尸還是另有隱情龙助,我是刑警寧澤,帶...
    沈念sama閱讀 34,291評(píng)論 4 329
  • 正文 年R本政府宣布蛛芥,位于F島的核電站提鸟,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏仅淑。R本人自食惡果不足惜称勋,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,892評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望涯竟。 院中可真熱鬧赡鲜,春花似錦、人聲如沸昆禽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽醉鳖。三九已至捡硅,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間盗棵,已是汗流浹背壮韭。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留纹因,地道東北人喷屋。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像瞭恰,于是被迫代替她去往敵國和親屯曹。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,492評(píng)論 2 348

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