常見并發(fā)面試題

問:在java中守護(hù)線程和用戶線程的區(qū)別?

答:java中的線程分為兩種:守護(hù)線程(Daemon)和用戶線程(User)陈惰。任何線程都可以設(shè)置為守護(hù)線程和用戶線程畦徘,通過方法Thread.setDaemon(bool on);true 則把該線程設(shè)置為守護(hù)線程抬闯,反之則為用戶線程井辆。Thread.setDaemon()必須在Thread.start()之前調(diào)用,否則運行時會拋出異常溶握。兩者的區(qū)別:唯一的區(qū)別是判斷虛擬機(jī)(JVM)何時離開掘剪,Daemon 是為其他線程提供服務(wù),如果全部的User Thread 已經(jīng)結(jié)束奈虾,Daemon 沒有可服務(wù)的線程夺谁,JVM 關(guān)閉廉赔。擴(kuò)展:Thread Dump 打印出來的線程信息,含有daemon 字樣的線即為守護(hù)進(jìn)程匾鸥。

問:線程與進(jìn)程的區(qū)別蜡塌?

答:進(jìn)程是操作系統(tǒng)分配資源的最小單元,線程是操作系統(tǒng)調(diào)度的最小單元勿负。一個程序至少有一個進(jìn)程,一個進(jìn)程至少有一個線程馏艾。

問:什么是多線程中的上下文切換?

答:多線程會共同使用一組計算機(jī)上的CPU奴愉,而線程數(shù)大于給程序分配的CPU數(shù)量時琅摩,為了各個線程都有執(zhí)行的機(jī)會,就需要輪轉(zhuǎn)使用CPU锭硼。不同的線程切換使用CPU 發(fā)生的切換數(shù)據(jù)等就是上下文切換房资。

問:死鎖與活鎖的區(qū)別,死鎖與饑餓的區(qū)別檀头?

答:死鎖:是指兩個或兩個以上的進(jìn)程(或線程)在執(zhí)行過程中轰异,因爭奪資源而造成的一種互相等待的現(xiàn)象,若無外力作用暑始,它們都將無法推進(jìn)下去搭独。產(chǎn)生死鎖的必要條件:互斥條件:所謂互斥就是進(jìn)程在某一時間內(nèi)獨占資源。請求與保持條件:一個進(jìn)程因請求資源而阻塞時廊镜,對已獲得的資源保持不放牙肝。不剝奪條件:進(jìn)程已獲得資源,在末使用完之前嗤朴,不能強(qiáng)行剝奪惊奇。循環(huán)等待條件:若干進(jìn)程之間形成一種頭尾相接的循環(huán)等待資源關(guān)系〔チ蓿活鎖:任務(wù)或者執(zhí)行者沒有被阻塞,由于某些條件沒有滿足吼渡,導(dǎo)致一直重復(fù)嘗試容为,失敗,嘗試寺酪,失敗坎背。活鎖和死鎖的區(qū)別在于寄雀,處于活鎖的實體是在不斷的改變狀態(tài)得滤,所謂的“活”,而處于死鎖的實體表現(xiàn)為等待盒犹;活鎖有可能自行解開懂更,死鎖則不能眨业。饑餓:一個或者多個線程因為種種原因無法獲得所需要的資源,導(dǎo)致一直無法執(zhí)行的狀態(tài)沮协。

問:synchronized底層實現(xiàn)原理龄捡?

答:synchronized (this)原理:涉及兩條指令:monitorenter,monitorexit慷暂;再說同步方法聘殖,從同步方法反編譯的結(jié)果來看,方法的同步并沒有通過指令monitorenter 和monitorexit 來實現(xiàn)行瑞,相對于普通方法奸腺,其常量池中多了ACC_SYNCHRONIZED 標(biāo)示符。JVM 就是根據(jù)該標(biāo)示符來實現(xiàn)方法的同步的:當(dāng)方法被調(diào)用時血久,調(diào)用指令將會檢查方法的ACC_SYNCHRONIZED 訪問標(biāo)志是否被設(shè)置突照,如果設(shè)置了,執(zhí)行線程將先獲取monitor洋魂,獲取成功之后才能執(zhí)行方法體绷旗,方法執(zhí)行完后再釋放monitor。在方法執(zhí)行期間副砍,其他任何線程都無法再獲得同一個monitor 對象衔肢。注意,這個問題可能會接著追問豁翎,java 對象頭信息角骤,偏向鎖,輕量鎖心剥,重量級鎖及其他們相互間轉(zhuǎn)化邦尊。

問:什么是線程組,為什么在Java中不推薦使用优烧?

答:ThreadGroup類蝉揍,可以把線程歸屬到某一個線程組中,線程組中可以有線程對象畦娄,也可以有線程組又沾,組中還可以有線程,這樣的組織結(jié)構(gòu)有點類似于樹的形式熙卡。1.線程組ThreadGroup 對象中比較有用的方法是stop杖刷、resume、suspend 等方法驳癌,由于這幾個方法會導(dǎo)致線程的安全問題(主要是死鎖問題)滑燃,已經(jīng)被官方廢棄掉了,所以線程組本身的應(yīng)用價值就大打折扣了颓鲜。2.線程組ThreadGroup 不是線程安全的表窘,這在使用過程中獲取的信息并不全是及時有效的典予,這就降低了它的統(tǒng)計使用價值。

問:什么是Executors框架蚊丐?為什么使用Executor 框架熙参?

答:Executor框架是一個根據(jù)一組執(zhí)行策略調(diào)用,調(diào)度麦备,執(zhí)行和控制的異步任務(wù)的框架孽椰。每次執(zhí)行任務(wù)創(chuàng)建線程new Thread()比較消耗性能,創(chuàng)建一個線程是比較耗時凛篙、耗資源的黍匾。調(diào)用new Thread()創(chuàng)建的線程缺乏管理,而且可以無限制的創(chuàng)建呛梆,線程之間的相互競爭會導(dǎo)致過多占用系統(tǒng)資源而導(dǎo)致系統(tǒng)癱瘓锐涯,還有線程之間的頻繁交替也會消耗很多系統(tǒng)資源。接使用new Thread() 啟動的線程不利于擴(kuò)展填物,比如定時執(zhí)行娶桦、定期執(zhí)行懈费、定時定期執(zhí)行、線程中斷等都不便實現(xiàn)。

問:在Java中Executor 和Executors 的區(qū)別忿墅?

答:Executors工具類的不同方法按照我們的需求創(chuàng)建了不同的線程池右遭,來滿足業(yè)務(wù)的需求吮蛹。Executor 接口對象能執(zhí)行我們的線程任務(wù)轿偎。ExecutorService 接口繼承了Executor 接口并進(jìn)行了擴(kuò)展,提供了更多的方法我們能獲得任務(wù)執(zhí)行的狀態(tài)并且可以獲取任務(wù)的返回值阅茶。使用ThreadPoolExecutor 可以創(chuàng)建自定義線程池蛛枚。

問:什么是原子操作?在Java Concurrency API中有哪些原子類(atomicclasses)脸哀?

答:原子操作(atomic operation)意為”不可被中斷的一個或一系列操作”蹦浦。處理器使用基于對緩存加鎖或總線加鎖的方式來實現(xiàn)多處理器之間的原子操作。在Java 中可以通過鎖和循環(huán)CAS 的方式來實現(xiàn)原子操作撞蜂。CAS 操作——Compare & Set盲镶,或是Compare & Swap,現(xiàn)在幾乎所有的CPU 指令都支持CAS 的原子操作谅摄。java.util.concurrent.atomic 下提供了大量的原子操作類,比如原子類:AtomicBoolean系馆,AtomicInteger送漠,AtomicLong,AtomicReference 由蘑,原子數(shù)組:AtomicIntegerArray闽寡,AtomicLongArray代兵,AtomicReferenceArray ,原子屬性更新器:AtomicLongFieldUpdater爷狈,AtomicIntegerFieldUpdater植影,AtomicReferenceFieldUpdater。

問:Java Concurrency API中的Lock 接口(Lock interface)是什么涎永?對比synchronized 它有什么優(yōu)勢思币?

答:Lock接口比同步方法和同步塊提供了更具擴(kuò)展性的鎖操作。他們允許更靈活的結(jié)構(gòu)羡微,可以具有完全不同的性質(zhì)谷饿,并且可以支持多個相關(guān)類的條件對象。它的優(yōu)勢有:可以使鎖更公平妈倔,可以使線程在等待鎖的時候響應(yīng)中斷博投,可以讓線程嘗試獲取鎖,并在無法獲取鎖的時候立即返回或者等待一段時間盯蝴,可以在不同的范圍毅哗,以不同的順序獲取和釋放鎖。整體上來說Lock 是synchronized 的擴(kuò)展版捧挺,Lock 提供了無條件的虑绵、可輪詢的(tryLock 方法)、定時的(tryLock 帶參方法)松忍、可中斷的(lockInterruptibly)蒸殿、可多條件隊列的(newCondition 方法)鎖操作。另外Lock 的實現(xiàn)類基本都支持非公平鎖(默認(rèn))和公平鎖鸣峭,synchronized 只支持非公平鎖宏所,當(dāng)然,在大部分情況下摊溶,非公平鎖是高效的選擇爬骤。

問:什么是阻塞隊列?阻塞隊列的實現(xiàn)原理是什么莫换?如何使用阻塞隊列來實現(xiàn)生產(chǎn)者-消費者模型霞玄?

答:阻塞隊列(BlockingQueue)是一個支持兩個附加操作的隊列。這兩個附加的操作是:在隊列為空時拉岁,獲取元素的線程會等待隊列變?yōu)榉强湛谰纭.?dāng)隊列滿時,存儲元素的線程會等待隊列可用喊暖。阻塞隊列常用于生產(chǎn)者和消費者的場景惫企,生產(chǎn)者是往隊列里添加元素的線程,消費者是從隊列里拿元素的線程。阻塞隊列就是生產(chǎn)者存放元素的容器狞尔,而消費者也只從容器里拿元素丛版。JDK7 提供了7 個阻塞隊列。在實現(xiàn)上偏序,主要是利用了Condition 和Lock 的等待通知模式页畦。

問:什么是Callable和Future?

答:Callable接口類似于Runnable,從名字就可以看出來了研儒,但是Runnable 不會返回結(jié)果豫缨,并且無法拋出返回結(jié)果的異常,而Callable 功能更強(qiáng)大一些殉摔,被線程執(zhí)行后州胳,可以返回值,這個返回值可以被Future 拿到逸月,也就是說栓撞,F(xiàn)uture 可以拿到異步執(zhí)行任務(wù)的返回值⊥胗玻可以認(rèn)為是帶有回調(diào)的Runnable瓤湘。Future 接口表示異步任務(wù),是還沒有完成的任務(wù)給出的未來結(jié)果恩尾。所以說Callable 用于產(chǎn)生結(jié)果弛说,F(xiàn)uture 用于獲取結(jié)果。

問:什么是FutureTask?

答:在Java并發(fā)程序中FutureTask 表示一個可以取消的異步運算翰意。它有啟動和取消運算木人、查詢運算是否完成和取回運算結(jié)果等方法。只有當(dāng)運算完成的時候結(jié)果才能取回冀偶,如果運算尚未完成get 方法將會阻塞醒第。一個FutureTask 對象可以對調(diào)用了Callable 和Runnable 的對象進(jìn)行包裝,由于FutureTask 也是調(diào)用了Runnable 接口所以它可以提交給Executor 來執(zhí)行进鸠。

問:什么是并發(fā)容器的實現(xiàn)稠曼?

答:何為同步容器:可以簡單地理解為通過synchronized來實現(xiàn)同步的容器,如果有多個線程調(diào)用同步容器的方法客年,它們將會串行執(zhí)行霞幅。比如Vector,Hashtable量瓜,以及Collections.synchronizedSet司恳,synchronizedList 等方法返回的容器。并發(fā)容器使用了與同步容器完全不同的加鎖策略來提供更高的并發(fā)性和伸縮性绍傲,例如在ConcurrentHashMap 中采用了一種粒度更細(xì)的加鎖機(jī)制扔傅,可以稱為分段鎖,在這種鎖機(jī)制下,允許任意數(shù)量的讀線程并發(fā)地訪問map铅鲤,并且執(zhí)行讀操作的線程和寫操作的線程也可以并發(fā)的訪問map,同時允許一定數(shù)量的寫操作線程并發(fā)地修改map枫弟,所以它可以在并發(fā)環(huán)境下實現(xiàn)更高的吞吐量邢享。

問:多線程同步和互斥有幾種實現(xiàn)方法,都是什么淡诗?

答:線程同步是指線程之間所具有的一種制約關(guān)系骇塘,一個線程的執(zhí)行依賴另一個線程的消息,當(dāng)它沒有得到另一個線程的消息時應(yīng)等待韩容,直到消息到達(dá)時才被喚醒款违。線程互斥是指對于共享的進(jìn)程系統(tǒng)資源,在各單個線程訪問時的排它性群凶。當(dāng)有若干個線程都要使用某一共享資源時插爹,任何時刻最多只允許一個線程去使用,其它要使用該資源的線程必須等待请梢,直到占用資源者釋放該資源赠尾。線程互斥可以看成是一種特殊的線程同步。線程間的同步方法大體可分為兩類:用戶模式和內(nèi)核模式毅弧。顧名思義气嫁,內(nèi)核模式就是指利用系統(tǒng)內(nèi)核對象的單一性來進(jìn)行同步,使用時需要切換內(nèi)核態(tài)與用戶態(tài)够坐,而用戶模式就是不需要切換到內(nèi)核態(tài)寸宵,只在用戶態(tài)完成操作。用戶模式下的方法有:原子操作(例如一個單一的全局變量)元咙,臨界區(qū)梯影。內(nèi)核模式下的方法有:事件,信號量蛾坯,互斥量光酣。

問:什么是競爭條件?

答:當(dāng)多個進(jìn)程都企圖對共享數(shù)據(jù)進(jìn)行某種處理脉课,而最后的結(jié)果又取決于進(jìn)程運行的順序時救军,則我們認(rèn)為這發(fā)生了競爭條件(race condition)。

問:為什么我們調(diào)用start()方法時會執(zhí)行run()方法倘零,為什么我們不能直接調(diào)用run()方法唱遭?

答:當(dāng)你調(diào)用start()方法時你將創(chuàng)建新的線程,并且執(zhí)行在run()方法里的代碼呈驶。但是如果你直接調(diào)用run()方法拷泽,它不會創(chuàng)建新的線程也不會執(zhí)行調(diào)用線程的代碼,只會把run 方法當(dāng)作普通方法去執(zhí)行。

問:在Java中CycliBarriar 和CountdownLatch 有什么區(qū)別司致?

答:CyclicBarrier可以重復(fù)使用拆吆,而CountdownLatch 不能重復(fù)使用。

問:什么是不可變對象脂矫,它對寫并發(fā)應(yīng)用有什么幫助枣耀?

答:不可變對象(Immutable Objects)即對象一旦被創(chuàng)建它的狀態(tài)(對象的數(shù)據(jù),也即對象屬性值)就不能改變庭再,反之即為可變對象(Mutable Objects)捞奕。不可變對象的類即為不可變類(Immutable Class)。Java 平臺類庫中包含許多不可變類拄轻,如String颅围、基本類型的包裝類、BigInteger 和BigDecimal 等恨搓。不可變對象天生是線程安全的院促。它們的常量(域)是在構(gòu)造函數(shù)中創(chuàng)建的。既然它們的狀態(tài)無法修改斧抱,這些常量永遠(yuǎn)不會變一疯。不可變對象永遠(yuǎn)是線程安全的。只有滿足如下狀態(tài)夺姑,一個對象才是不可變的墩邀;它的狀態(tài)不能在創(chuàng)建后再被修改;所有域都是final 類型盏浙;并且眉睹,它被正確創(chuàng)建。

問:notify()和notifyAll()有什么區(qū)別废膘?

答:當(dāng)一個線程進(jìn)入wait之后竹海,就必須等其他線程notify/notifyall,使用notifyall,可以喚醒所有處于wait 狀態(tài)的線程,使其重新進(jìn)入鎖的爭奪隊列中丐黄,而notify只能喚醒一個斋配。如果沒把握,建議notifyAll灌闺,防止notigy 因為信號丟失而造成程序異常艰争。

問:什么是可重入鎖(ReentrantLock)?談?wù)勊膶崿F(xiàn)桂对。

答:線程可以重復(fù)進(jìn)入任何一個它已經(jīng)擁有的鎖所同步著的代碼塊甩卓,synchronized、ReentrantLock 都是可重入的鎖蕉斜。在實現(xiàn)上逾柿,就是線程每次獲取鎖時判定如果獲得鎖的線程是它自己時缀棍,簡單將計數(shù)器累積即可,每釋放一次鎖机错,進(jìn)行計數(shù)器累減爬范,直到計算器歸零,表示線程已經(jīng)徹底釋放鎖弱匪。

問:當(dāng)一個線程進(jìn)入某個對象的一個synchronized的實例方法后坦敌,其它線程是否可進(jìn)入此對象的其它方法?

答:如果其他方法沒有synchronized的話痢法,其他線程是可以進(jìn)入的。所以要開放一個線程安全的對象時杜顺,得保證每個方法都是線程安全的财搁。

問:樂觀鎖和悲觀鎖的理解及如何實現(xiàn),有哪些實現(xiàn)方式躬络?

答:悲觀鎖:總是假設(shè)最壞的情況尖奔,每次去拿數(shù)據(jù)的時候都認(rèn)為別人會修改,所以每次在拿數(shù)據(jù)的時候都會上鎖穷当,這樣別人想拿這個數(shù)據(jù)就會阻塞直到它拿到鎖提茁。Java里面的同步原語synchronized 關(guān)鍵字的實現(xiàn)是悲觀鎖。樂觀鎖:顧名思義馁菜,就是很樂觀茴扁,每次去拿數(shù)據(jù)的時候都認(rèn)為別人不會修改,所以不會上鎖汪疮,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數(shù)據(jù)峭火,可以使用版本號等機(jī)制。在Java 中j 原子變量類就是使用了樂觀鎖的一種實現(xiàn)方式CAS 實現(xiàn)的智嚷。樂觀鎖的實現(xiàn)方式:(1)使用版本標(biāo)識來確定讀到的數(shù)據(jù)與提交時的數(shù)據(jù)是否一致卖丸。提交后修改版本標(biāo)識,不一致時可以采取丟棄和再次嘗試的策略盏道。(2)java 中的Compare and Swap 即CAS 稍浆,當(dāng)多個線程嘗試使用CAS同時更新同一個變量時,只有其中一個線程能更新變量的值猜嘱,而其它線程都失敗衅枫,失敗的線程并不會被掛起,而是被告知這次競爭中失敗朗伶,并可以再次嘗試为鳄。

問:什么是CAS操作,缺點是什么腕让?

答:CAS的基本思路就是孤钦,如果這個地址上的值和期望的值相等歧斟,則給其賦予新值,否則不做任何事兒偏形,但是要返回原值是多少静袖。每一個CAS 操作過程都包含三個運算符:一個內(nèi)存地址V,一個期望的值A(chǔ) 和一個新值B俊扭,操作的時候如果這個地址上存放的值等于這個期望的值A(chǔ)队橙,則將地址上的值賦為新值B,否則不做任何操作萨惑。CAS 缺點:ABA 問題:比如說一個線程one 從內(nèi)存位置V 中取出A捐康,這時候另一個線程two 也從內(nèi)存中取出A,并且two 進(jìn)行了一些操作變成了B庸蔼,然后two 又將V 位置的數(shù)據(jù)變成A解总,這時候線程one 進(jìn)行CAS 操作發(fā)現(xiàn)內(nèi)存中仍然是A,然后one 操作成功姐仅。盡管線程one 的CAS 操作成功花枫,但可能存在潛藏的問題。從Java1.5 開始JDK 的atomic 包里提供了一個類AtomicStampedReference 來解決ABA 問題掏膏。循環(huán)時間長開銷大:對于資源競爭嚴(yán)重(線程沖突嚴(yán)重)的情況劳翰,CAS 自旋的概率會比較大,從而浪費更多的CPU 資源馒疹,效率低于synchronized佳簸。只能保證一個共享變量的原子操作:當(dāng)對一個共享變量執(zhí)行操作時,我們可以使用循環(huán)CAS 的方式來保證原子操作颖变,但是對多個共享變量操作時溺蕉,循環(huán)CAS 就無法保證操作的原子性,這個時候就可以用鎖悼做。

問:SynchronizedMap和ConcurrentHashMap 有什么區(qū)別疯特?

答:SynchronizedMap一次鎖住整張表來保證線程安全,所以每次只能有一個線程來訪為map肛走。ConcurrentHashMap 使用分段鎖來保證在多線程下的性能漓雅。

問:寫時復(fù)制容器可以用于什么應(yīng)用場景?

答:CopyOnWrite并發(fā)容器用于對于絕大部分訪問都是讀朽色,且只是偶爾寫的并發(fā)場景邻吞。比如白名單,黑名單葫男,商品類目的訪問和更新場景抱冷。透露的思想讀寫分離,讀和寫分開最終一致性使用另外開辟空間的思路梢褐,來解決并發(fā)沖突旺遮。

問:volatile有什么用赵讯?能否用一句話說明下volatile 的應(yīng)用場景?

答:volatile保證內(nèi)存可見性和禁止指令重排耿眉。volatile 用于多線程環(huán)境下的一寫多讀边翼,或者無關(guān)聯(lián)的多寫。

問:為什么代碼會重排序鸣剪?

答:在執(zhí)行程序時组底,為了提供性能,處理器和編譯器常常會對指令進(jìn)行重排序筐骇,但是不能隨意重排序债鸡,不是你想怎么排序就怎么排序,它需要滿足以下兩個條件:在單線程環(huán)境下不能改變程序運行的結(jié)果铛纬;存在數(shù)據(jù)依賴關(guān)系的不允許重排序厌均。

問:在java中wait 和sleep 方法的不同?

答:最大的不同是在等待時wait會釋放鎖饺鹃,而sleep 一直持有鎖。Wait 通常被用于線程間交互间雀,sleep 通常被用于暫停執(zhí)行悔详。

問:一個線程運行時發(fā)生異常會怎樣?

答:如果異常沒有被捕獲該線程將會停止執(zhí)行惹挟。hread.UncaughtExceptionHandler是用于處理未捕獲異常造成線程突然中斷情況的一個內(nèi)嵌接口茄螃。當(dāng)一個未捕獲異常將造成線程中斷的時候JVM 會使用Thread.getUncaughtExceptionHandler()來查詢線程的UncaughtExceptionHandler 并將線程和異常作為參數(shù)傳遞給handler 的uncaughtException()方法進(jìn)行處理。

問:為什么wait, notify和notifyAll 這些方法不在thread 類里面连锯?

答:JAVA提供的鎖是對象級的而不是線程級的归苍,每個對象都有鎖,通過線程獲得运怖。如果線程需要等待某些鎖那么調(diào)用對象中的wait()方法就有意義了拼弃。如果wait()方法定義在Thread 類中,線程正在等待的是哪個鎖就不明顯了摇展。簡單的說吻氧,由于wait,notify 和notifyAll 都是鎖級別的操作咏连,所以把他們定義在Object 類中因為鎖屬于對象盯孙。

問:什么是ThreadLocal變量?

答:ThreadLocal是Java 里一種特殊的變量祟滴。每個線程都有一個ThreadLocal 就是每個線程都擁有了自己獨立的一個變量振惰,競爭條件被徹底消除了。

問:Java中interrupted 和isInterrupted 方法的區(qū)別垄懂?

答:interrupted()和isInterrupted()的主要區(qū)別是前者會將中斷狀態(tài)清除而后者不會骑晶。Java 多線程的中斷機(jī)制是用內(nèi)部標(biāo)識來實現(xiàn)的痛垛,調(diào)用Thread.interrupt()來中斷一個線程就會設(shè)置中斷標(biāo)識為true。當(dāng)中斷線程調(diào)用靜態(tài)方法Thread.interrupted()來檢查中斷狀態(tài)時透罢,中斷狀態(tài)會被清零榜晦。而非靜態(tài)方法isInterrupted()用來查詢其它線程的中斷狀態(tài)且不會改變中斷狀態(tài)標(biāo)識。

問:為什么wait和notify 方法要在同步塊中調(diào)用羽圃?

答:主要是因為Java API強(qiáng)制要求這樣做乾胶,如果你不這么做,你的代碼會拋出IllegalMonitorStateException 異常朽寞。

問:為什么你應(yīng)該在循環(huán)中檢查等待條件?

答:處于等待狀態(tài)的線程可能會收到錯誤警報和偽喚醒识窿,如果不在循環(huán)中檢查等待條件,程序就會在沒有滿足結(jié)束條件的情況下退出脑融。因此喻频,當(dāng)一個等待線程醒來時,不能認(rèn)為它原來的等待狀態(tài)仍然是有效的肘迎,在notify()方法調(diào)用之后和等待線程醒來之前這段時間它可能會改變甥温。這就是在循環(huán)中使用wait()方法效果更好的原因

問:怎么檢測一個線程是否擁有鎖?

答:在java.lang.Thread中有一個方法叫holdsLock()妓布,它返回true 如果當(dāng)且僅當(dāng)當(dāng)前線程擁有某個具體對象的鎖姻蚓。

問:你如何在Java中獲取線程堆棧?

答:kill -3 [java pid]不會在當(dāng)前終端輸出匣沼,它會輸出到代碼執(zhí)行的或指定的地方去狰挡。比如,kill -3 tomcat pid, 輸出堆棧到log 目錄下释涛。Jstack [java pid]這個比較簡單加叁,在當(dāng)前終端顯示,也可以重定向到指定文件中唇撬∷埃或者使用Java 提供的擬機(jī)線程系統(tǒng)的管理接口ManagementFactory.getThreadMXBean()。

問:Java線程池中submit() 和execute()方法有什么區(qū)別窖认?

答:兩個方法都可以向線程池提交任務(wù)超凳,execute()方法的返回類型是void,它定義在Executor 接口中耀态。而submit()方法可以返回持有計算結(jié)果的Future 對象轮傍,它定義在ExecutorService 接口中,它擴(kuò)展了Executor 接口

問:你對線程優(yōu)先級的理解是什么首装?

答:每一個線程都是有優(yōu)先級的创夜,一般來說,高優(yōu)先級的線程在運行時會具有優(yōu)先權(quán)仙逻,但這依賴于線程調(diào)度的實現(xiàn)驰吓,這個實現(xiàn)是和操作系統(tǒng)相關(guān)的(OS dependent)涧尿。我們可以定義線程的優(yōu)先級,但是這并不能保證高優(yōu)先級的線程會在低優(yōu)先級的線程前執(zhí)行檬贰。線程優(yōu)先級是一個int 變量(從1-10)姑廉,1 代表最低優(yōu)先級,10 代表最高優(yōu)先級翁涤。java 的線程優(yōu)先級調(diào)度會委托給操作系統(tǒng)去處理桥言,所以與具體的操作系統(tǒng)優(yōu)先級有關(guān),如非特別需要葵礼,一般無需設(shè)置線程優(yōu)先級号阿。

問:你如何確保main()方法所在的線程是Java 程序最后結(jié)束的線程?

答:可以使用Thread類的join()方法(或者CountDownLatch 工具類)來確保所有程序創(chuàng)建的線程在main()方法退出前結(jié)束鸳粉。

問:為什么Thread類的sleep()和yield ()方法是靜態(tài)的扔涧?

答:Thread類的sleep()和yield()方法將在當(dāng)前正在執(zhí)行的線程上運行。所以在其他處于等待狀態(tài)的線程上調(diào)用這些方法是沒有意義的届谈。這就是為什么這些方法是靜態(tài)的枯夜。它們可以在當(dāng)前正在執(zhí)行的線程中工作,并避免程序員錯誤的認(rèn)為可以在其他非運行線程調(diào)用這些方法艰山。

問:現(xiàn)在有T1湖雹、T2、T3 三個線程程剥,你怎樣保證T2 在T1 執(zhí)行完后執(zhí)行劝枣,T3 在T2 執(zhí)行完后執(zhí)行汤踏?

答:可以用join方法實現(xiàn)织鲸。

問:你需要實現(xiàn)一個高效的緩存,它允許多個用戶讀溪胶,但只允許一個用戶寫搂擦,以此來保持它的完整性,你會怎樣去實現(xiàn)它哗脖?

答:volatile關(guān)鍵字瀑踢,讀寫鎖,寫時復(fù)制等等都可以實現(xiàn)才避。

問:用Java實現(xiàn)阻塞隊列

答:見作業(yè)答案:包cn.enjoyedu.ch5.answer下

問:用Java寫代碼來解決生產(chǎn)者——消費者問題橱夭。

答:阻塞隊列實現(xiàn)即可,也可以用wait和notify 來解決這個問題桑逝,或者用Semaphore

問:用Java編程一個會導(dǎo)致死鎖的程序棘劣,你將怎么解決?

答:參見代碼cn.enjoyedu.ch7. NormalDeadLock楞遏,如何解決死鎖茬暇,參見筆記首昔。

問:Java中如何停止一個線程?

答:使用共享變量的方式糙俗。在這種方式中勒奇,之所以引入共享變量,是因為該變量可以被多個執(zhí)行相同任務(wù)的線程用來作為是否中斷的信號巧骚,通知中斷線程的執(zhí)行赊颠。使用interrupt方法終止線程如果一個線程由于等待某些事件的發(fā)生而被阻塞,又該怎樣停止該線程呢网缝?比如當(dāng)一個線程由于需要等候鍵盤輸入而被阻塞巨税,或者調(diào)用Thread.join()方法,或者Thread.sleep()方法粉臊,在網(wǎng)絡(luò)中調(diào)用ServerSocket.accept()方法草添,或者調(diào)用了DatagramSocket.receive()方法時,都有可能導(dǎo)致線程阻塞扼仲,使線程處于處于不可運行狀態(tài)時远寸,即使主程序中將該線程的共享變量設(shè)置為true,但該線程此時根本無法檢查循環(huán)標(biāo)志屠凶,當(dāng)然也就無法立即中斷驰后。所以應(yīng)該盡量使用Thread 提供的interrupt()方法,因為該方法雖然不會中斷一個正在運行的線程矗愧,但是它可以使一個被阻塞的線程拋出一個中斷異常灶芝,從而使線程提前結(jié)束阻塞狀態(tài)。

問:JVM中哪個參數(shù)是用來控制線程的棧堆棧大小的

答:-Xss

問:如果同步塊內(nèi)的線程拋出異常鎖會釋放嗎唉韭?

答:會

問:單例模式的雙重檢查實現(xiàn)是什么夜涕?為什么并不安全?如何在Java中創(chuàng)建線程安全的Singleton属愤?

答:實現(xiàn)參見cn.enjoyedu.ch7.dcl. SingleDcl女器,不安全的根本原因是重排序會導(dǎo)致未初始化完成的對象可以被其他線程看見而導(dǎo)致錯誤。創(chuàng)建安全的單例模式有:延遲占位模式住诸、在聲明的時候就new 這個類的實例驾胆、枚舉

問:寫出3條你遵循的多線程最佳實踐

答:給你的線程起個有意義的名字。這樣可以方便找bug或追蹤贱呐。OrderProcessor, QuoteProcessor or TradeProcessor 這種名字比Thread-1.Thread-2 and Thread-3 好多了丧诺,給線程起一個和它要完成的任務(wù)相關(guān)的名字,所有的主要框架甚至JDK 都遵循這個最佳實踐奄薇。避免鎖定和縮小同步的范圍鎖花費的代價高昂且上下文切換更耗費時間空間驳阎,試試最低限度的使用同步和鎖,縮小臨界區(qū)。因此相對于同步方法我更喜歡同步塊搞隐,它給我擁有對鎖的絕對控制權(quán)驹愚。多用同步類少用wait 和notify 首先,CountDownLatch, Semaphore,CyclicBarrier 和Exchanger 這些同步類簡化了編碼操作劣纲,而用wait 和notify 很難實現(xiàn)對復(fù)雜控制流的控制逢捺。其次,這些類是由最好的企業(yè)編寫和維護(hù)在后續(xù)的JDK中它們還會不斷優(yōu)化和完善癞季,使用這些更高等級的同步工具你的程序可以不費吹灰之力獲得優(yōu)化劫瞳。多用并發(fā)集合少用同步集合這是另外一個容易遵循且受益巨大的最佳實踐,并發(fā)集合比同步集合的可擴(kuò)展性更好绷柒,所以在并發(fā)編程時使用并發(fā)集合效果更好志于。比如并發(fā)編程的黃金原則,盡量無鎖化編程等等…….

問:請概述線程池的創(chuàng)建參數(shù)废睦,怎么樣合理配置一個線程池的參數(shù)伺绽?

答:參見筆記中線程池一章的內(nèi)容

問:請概述鎖的公平和非公平,JDK內(nèi)部是如何實現(xiàn)的嗜湃。

答:公平鎖是指所有試圖獲得鎖的線程按照獲取鎖的順序依次獲得鎖奈应,而非公平鎖則是當(dāng)前的鎖狀態(tài)沒有被占用時,當(dāng)前線程可以直接占用,而不需要等待。在實現(xiàn)上购披,非公平鎖邏輯基本跟公平鎖一致杖挣,唯一的區(qū)別是,當(dāng)前線程不需要判斷同步隊列中是否有等待線程刚陡。非公平鎖性能高于公平鎖性能惩妇。首先,在恢復(fù)一個被掛起的線程與該線程真正運行之間存在著嚴(yán)重的延遲筐乳。而且歌殃,非公平鎖能更充分的利用cpu 的時間片,盡量的減少cpu 空閑的狀態(tài)時間哥童。使用場景的話呢挺份,其實還是和他們的屬性一一相關(guān)褒翰,比如:如果業(yè)務(wù)中線程占用(處理)時間要遠(yuǎn)長于線程等待贮懈,那用非公平鎖其實效率并不明顯,但是用公平鎖可以保證不會有線程被餓死优训。

問:請概述AQS

答:是用來構(gòu)建鎖或者其他同步組件的基礎(chǔ)框架朵你,比如ReentrantLock、ReentrantReadWriteLock 和CountDownLatch 就是基于AQS 實現(xiàn)的揣非。它使用了一個int 成員變量表示同步狀態(tài)抡医,通過內(nèi)置的FIFO 隊列來完成資源獲取線程的排隊工作。它是CLH 隊列鎖的一種變體實現(xiàn)。它可以實現(xiàn)2 種同步方式:獨占式忌傻,共享式大脉。AQS 的主要使用方式是繼承,子類通過繼承AQS 并實現(xiàn)它的抽象方法來管理同步狀態(tài)水孩,同步器的設(shè)計基于模板方法模式镰矿,所以如果要實現(xiàn)我們自己的同步工具類就需要覆蓋其中幾個可重寫的方法,如tryAcquire俘种、tryReleaseShared 等等秤标。這樣設(shè)計的目的是同步組件(比如鎖)是面向使用者的,它定義了使用者與同步組件交互的接口(比如可以允許兩個線程并行訪問)宙刘,隱藏了實現(xiàn)細(xì)節(jié)苍姜;同步器面向的是鎖的實現(xiàn)者,它簡化了鎖的實現(xiàn)方式悬包,屏蔽了同步狀態(tài)管理衙猪、線程的排隊、等待與喚醒等底層操作布近。這樣就很好地隔離了使用者和實現(xiàn)者所需關(guān)注的領(lǐng)域屈嗤。在內(nèi)部,AQS 維護(hù)一個共享資源state吊输,通過內(nèi)置的FIFO 來完成獲取資源線程的排隊工作饶号。該隊列由一個一個的Node 結(jié)點組成,每個Node 結(jié)點維護(hù)一個prev 引用和next 引用季蚂,分別指向自己的前驅(qū)和后繼結(jié)點茫船,構(gòu)成一個雙端雙向鏈表。同時與Condition 相關(guān)的等待隊列扭屁,節(jié)點類型也是Node算谈,構(gòu)成一個單向鏈表。

問:請概述volatile

答:volatile關(guān)鍵字的作用主要有兩點:多線程主要圍繞可見性和原子性兩個特性而展開料滥,使用volatile 關(guān)鍵字修飾的變量然眼,保證了其在多線程之間的可見性,即每次讀取到volatile 變量葵腹,一定是最新的數(shù)據(jù)高每。但是volatile 不能保證操作的原子,對任意單個volatile 變量的讀/

寫具有原子性践宴,但類似于++這種復(fù)合操作不具有原子性鲸匿。。代碼底層在執(zhí)行時為了獲取更好的性能會對指令進(jìn)行重排序阻肩,多線程下可能會出現(xiàn)一些意想不到的問題带欢。使用volatile 則會對禁止重排序,當(dāng)然這也一定程度上降低了代碼執(zhí)行效率。同時在內(nèi)存語義上乔煞,當(dāng)寫一個volatile 變量時吁朦,JMM 會把該線程對應(yīng)的本地內(nèi)存中的共享變量值刷新到主內(nèi)存,當(dāng)讀一個volatile 變量時渡贾,JMM 會把該線程對應(yīng)的本地內(nèi)存置為無效喇完。線程接下來將從主內(nèi)存中讀取共享變量。在Java 中對于volatile 修飾的變量剥啤,編譯器在生成字節(jié)碼時锦溪,會在指令序列中插入內(nèi)存屏障來禁止特定類型的處理器重排序問題、強(qiáng)制刷新和讀取府怯。在具體實現(xiàn)上刻诊,volatile 關(guān)鍵字修飾的變量會存在一個“l(fā)ock:”的前綴。它不是一種內(nèi)存屏障牺丙,但是它能完成類似內(nèi)存屏障的功能则涯。Lock 會對CPU 總線和高速緩存加鎖,可以理解為CPU 指令級的一種鎖冲簿。同時該指令會將當(dāng)前處理器緩存行的數(shù)據(jù)直接寫會到系統(tǒng)內(nèi)存中粟判,且這個寫回內(nèi)存的操作會使在其他CPU 里緩存了該地址的數(shù)據(jù)無效。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末峦剔,一起剝皮案震驚了整個濱河市档礁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌吝沫,老刑警劉巖呻澜,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異惨险,居然都是意外死亡羹幸,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進(jìn)店門辫愉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來栅受,“玉大人,你說我怎么就攤上這事恭朗∑聊鳎” “怎么了?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵冀墨,是天一觀的道長闸衫。 經(jīng)常有香客問我涛贯,道長诽嘉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮虫腋,結(jié)果婚禮上骄酗,老公的妹妹穿的比我還像新娘。我一直安慰自己悦冀,他們只是感情好趋翻,可當(dāng)我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著盒蟆,像睡著了一般踏烙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上历等,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天讨惩,我揣著相機(jī)與錄音,去河邊找鬼寒屯。 笑死荐捻,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的寡夹。 我是一名探鬼主播处面,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼菩掏!你這毒婦竟也來了魂角?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤智绸,失蹤者是張志新(化名)和其女友劉穎或颊,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體传于,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡囱挑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了沼溜。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片平挑。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖系草,靈堂內(nèi)的尸體忽然破棺而出通熄,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布明刷,位于F島的核電站驯妄,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏赏枚。R本人自食惡果不足惜亡驰,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望饿幅。 院中可真熱鬧凡辱,春花似錦、人聲如沸栗恩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽磕秤。三九已至乳乌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間市咆,已是汗流浹背钦扭。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留床绪,地道東北人客情。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像癞己,于是被迫代替她去往敵國和親膀斋。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,933評論 2 355