大家好篡诽,我是九神。這是互聯(lián)網(wǎng)技術(shù)崗的分享專題墓塌,廢話少說(shuō),進(jìn)入正題:
35.并行和并發(fā)有什么區(qū)別奥额?
并發(fā)(concurrency):指在同一時(shí)刻只能有一條指令執(zhí)行,但多個(gè)進(jìn)程指令被快速的輪換執(zhí)行访诱,使得在宏觀上具有多個(gè)進(jìn)程同時(shí)執(zhí)行的效果垫挨,但在微觀上并不是同時(shí)執(zhí)行的,只是把時(shí)間分成若干端触菜,使多個(gè)進(jìn)程快速交替的執(zhí)行九榔。
并行(parallellism):指在同一時(shí)刻,有多條指令在多個(gè)處理器上同時(shí)執(zhí)行涡相。
直白的:并發(fā)是交替執(zhí)行哲泊,并行是同時(shí)執(zhí)行。
36.線程和進(jìn)程的區(qū)別催蝗?
進(jìn)程是程序運(yùn)行和資源分配的基本單位切威,一個(gè)程序至少有一個(gè)進(jìn)程,一個(gè)進(jìn)程至少有一個(gè)線程丙号。
進(jìn)程在執(zhí)行過(guò)程中擁有獨(dú)立的內(nèi)存單元先朦,而多個(gè)線程共享內(nèi)存資源缰冤,減少切換次數(shù),從而效率更高喳魏。
線程是進(jìn)程的一個(gè)實(shí)體棉浸,是cpu調(diào)度和分派的基本單位,是比程序更小的能獨(dú)立運(yùn)行的基本單位刺彩。同一進(jìn)程中的多個(gè)線程之間可以并發(fā)執(zhí)行迷郑。
37.守護(hù)線程是什么?
java里線程分2種:
1创倔、守護(hù)線程(即daemon thread)嗡害,是個(gè)服務(wù)線程,準(zhǔn)確地來(lái)說(shuō)就是服務(wù)其他的線程三幻。比如垃圾回收線程就漾,就是最典型的守護(hù)線程。
2念搬、用戶線程抑堡,就是應(yīng)用程序里的自定義線程。
守護(hù)線程的意義
當(dāng)主線程結(jié)束時(shí)朗徊,結(jié)束其余的子線程(守護(hù)線程)自動(dòng)關(guān)閉首妖,就免去了還要繼續(xù)關(guān)閉子線程的麻煩。
如:Java垃圾回收線程就是一個(gè)典型的守護(hù)線程爷恳;內(nèi)存資源或者線程的管理有缆,但是非守護(hù)線程也可以。
38.創(chuàng)建線程有哪幾種方式温亲?
1棚壁、繼承Thread類創(chuàng)建線程類
定義Thread類的子類,并重寫該類的run方法栈虚,該run方法的方法體就代表了線程要完成的任務(wù)袖外。因此把run()方法稱為執(zhí)行體。
創(chuàng)建Thread子類的實(shí)例魂务,即創(chuàng)建了線程對(duì)象曼验。
調(diào)用線程對(duì)象的start()方法來(lái)啟動(dòng)該線程。
2粘姜、通過(guò)Runnable接口創(chuàng)建線程類
定義runnable接口的實(shí)現(xiàn)類鬓照,并重寫該接口的run()方法,該run()方法的方法體同樣是該線程的線程執(zhí)行體孤紧。
創(chuàng)建 Runnable實(shí)現(xiàn)類的實(shí)例豺裆,并依此實(shí)例作為Thread的target來(lái)創(chuàng)建Thread對(duì)象,該Thread對(duì)象才是真正的線程對(duì)象号显。
調(diào)用線程對(duì)象的start()方法來(lái)啟動(dòng)該線程留储。
3翼抠、通過(guò)Callable和Future創(chuàng)建線程
創(chuàng)建Callable接口的實(shí)現(xiàn)類,并實(shí)現(xiàn)call()方法获讳,該call()方法將作為線程執(zhí)行體阴颖,并且有返回值。
創(chuàng)建Callable實(shí)現(xiàn)類的實(shí)例丐膝,使用FutureTask類來(lái)包裝Callable對(duì)象量愧,該FutureTask對(duì)象封裝了該Callable對(duì)象的call()方法的返回值。
使用FutureTask對(duì)象作為Thread對(duì)象的target創(chuàng)建并啟動(dòng)新線程帅矗。
調(diào)用FutureTask對(duì)象的get()方法來(lái)獲得子線程執(zhí)行結(jié)束后的返回值偎肃。
39.說(shuō)一下 runnable 和 callable 有什么區(qū)別?
Runnable接口中的run()方法的返回值是void浑此,它做的事情只是純粹地去執(zhí)行run()方法中的代碼而已累颂;
Callable接口中的call()方法是有返回值的,是一個(gè)泛型凛俱,和Future紊馏、FutureTask配合可以用來(lái)獲取異步執(zhí)行的結(jié)果。
40.線程有哪些狀態(tài)?
線程通常都有五種狀態(tài),創(chuàng)建没佑、就緒、運(yùn)行赫编、阻塞和死亡。
創(chuàng)建狀態(tài)奋隶。在生成線程對(duì)象擂送,并沒有調(diào)用該對(duì)象的start方法,這是線程處于創(chuàng)建狀態(tài)唯欣。
就緒狀態(tài)嘹吨。當(dāng)調(diào)用了線程對(duì)象的start方法之后,該線程就進(jìn)入了就緒狀態(tài)黍聂,但是此時(shí)線程調(diào)度程序還沒有把該線程設(shè)置為當(dāng)前線程,此時(shí)處于就緒狀態(tài)身腻。在線程運(yùn)行之后产还,從等待或者睡眠中回來(lái)之后,也會(huì)處于就緒狀態(tài)嘀趟。
運(yùn)行狀態(tài)脐区。線程調(diào)度程序?qū)⑻幱诰途w狀態(tài)的線程設(shè)置為當(dāng)前線程,此時(shí)線程就進(jìn)入了運(yùn)行狀態(tài)她按,開始運(yùn)行run函數(shù)當(dāng)中的代碼牛隅。
阻塞狀態(tài)炕柔。線程正在運(yùn)行的時(shí)候,被暫停媒佣,通常是為了等待某個(gè)時(shí)間的發(fā)生(比如說(shuō)某項(xiàng)資源就緒)之后再繼續(xù)運(yùn)行匕累。sleep,suspend默伍,wait等方法都可以導(dǎo)致線程阻塞欢嘿。
死亡狀態(tài)。如果一個(gè)線程的run方法執(zhí)行結(jié)束或者調(diào)用stop方法后也糊,該線程就會(huì)死亡炼蹦。對(duì)于已經(jīng)死亡的線程,無(wú)法再使用start方法令其進(jìn)入就緒
41.sleep() 和 wait() 有什么區(qū)別狸剃?
sleep():方法是線程類(Thread)的靜態(tài)方法掐隐,讓調(diào)用線程進(jìn)入睡眠狀態(tài),讓出執(zhí)行機(jī)會(huì)給其他線程钞馁,等到休眠時(shí)間結(jié)束后虑省,線程進(jìn)入就緒狀態(tài)和其他線程一起競(jìng)爭(zhēng)cpu的執(zhí)行時(shí)間。因?yàn)閟leep() 是static靜態(tài)的方法指攒,他不能改變對(duì)象的機(jī)鎖慷妙,當(dāng)一個(gè)synchronized塊中調(diào)用了sleep() 方法,線程雖然進(jìn)入休眠允悦,但是對(duì)象的機(jī)鎖沒有被釋放膝擂,其他線程依然無(wú)法訪問這個(gè)對(duì)象。
wait():wait()是Object類的方法隙弛,當(dāng)一個(gè)線程執(zhí)行到wait方法時(shí)架馋,它就進(jìn)入到一個(gè)和該對(duì)象相關(guān)的等待池,同時(shí)釋放對(duì)象的機(jī)鎖全闷,使得其他線程能夠訪問叉寂,可以通過(guò)notify,notifyAll方法來(lái)喚醒等待的線程
42.notify()和 notifyAll()有什么區(qū)別总珠?
如果線程調(diào)用了對(duì)象的 wait()方法屏鳍,那么線程便會(huì)處于該對(duì)象的等待池中,等待池中的線程不會(huì)去競(jìng)爭(zhēng)該對(duì)象的鎖局服。
當(dāng)有線程調(diào)用了對(duì)象的 notifyAll()方法(喚醒所有 wait 線程)或 notify()方法(只隨機(jī)喚醒一個(gè) wait 線程)钓瞭,被喚醒的的線程便會(huì)進(jìn)入該對(duì)象的鎖池中,鎖池中的線程會(huì)去競(jìng)爭(zhēng)該對(duì)象鎖淫奔。也就是說(shuō)山涡,調(diào)用了notify后只要一個(gè)線程會(huì)由等待池進(jìn)入鎖池,而notifyAll會(huì)將該對(duì)象等待池內(nèi)的所有線程移動(dòng)到鎖池中,等待鎖競(jìng)爭(zhēng)鸭丛。
優(yōu)先級(jí)高的線程競(jìng)爭(zhēng)到對(duì)象鎖的概率大竞穷,假若某線程沒有競(jìng)爭(zhēng)到該對(duì)象鎖,它還會(huì)留在鎖池中鳞溉,唯有線程再次調(diào)用 wait()方法瘾带,它才會(huì)重新回到等待池中。而競(jìng)爭(zhēng)到對(duì)象鎖的線程則繼續(xù)往下執(zhí)行穿挨,直到執(zhí)行完了 synchronized 代碼塊月弛,它會(huì)釋放掉該對(duì)象鎖,這時(shí)鎖池中的線程會(huì)繼續(xù)競(jìng)爭(zhēng)該對(duì)象鎖科盛。
43.線程的 run()和 start()有什么區(qū)別帽衙?
每個(gè)線程都是通過(guò)某個(gè)特定Thread對(duì)象所對(duì)應(yīng)的方法run()來(lái)完成其操作的,方法run()稱為線程體贞绵。通過(guò)調(diào)用Thread類的start()方法來(lái)啟動(dòng)一個(gè)線程厉萝。
start()方法來(lái)啟動(dòng)一個(gè)線程,真正實(shí)現(xiàn)了多線程運(yùn)行榨崩。這時(shí)無(wú)需等待run方法體代碼執(zhí)行完畢谴垫,可以直接繼續(xù)執(zhí)行下面的代碼;這時(shí)此線程是處于就緒狀態(tài)母蛛, 并沒有運(yùn)行翩剪。然后通過(guò)此Thread類調(diào)用方法run()來(lái)完成其運(yùn)行狀態(tài), 這里方法run()稱為線程體彩郊,它包含了要執(zhí)行的這個(gè)線程的內(nèi)容前弯, Run方法運(yùn)行結(jié)束, 此線程終止秫逝。然后CPU再調(diào)度其它線程恕出。
run()方法是在本線程里的,只是線程里的一個(gè)函數(shù),而不是多線程的违帆。如果直接調(diào)用run(),其實(shí)就相當(dāng)于是調(diào)用了一個(gè)普通函數(shù)而已浙巫,直接待用run()方法必須等待run()方法執(zhí)行完畢才能執(zhí)行下面的代碼,所以執(zhí)行路徑還是只有一條刷后,根本就沒有線程的特征的畴,所以在多線程執(zhí)行時(shí)要使用start()方法而不是run()方法。
44.創(chuàng)建線程池有哪幾種方式尝胆?
1丧裁、newFixedThreadPool(int nThreads)
創(chuàng)建一個(gè)固定長(zhǎng)度的線程池,每當(dāng)提交一個(gè)任務(wù)就創(chuàng)建一個(gè)線程班巩,直到達(dá)到線程池的最大數(shù)量渣慕,這時(shí)線程規(guī)模將不再變化,當(dāng)線程發(fā)生未預(yù)期的錯(cuò)誤而結(jié)束時(shí)抱慌,線程池會(huì)補(bǔ)充一個(gè)新的線程逊桦。
2、newCachedThreadPool()
創(chuàng)建一個(gè)可緩存的線程池抑进,如果線程池的規(guī)模超過(guò)了處理需求强经,將自動(dòng)回收空閑線程,而當(dāng)需求增加時(shí)寺渗,則可以自動(dòng)添加新線程匿情,線程池的規(guī)模不存在任何限制。
3信殊、newSingleThreadExecutor()
這是一個(gè)單線程的Executor炬称,它創(chuàng)建單個(gè)工作線程來(lái)執(zhí)行任務(wù),如果這個(gè)線程異常結(jié)束涡拘,會(huì)創(chuàng)建一個(gè)新的來(lái)替代它玲躯;它的特點(diǎn)是能確保依照任務(wù)在隊(duì)列中的順序來(lái)串行執(zhí)行。
4鳄乏、newScheduledThreadPool(int corePoolSize)
創(chuàng)建了一個(gè)固定長(zhǎng)度的線程池跷车,而且以延遲或定時(shí)的方式來(lái)執(zhí)行任務(wù),類似于Timer橱野。
45.線程池都有哪些狀態(tài)朽缴?
線程池有5種狀態(tài):Running、ShutDown水援、Stop密强、Tidying、Terminated裹唆。
線程池各個(gè)狀態(tài)切換框架圖:
46.線程池中 submit()和 execute()方法有什么區(qū)別誓斥?
接收的參數(shù)不一樣
submit有返回值,而execute沒有
submit方便Exception處理
47.在 java 程序中怎么保證多線程的運(yùn)行安全许帐?
線程安全在三個(gè)方面體現(xiàn):
原子性:提供互斥訪問劳坑,同一時(shí)刻只能有一個(gè)線程對(duì)數(shù)據(jù)進(jìn)行操作,(atomic,synchronized)成畦;
可見性:一個(gè)線程對(duì)主內(nèi)存的修改可以及時(shí)地被其他線程看到距芬,(synchronized,volatile);
有序性:一個(gè)線程觀察其他線程中的指令執(zhí)行順序循帐,由于指令重排序框仔,該觀察結(jié)果一般雜亂無(wú)序,(happens-before原則)拄养。
48.多線程鎖的升級(jí)原理是什么离斩?
鎖的級(jí)別:無(wú)鎖->偏向鎖->輕量級(jí)鎖->重量級(jí)鎖
鎖分級(jí)別原因:沒有優(yōu)化前银舱,sychroniezed是重量級(jí)鎖(悲觀鎖),使用wait跛梗、notify寻馏、notifyAll來(lái)切換線程狀態(tài)非常消耗系統(tǒng)資源,線程的掛起和喚醒間隔很短暫核偿,這樣很浪費(fèi)資源诚欠,影響性能。所以JVM對(duì)sychronized關(guān)鍵字進(jìn)行了優(yōu)化漾岳,把鎖分為無(wú)鎖轰绵、偏向鎖、輕量級(jí)鎖尼荆、重量級(jí)鎖左腔。當(dāng)JVM檢測(cè)到不同的競(jìng)爭(zhēng)狀態(tài)時(shí),就會(huì)根據(jù)需要自動(dòng)切換到合適的鎖捅儒,這種切換就是鎖的升級(jí)翔悠。
升級(jí)是不可逆的,也就是說(shuō)只能從低到高野芒,也就是偏向-->輕量級(jí)-->重量級(jí)蓄愁,不能夠降級(jí)
以下是五種鎖(醬油君評(píng):非必要回答,答上來(lái)加分):
一狞悲、無(wú)鎖
沒有對(duì)資源進(jìn)行鎖定撮抓,所有的線程都能訪問并修改同一個(gè)資源,但同時(shí)只有一個(gè)線程能修改成功摇锋,其它修改失敗的線程會(huì)不斷重試直到修改成功丹拯。
二、偏向鎖
對(duì)象的代碼一直被同一線程執(zhí)行荸恕,不存在多個(gè)線程競(jìng)爭(zhēng)乖酬,該線程在后續(xù)執(zhí)行中自動(dòng)獲取鎖,降低獲取鎖帶來(lái)的性能開銷融求。偏向鎖咬像,指的是偏向第一個(gè)加鎖線程,該線程是不會(huì)主動(dòng)釋放偏向鎖的生宛,只有當(dāng)其他線程嘗試競(jìng)爭(zhēng)偏向鎖才會(huì)被釋放县昂。
偏向鎖的撤銷,需要在某個(gè)時(shí)間點(diǎn)上沒有字節(jié)碼正在執(zhí)行時(shí)陷舅,先暫停偏向鎖的線程倒彰,然后判斷鎖對(duì)象是否處于被鎖定狀態(tài),如果線程不處于活動(dòng)狀態(tài)莱睁,則將對(duì)象頭設(shè)置成無(wú)鎖狀態(tài)待讳,并撤銷偏向鎖芒澜。
如果線程處于活動(dòng)狀態(tài),升級(jí)為輕量級(jí)鎖的狀態(tài)创淡。
三撰糠、輕量級(jí)鎖
輕量級(jí)鎖是指當(dāng)鎖是偏向鎖的時(shí)候,被第二個(gè)線程B訪問辩昆,此時(shí)偏向鎖就會(huì)升級(jí)為輕量級(jí)鎖,線程B會(huì)通過(guò)自旋的形式嘗試獲取鎖旨袒,線程不會(huì)阻塞汁针,從未提升性能。
當(dāng)前只有一個(gè)等待線程砚尽,則該線程將通過(guò)自旋進(jìn)行等待施无。但是當(dāng)自旋超過(guò)一定次數(shù)時(shí),輕量級(jí)鎖邊會(huì)升級(jí)為重量級(jí)鎖必孤,當(dāng)一個(gè)線程已持有鎖猾骡,另一個(gè)線程在自旋,而此時(shí)第三個(gè)線程來(lái)訪時(shí)敷搪,輕量級(jí)鎖也會(huì)升級(jí)為重量級(jí)鎖兴想。
注:自旋是什么?
自旋(spinlock)是指當(dāng)一個(gè)線程獲取鎖的時(shí)候赡勘,如果鎖已經(jīng)被其它線程獲取嫂便,那么該線程將循環(huán)等待,然后不斷的判斷鎖是否能夠被成功獲取闸与,直到獲取到鎖才會(huì)退出循環(huán)毙替。
四、重量級(jí)鎖
指當(dāng)有一個(gè)線程獲取鎖之后践樱,其余所有等待獲取該鎖的線程都會(huì)處于阻塞狀態(tài)厂画。
重量級(jí)鎖通過(guò)對(duì)象內(nèi)部的監(jiān)聽器(monitor)實(shí)現(xiàn),而其中monitor的本質(zhì)是依賴于底層操作系統(tǒng)的Mutex Lock實(shí)現(xiàn)拷邢,操作系統(tǒng)實(shí)現(xiàn)線程之間的切換需要從用戶態(tài)切換到內(nèi)核態(tài)袱院,切換成本非常高。
鎖升級(jí)的圖示過(guò)程:
49.什么是死鎖瞭稼?
死鎖是指兩個(gè)或兩個(gè)以上的進(jìn)程在執(zhí)行過(guò)程中坑填,由于競(jìng)爭(zhēng)資源或者由于彼此通信而造成的一種阻塞的現(xiàn)象,若無(wú)外力作用弛姜,它們都將無(wú)法推進(jìn)下去脐瑰。此時(shí)稱系統(tǒng)處于死鎖狀態(tài)或系統(tǒng)產(chǎn)生了死鎖,這些永遠(yuǎn)在互相等待的進(jìn)程稱為死鎖進(jìn)程廷臼。是操作系統(tǒng)層面的一個(gè)錯(cuò)誤苍在,是進(jìn)程死鎖的簡(jiǎn)稱绝页,最早在 1965 年由 Dijkstra 在研究銀行家算法時(shí)提出的,它是計(jì)算機(jī)操作系統(tǒng)乃至整個(gè)并發(fā)程序設(shè)計(jì)領(lǐng)域最難處理的問題之一寂恬。
50.怎么防止死鎖续誉?
死鎖的四個(gè)必要條件:
互斥條件:進(jìn)程對(duì)所分配到的資源不允許其他進(jìn)程進(jìn)行訪問,若其他進(jìn)程訪問該資源初肉,只能等待酷鸦,直至占有該資源的進(jìn)程使用完成后釋放該資源
請(qǐng)求和保持條件:進(jìn)程獲得一定的資源之后,又對(duì)其他資源發(fā)出請(qǐng)求牙咏,但是該資源可能被其他進(jìn)程占有臼隔,此事請(qǐng)求阻塞,但又對(duì)自己獲得的資源保持不放
不可剝奪條件:是指進(jìn)程已獲得的資源妄壶,在未完成使用之前摔握,不可被剝奪,只能在使用完后自己釋放
環(huán)路等待條件:是指進(jìn)程發(fā)生死鎖后丁寄,若干進(jìn)程之間形成一種頭尾相接的循環(huán)等待資源關(guān)系
這四個(gè)條件是死鎖的必要條件氨淌,只要系統(tǒng)發(fā)生死鎖,這些條件必然成立伊磺,而只要上述條件之 一不滿足盛正,就不會(huì)發(fā)生死鎖。
理解了死鎖的原因屑埋,尤其是產(chǎn)生死鎖的四個(gè)必要條件蛮艰,就可以最大可能地避免、預(yù)防和 解除死鎖雀彼。
所以壤蚜,在系統(tǒng)設(shè)計(jì)、進(jìn)程調(diào)度等方面注意如何不讓這四個(gè)必要條件成立徊哑,如何確 定資源的合理分配算法袜刷,避免進(jìn)程永久占據(jù)系統(tǒng)資源。
此外莺丑,也要防止進(jìn)程在處于等待狀態(tài)的情況下占用資源著蟹。因此,對(duì)資源的分配要給予合理的規(guī)劃梢莽。
51.ThreadLocal 是什么萧豆?有哪些使用場(chǎng)景?
線程局部變量是局限于線程內(nèi)部的變量昏名,屬于線程自身所有涮雷,不在多個(gè)線程間共享。Java提供ThreadLocal類來(lái)支持線程局部變量轻局,是一種實(shí)現(xiàn)線程安全的方式洪鸭。
但是在管理環(huán)境下(如 web 服務(wù)器)使用線程局部變量的時(shí)候要特別小心样刷,在這種情況下,工作線程的生命周期比任何應(yīng)用變量的生命周期都要長(zhǎng)览爵。任何線程局部變量一旦在工作完成后沒有釋放置鼻,Java 應(yīng)用就存在內(nèi)存泄露的風(fēng)險(xiǎn)。
52.說(shuō)一下 synchronized 底層實(shí)現(xiàn)原理蜓竹?
synchronized可以保證方法或者代碼塊在運(yùn)行時(shí)箕母,同一時(shí)刻只有一個(gè)方法可以進(jìn)入到臨界區(qū),同時(shí)它還可以保證共享變量的內(nèi)存可見性俱济。
Java中每一個(gè)對(duì)象都可以作為鎖嘶是,這是synchronized實(shí)現(xiàn)同步的基礎(chǔ):
普通同步方法,鎖是當(dāng)前實(shí)例對(duì)象
靜態(tài)同步方法姨蝴,鎖是當(dāng)前類的class對(duì)象
同步方法塊,鎖是括號(hào)里面的對(duì)象
53.synchronized 和 volatile 的區(qū)別是什么肺缕?
volatile本質(zhì)是在告訴jvm當(dāng)前變量在寄存器(工作內(nèi)存)中的值是不確定的左医,需要從主存中讀取同木;synchronized則是鎖定當(dāng)前變量浮梢,只有當(dāng)前線程可以訪問該變量,其他線程被阻塞住彤路。
volatile僅能使用在變量級(jí)別秕硝;synchronized則可以使用在變量、方法洲尊、和類級(jí)別的远豺。
volatile僅能實(shí)現(xiàn)變量的修改可見性,不能保證原子性坞嘀;而synchronized則可以保證變量的修改可見性和原子性躯护。
volatile不會(huì)造成線程的阻塞;synchronized可能會(huì)造成線程的阻塞丽涩。
volatile標(biāo)記的變量不會(huì)被編譯器優(yōu)化棺滞;synchronized標(biāo)記的變量可以被編譯器優(yōu)化。
54.synchronized 和 Lock 有什么區(qū)別矢渊?
首先synchronized是java內(nèi)置關(guān)鍵字继准,在jvm層面,Lock是個(gè)java類矮男;
synchronized無(wú)法判斷是否獲取鎖的狀態(tài)移必,Lock可以判斷是否獲取到鎖;
synchronized會(huì)自動(dòng)釋放鎖(a 線程執(zhí)行完同步代碼會(huì)釋放鎖 毡鉴;b 線程執(zhí)行過(guò)程中發(fā)生異常會(huì)釋放鎖)避凝,Lock需在finally中手工釋放鎖(unlock()方法釋放鎖)舞萄,否則容易造成線程死鎖;
用synchronized關(guān)鍵字的兩個(gè)線程1和線程2管削,如果當(dāng)前線程1獲得鎖倒脓,線程2線程等待。如果線程1阻塞含思,線程2則會(huì)一直等待下去崎弃,而Lock鎖就不一定會(huì)等待下去,如果嘗試獲取不到鎖含潘,線程可以不用一直等待就結(jié)束了饲做;
synchronized的鎖可重入、不可中斷遏弱、非公平盆均,而Lock鎖可重入、可判斷漱逸、可公平(兩者皆可)泪姨;
Lock鎖適合大量同步的代碼的同步問題,synchronized鎖適合代碼少量的同步問題饰抒。
55.synchronized 和 ReentrantLock 區(qū)別是什么肮砾?
synchronized是和if、else袋坑、for仗处、while一樣的關(guān)鍵字,ReentrantLock是類枣宫,這是二者的本質(zhì)區(qū)別婆誓。既然ReentrantLock是類,那么它就提供了比synchronized更多更靈活的特性也颤,可以被繼承旷档、可以有方法、可以有各種各樣的類變量歇拆,ReentrantLock比synchronized的擴(kuò)展性體現(xiàn)在幾點(diǎn)上:
ReentrantLock可以對(duì)獲取鎖的等待時(shí)間進(jìn)行設(shè)置鞋屈,這樣就避免了死鎖
ReentrantLock可以獲取各種鎖的信息
ReentrantLock可以靈活地實(shí)現(xiàn)多路通知
另外,二者的鎖機(jī)制其實(shí)也是不一樣的:ReentrantLock底層調(diào)用的是Unsafe的park方法加鎖故觅,synchronized操作的應(yīng)該是對(duì)象頭中mark word厂庇。
56.說(shuō)一下 atomic 的原理?
Atomic包中的類基本的特性就是在多線程環(huán)境下输吏,當(dāng)有多個(gè)線程同時(shí)對(duì)單個(gè)(包括基本類型及引用類型)變量進(jìn)行操作時(shí)权旷,具有排他性,即當(dāng)多個(gè)線程同時(shí)對(duì)該變量的值進(jìn)行更新時(shí),僅有一個(gè)線程能成功拄氯,而未成功的線程可以向自旋鎖一樣躲查,繼續(xù)嘗試,一直等到執(zhí)行成功译柏。
Atomic系列的類中的核心方法都會(huì)調(diào)用unsafe類中的幾個(gè)本地方法镣煮。我們需要先知道一個(gè)東西就是Unsafe類,全名為:sun.misc.Unsafe鄙麦,這個(gè)類包含了大量的對(duì)C代碼的操作典唇,包括很多直接內(nèi)存分配以及原子操作的調(diào)用,而它之所以標(biāo)記為非安全的胯府,是告訴你這個(gè)里面大量的方法調(diào)用都會(huì)存在安全隱患介衔,需要小心使用,否則會(huì)導(dǎo)致嚴(yán)重的后果骂因,例如在通過(guò)unsafe分配內(nèi)存的時(shí)候炎咖,如果自己指定某些區(qū)域可能會(huì)導(dǎo)致一些類似C++一樣的指針越界到其他進(jìn)程的問題。
文章轉(zhuǎn)載自:
經(jīng)典Java面試題的答案——多線程