1蠢络、在 java 中守護(hù)線程和本地線程區(qū)別社裆?
1弹砚、java 中的線程分為兩種:守護(hù)線程(Daemon)和用戶線程(User)双仍。
2、任何線程都可以設(shè)置為守護(hù)線程和用戶線程桌吃,通過方法 Thread.setDaemon(boolon)朱沃;
3、true 則把該線程設(shè)置為守護(hù)線程茅诱,反之則為用戶線程逗物。
4、Thread.setDaemon()必須在 Thread.start()之前調(diào)用瑟俭,否則運(yùn)行時(shí)會(huì)拋出異常
2翎卓、線程與進(jìn)程的區(qū)別?
1摆寄、進(jìn)程是操作系統(tǒng)分配資源的最小單元失暴,線程是操作系統(tǒng)調(diào)度的最小單元。
2微饥、一個(gè)程序至少有一個(gè)進(jìn)程,一個(gè)進(jìn)程至少有一個(gè)線程逗扒。
3、什么是多線程中的上下文切換欠橘?
1缴阎、多線程會(huì)共同使用一組計(jì)算機(jī)上的 CPU,而線程數(shù)大于給程序分配的 CPU 數(shù)量時(shí)简软,
2蛮拔、為了讓各個(gè)線程都有執(zhí)行的機(jī)會(huì),就需要輪轉(zhuǎn)使用 CPU痹升。
3建炫、不同的線程切換使用 CPU 發(fā)生的切換數(shù)據(jù)等就是上下文切換。
4疼蛾、死鎖與活鎖的區(qū)別肛跌,死鎖與饑餓的區(qū)別?
4.1察郁、死鎖:
是指兩個(gè)或兩個(gè)以上的進(jìn)程(或線程)在執(zhí)行過程中衍慎,因爭奪資源而造成
的一種互相等待的現(xiàn)象,若無外力作用皮钠,它們都將無法推進(jìn)下去稳捆。
產(chǎn)生死鎖的必要條件:
1、互斥條件:所謂互斥就是進(jìn)程在某一時(shí)間內(nèi)獨(dú)占資源麦轰。
2乔夯、請(qǐng)求與保持條件:一個(gè)進(jìn)程因請(qǐng)求資源而阻塞時(shí)砖织,對(duì)已獲得的資源保持不放。
3末荐、不剝奪條件:進(jìn)程已獲得資源侧纯,在末使用完之前,不能強(qiáng)行剝奪甲脏。
4眶熬、循環(huán)等待條件:若干進(jìn)程之間形成一種頭尾相接的循環(huán)等待資源關(guān)系。
4.2块请、活鎖:
任務(wù)或者執(zhí)行者沒有被阻塞聋涨,由于某些條件沒有滿足,導(dǎo)致一直重復(fù)嘗試负乡,
失敗牍白,嘗試,失敗抖棘。
4.3茂腥、活鎖和死鎖的區(qū)別:
處于活鎖的實(shí)體是在不斷的改變狀態(tài),所謂的“活”切省,
而處于死鎖的實(shí)體表現(xiàn)為等待最岗;活鎖有可能自行解開,死鎖則不能朝捆。
4.4般渡、饑餓:
一個(gè)或者多個(gè)線程因?yàn)榉N種原因無法獲得所需要的資源,導(dǎo)致一直無法執(zhí)
行的狀態(tài)芙盘。
Java 中導(dǎo)致饑餓的原因:
1驯用、高優(yōu)先級(jí)線程吞噬所有的低優(yōu)先級(jí)線程的 CPU 時(shí)間。
2儒老、線程被永久堵塞在一個(gè)等待進(jìn)入同步塊的狀態(tài)蝴乔,因?yàn)槠渌€程總是能在它之前
持續(xù)地對(duì)該同步塊進(jìn)行訪問。
3驮樊、線程在等待一個(gè)本身也處于永久等待完成的對(duì)象(比如調(diào)用這個(gè)對(duì)象的 wait 方 法)薇正,因?yàn)槠渌€程總是被持續(xù)地獲得喚醒。
5囚衔、Java 中用到的線程調(diào)度算法是什么挖腰?
1、采用時(shí)間片輪轉(zhuǎn)的方式练湿『锫兀可以設(shè)置線程的優(yōu)先級(jí),
2鞠鲜、會(huì)映射到下層的系統(tǒng)上面的優(yōu)先級(jí)上宁脊,
3断国、如非特別需要贤姆,盡量不要用榆苞,防止線程饑餓。
6霞捡、什么是線程組坐漏,為什么在 Java 中不推薦使用?
1碧信、ThreadGroup 類赊琳,可以把線程歸屬到某一個(gè)線程組中,線程組中可以有線程對(duì)象砰碴,
也可以有線程組躏筏,組中還可以有線程,這樣的組織結(jié)構(gòu)有點(diǎn)類似于樹的形式呈枉。
2趁尼、為什么不推薦使用?因?yàn)槭褂糜泻芏嗟陌踩[患吧猖辫,沒有具體追究酥泞,如果需要使
用,推薦使用線程池啃憎。
7芝囤、為什么使用 Executor 框架?
1辛萍、每次執(zhí)行任務(wù)創(chuàng)建線程 new Thread()比較消耗性能悯姊,創(chuàng)建一個(gè)線程是比較耗時(shí)、耗資源的贩毕。
2挠轴、調(diào)用 new Thread()創(chuàng)建的線程缺乏管理,被稱為野線程耳幢,而且可以無限制的創(chuàng)建岸晦,線程之間的相互競爭會(huì)導(dǎo)致過多占用系統(tǒng)資源而導(dǎo)致系統(tǒng)癱瘓,還有線程之間的頻繁交替也會(huì)消耗很多系統(tǒng)資源睛藻。
3启上、接使用 new Thread() 啟動(dòng)的線程不利于擴(kuò)展,比如定時(shí)執(zhí)行店印、定期執(zhí)行冈在、定時(shí)定期執(zhí)行、線程中斷等都不便實(shí)現(xiàn)按摘。
8包券、在 Java 中 Executor 和 Executors 的區(qū)別纫谅?
1、Executors 工具類的不同方法按照我們的需求創(chuàng)建了不同的線程池溅固,來滿足業(yè)務(wù)的需求付秕。
2、Executor 接口對(duì)象能執(zhí)行我們的線程任務(wù)侍郭。
3询吴、ExecutorService 接口繼承了 Executor 接口并進(jìn)行了擴(kuò)展,提供了更多的方法我們能獲得任務(wù)執(zhí)行的狀態(tài)并且可以獲取任務(wù)的返回值亮元。
4猛计、使用 ThreadPoolExecutor 可以創(chuàng)建自定義線程池
9、如何在 Windows 和 Linux 上查找哪個(gè)線程使用的 CPU 時(shí)間最長爆捞?
1奉瘤、windows上面用任務(wù)管理器看
2、linux下可以用top 這個(gè)工具看煮甥。當(dāng)然如果你要查找具體的進(jìn)程盗温,可以用ps命令,比如查找java:
ps -ef |grep java
10、什么是原子操作苛秕?在 Java Concurrency API 中有哪些原子類(atomic classes)肌访?
1、原子操作(atomic operation)意為”不可被中斷的一個(gè)或一系列操作” 艇劫。
處理器使用基于對(duì)緩存加鎖或總線加鎖的方式來實(shí)現(xiàn)多處理器之間的原子操作吼驶。
在 Java 中可以通過鎖和循環(huán) CAS 的方式來實(shí)現(xiàn)原子操作。
CAS 操作——Compare & Set店煞,或是 Compare & Swap蟹演,現(xiàn)在幾乎所有的 CPU 指令都支持 CAS
的原子操作。
2顷蟀、原子操作是指一個(gè)不受其他操作影響的操作任務(wù)單元酒请。原子操作是在多線程環(huán)境下避免數(shù)據(jù)不一致必須的手段。
3鸣个、int++并不是一個(gè)原子操作羞反,所以當(dāng)一個(gè)線程讀取它的值并加 1 時(shí),另外一個(gè)線程有可能會(huì)讀到之前的值囤萤,這就會(huì)引發(fā)錯(cuò)誤昼窗。
為了解決這個(gè)問題,必須保證增加操作是原子的涛舍,在 JDK1.5 之前我們可以使用同步技術(shù)來做到這一點(diǎn)澄惊。到JDK1.5,java.util.concurrent.atomic 包提供了 int 和long 類型的原子包裝類,它們可以自動(dòng)的保證對(duì)于他們的操作是原子的并且不需要使用同步掸驱。
4肛搬、java.util.concurrent 這個(gè)包里面提供了一組原子類。其基本的特性就是在多線程環(huán)境下毕贼,當(dāng)有多個(gè)線程同時(shí)執(zhí)行這些類的實(shí)例包含的方法時(shí)温赔,具有排他性,即當(dāng)某個(gè)線程進(jìn)入方法帅刀,執(zhí)行其中的指令時(shí)让腹,不會(huì)被其他線程打斷远剩,而別的線程就像自旋鎖一樣扣溺,一直等到該方法執(zhí)行完成,才由 JVM 從等待隊(duì)列中選擇另一個(gè)線程進(jìn)入瓜晤,這只是一種邏輯上的理解锥余。
5、原子類:AtomicBoolean痢掠,AtomicInteger驱犹,AtomicLong,AtomicReference
原子數(shù)組:AtomicIntegerArray足画,AtomicLongArray雄驹,AtomicReferenceArray
原子屬性更新器:AtomicLongFieldUpdater,AtomicIntegerFieldUpdater淹辞,AtomicReferenceFieldUpdater
解決 ABA 問題的原子類:AtomicMarkableReference(通過引入一個(gè) boolean來反映中間有沒有變過)医舆,AtomicStampedReference(通過引入一個(gè) int 來累加來反映中間有沒有變過)
11、Java Concurrency API 中的 Lock 接口(Lock interface)是什么象缀?對(duì)比同步它有什么優(yōu)勢蔬将?
Lock 接口比同步方法和同步塊提供了更具擴(kuò)展性的鎖操作。
他們?cè)试S更靈活的結(jié)構(gòu)央星,可以具有完全不同的性質(zhì)霞怀,并且可以支持多個(gè)相關(guān)類的條件對(duì)象。
它的優(yōu)勢有:
1莉给、可以使鎖更公平
2毙石、可以使線程在等待鎖的時(shí)候響應(yīng)中斷
3、可以讓線程嘗試獲取鎖颓遏,并在無法獲取鎖的時(shí)候立即返回或者等待一段時(shí)間
4徐矩、可以在不同的范圍,以不同的順序獲取和釋放鎖
小結(jié):
整體上來說 Lock 是 synchronized 的擴(kuò)展版州泊,Lock 提供了無條件的丧蘸、可輪詢的(tryLock 方法)、定時(shí)的(tryLock 帶參方法)、可中斷的(lockInterruptibly)力喷、可多條件隊(duì)列的(newCondition 方法)鎖操作刽漂。另外 Lock 的實(shí)現(xiàn)類基本都支持非公平鎖(默認(rèn))和公平鎖,synchronized 只支持非公平鎖弟孟,當(dāng)然贝咙,在大部分情況下,非
公平鎖是高效的選擇拂募。
12庭猩、什么是 Executors 框架?
1陈症、Executor 框架是一個(gè)根據(jù)一組執(zhí)行策略調(diào)用蔼水,調(diào)度,執(zhí)行和控制的異步任務(wù)的框
架录肯。
2趴腋、無限制的創(chuàng)建線程會(huì)引起應(yīng)用程序內(nèi)存溢出。所以創(chuàng)建一個(gè)線程池是個(gè)更好的的解決方案论咏,因?yàn)榭梢韵拗凭€程的數(shù)量并且可以回收再利用這些線程优炬。利用Executors 框架可以非常方便的創(chuàng)建一個(gè)線程池。
13厅贪、什么是阻塞隊(duì)列蠢护?阻塞隊(duì)列的實(shí)現(xiàn)原理是什么?如何使用阻塞隊(duì)列來實(shí)現(xiàn)生產(chǎn)者-消費(fèi)者模型养涮?
1葵硕、阻塞隊(duì)列(BlockingQueue)是一個(gè)支持兩個(gè)附加操作的隊(duì)列。
2单寂、這兩個(gè)附加的操作是:在隊(duì)列為空時(shí)贬芥,獲取元素的線程會(huì)等待隊(duì)列變?yōu)榉强铡.?dāng)隊(duì)列滿時(shí)宣决,存儲(chǔ)元素的線程會(huì)等待隊(duì)列可用蘸劈。
3、阻塞隊(duì)列常用于生產(chǎn)者和消費(fèi)者的場景尊沸,生產(chǎn)者是往隊(duì)列里添加元素的線程威沫,消費(fèi)者是從隊(duì)列里拿元素的線程。阻塞隊(duì)列就是生產(chǎn)者存放元素的容器洼专,而消費(fèi)者也只從容器里拿元素棒掠。
JDK7 提供了 7 個(gè)阻塞隊(duì)列。分別是:
ArrayBlockingQueue :一個(gè)由數(shù)組結(jié)構(gòu)組成的有界阻塞隊(duì)列屁商。
LinkedBlockingQueue :一個(gè)由鏈表結(jié)構(gòu)組成的有界阻塞隊(duì)列烟很。
PriorityBlockingQueue :一個(gè)支持優(yōu)先級(jí)排序的無界阻塞隊(duì)列。
DelayQueue:一個(gè)使用優(yōu)先級(jí)隊(duì)列實(shí)現(xiàn)的無界阻塞隊(duì)列。
SynchronousQueue:一個(gè)不存儲(chǔ)元素的阻塞隊(duì)列雾袱。
LinkedTransferQueue:一個(gè)由鏈表結(jié)構(gòu)組成的無界阻塞隊(duì)列恤筛。
LinkedBlockingDeque:一個(gè)由鏈表結(jié)構(gòu)組成的雙向阻塞隊(duì)列。
Java 5 之前實(shí)現(xiàn)同步存取時(shí)芹橡,可以使用普通的一個(gè)集合毒坛,然后在使用線程的協(xié)作和線程同步可以實(shí)現(xiàn)生產(chǎn)者,消費(fèi)者模式林说,主要的技術(shù)就是用好煎殷,wait ,notify,notifyAll,sychronized 這些關(guān)鍵字。而在 java 5 之后腿箩,可以使用阻塞隊(duì)列來實(shí)現(xiàn)豪直,此方式大大簡少了代碼量,使得多線程編程更加容易度秘,安全方面也有保障顶伞。
BlockingQueue 接口是 Queue 的子接口饵撑,它的主要用途并不是作為容器剑梳,而是作為線程同步的的工具,因此他具有一個(gè)很明顯的特性滑潘,當(dāng)生產(chǎn)者線程試圖向BlockingQueue 放入元素時(shí)垢乙,如果隊(duì)列已滿,則線程被阻塞语卤,當(dāng)消費(fèi)者線程試圖從中取出一個(gè)元素時(shí)追逮,如果隊(duì)列為空,則該線程會(huì)被阻塞粹舵,正是因?yàn)樗哂羞@個(gè)特性钮孵,所以在程序中多個(gè)線程交替向 BlockingQueue 中放入元素,取出元素眼滤,它可以很好的控制線程之間的通信巴席。
阻塞隊(duì)列使用最經(jīng)典的場景就是 socket 客戶端數(shù)據(jù)的讀取和解析,讀取數(shù)據(jù)的線程不斷將數(shù)據(jù)放入隊(duì)列诅需,然后解析線程不斷從隊(duì)列取數(shù)據(jù)解析漾唉。
14、什么是 Callable 和 Future?
1堰塌、Callable 接口類似于 Runnable赵刑,從名字就可以看出來了,但是 Runnable 不會(huì)返回結(jié)果场刑,并且無法拋出返回結(jié)果的異常般此,
2、而 Callable 功能更強(qiáng)大一些,被線程執(zhí)行后铐懊,可以返回值屎勘,這個(gè)返回值可以被 Future 拿到,也就是說居扒,F(xiàn)uture 可以拿到異步執(zhí)行任務(wù)的返回值概漱。可以認(rèn)為是帶有回調(diào)的 Runnable喜喂。
2瓤摧、Future 接口表示異步任務(wù),是還沒有完成的任務(wù)給出的未來結(jié)果玉吁。所以說 Callable用于產(chǎn)生結(jié)果照弥,F(xiàn)uture 用于獲取結(jié)果。
15进副、什么是 FutureTask?使用 ExecutorService 啟動(dòng)任務(wù)这揣。
1、在 Java 并發(fā)程序中 FutureTask 表示一個(gè)可以取消的異步運(yùn)算影斑。
2给赞、它有啟動(dòng)和取消運(yùn)算、查詢運(yùn)算是否完成和取回運(yùn)算結(jié)果等方法矫户。
3片迅、只有當(dāng)運(yùn)算完成的時(shí)候結(jié)果才能取回,如果運(yùn)算尚未完成 get 方法將會(huì)阻塞皆辽。
4柑蛇、一個(gè) FutureTask 對(duì)象可以對(duì)調(diào)用了 Callable 和 Runnable 的對(duì)象進(jìn)行包裝,由于 FutureTask 也是調(diào)用了 Runnable接口所以它可以提交給 Executor 來執(zhí)行驱闷。
16耻台、什么是并發(fā)容器的實(shí)現(xiàn)?
1空另、何為同步容器:可以簡單地理解為通過 synchronized 來實(shí)現(xiàn)同步的容器盆耽,如果有多個(gè)線程調(diào)用同步容器的方法,它們將會(huì)串行執(zhí)行痹换。比如 Vector征字,Hashtable丧慈,以及 Collections.synchronizedSet常拓,synchronizedList 等方法返回的容器。
2番宁、可以通過查看 Vector冯痢,Hashtable 等這些同步容器的實(shí)現(xiàn)代碼氮昧,可以看到這些容器實(shí)現(xiàn)線程安全的方式就是將它們的狀態(tài)封裝起來框杜,并在需要同步的方法上加上關(guān)鍵字 synchronized。
1袖肥、并發(fā)容器使用了與同步容器完全不同的加鎖策略來提供更高的并發(fā)性和伸縮性咪辱,例如在ConcurrentHashMap 中采用了一種粒度更細(xì)的加鎖機(jī)制,可以稱為分段鎖椎组。
2油狂、在這種鎖機(jī)制下,允許任意數(shù)量的讀線程并發(fā)地訪問 map寸癌,并且執(zhí)行讀操作的線程和寫操作的線程也可以并發(fā)的訪問 map专筷,同時(shí)允許一定數(shù)量的寫操作線程并發(fā)地修改 map,所以它可以在并發(fā)環(huán)境下實(shí)現(xiàn)更高的吞吐量蒸苇。
17磷蛹、多線程同步和互斥有幾種實(shí)現(xiàn)方法,都是什么溪烤?
1味咳、線程同步是指線程之間所具有的一種制約關(guān)系,一個(gè)線程的執(zhí)行依賴另一個(gè)線程的消息檬嘀,當(dāng)它沒有得到另一個(gè)線程的消息時(shí)應(yīng)等待槽驶,直到消息到達(dá)時(shí)才被喚醒。
2枪眉、線程互斥是指對(duì)于共享的進(jìn)程系統(tǒng)資源捺檬,在各單個(gè)線程訪問時(shí)的排它性。當(dāng)有若干個(gè)線程都要使用某一共享資源時(shí)贸铜,任何時(shí)刻最多只允許一個(gè)線程去使用,其它要使用該資源的線程必須等待聂受,直到占用資源者釋放該資源蒿秦。線程互斥可以看成是一種特殊的線程同步。
1蛋济、線程間的同步方法大體可分為兩類:用戶模式和內(nèi)核模式棍鳖。顧名思義,內(nèi)核模式就是指利用系統(tǒng)內(nèi)核對(duì)象的單一性來進(jìn)行同步碗旅,使用時(shí)需要切換內(nèi)核態(tài)與用戶態(tài)渡处,而用戶模式就是不需要切換到內(nèi)核態(tài),只在用戶態(tài)完成操作祟辟。
2医瘫、用戶模式下的方法有:原子操作(例如一個(gè)單一的全局變量),臨界區(qū)旧困。內(nèi)核模式下的方法有:事件醇份,信號(hào)量稼锅,互斥量。
18僚纷、什么是競爭條件矩距?
當(dāng)多個(gè)線程都企圖對(duì)共享數(shù)據(jù)進(jìn)行某種處理,而最后的結(jié)果又取決于線程運(yùn)行的順序時(shí)怖竭,則我們認(rèn)為這發(fā)生了競爭條件(race condition)锥债。
19、你將如何使用 thread dump痊臭?你將如何分析 Thread dump赞弥?
1、新建狀態(tài)(New):
用 new 語句創(chuàng)建的線程處于新建狀態(tài)趣兄,此時(shí)它和其他 Java 對(duì)象一樣绽左,僅僅在堆區(qū)中被分配了內(nèi)存。
2艇潭、就緒狀態(tài)(Runnable):
當(dāng)一個(gè)線程對(duì)象創(chuàng)建后拼窥,其他線程調(diào)用它的 start()方法,該線程就進(jìn)入就緒狀態(tài)蹋凝,Java 虛擬機(jī)會(huì)為它創(chuàng)建方法調(diào)用棧和程序計(jì)數(shù)器鲁纠。處于這個(gè)狀態(tài)的線程位于可運(yùn)行池中,等待獲得 CPU 的使用權(quán)鳍寂。
3改含、運(yùn)行狀態(tài)(Running):
處于這個(gè)狀態(tài)的線程占用 CPU,執(zhí)行程序代碼迄汛。只有處于就緒狀態(tài)的線程才有機(jī)會(huì)轉(zhuǎn)到運(yùn)行狀態(tài)捍壤。
4、阻塞狀態(tài)(Blocked):
阻塞狀態(tài)是指線程因?yàn)槟承┰蚍艞?CPU鞍爱,暫時(shí)停止運(yùn)行鹃觉。當(dāng)線程處于阻塞狀態(tài)時(shí),Java 虛擬機(jī)不會(huì)給線程分配 CPU睹逃。直到線程重新進(jìn)入就緒狀態(tài)盗扇,它才有機(jī)會(huì)轉(zhuǎn)到運(yùn)行狀態(tài)。
阻塞狀態(tài)可分為以下 3 種:
(1)位于對(duì)象等待池中的阻塞狀態(tài)(Blocked in object’s wait pool):
當(dāng)線程處于運(yùn)行狀態(tài)時(shí)沉填,如果執(zhí)行了某個(gè)對(duì)象的 wait()方法疗隶,Java 虛擬機(jī)就會(huì)把線程放到這個(gè)對(duì)象的等待池中,這涉及到“線程通信”的內(nèi)容翼闹。
(2)位于對(duì)象鎖池中的阻塞狀態(tài)(Blocked in object’s lock pool):
當(dāng)線程處于運(yùn)行狀態(tài)時(shí)斑鼻,試圖獲得某個(gè)對(duì)象的同步鎖時(shí),如果該對(duì)象的同步鎖已經(jīng)被其他線程占用橄碾,Java 虛擬機(jī)就會(huì)把這個(gè)線程放到這個(gè)對(duì)象的鎖池中卵沉,這涉及到“線程同步”的內(nèi)容颠锉。
(3)其他阻塞狀態(tài)(Otherwise Blocked):
當(dāng)前線程執(zhí)行了 sleep()方法,或者調(diào)用了其他線程的 join()方法史汗,或者發(fā)出了 I/O請(qǐng)求時(shí)琼掠,就會(huì)進(jìn)入這個(gè)狀態(tài)。
5停撞、死亡狀態(tài)(Dead)
當(dāng)線程退出 run()方法時(shí)瓷蛙,就進(jìn)入死亡狀態(tài),該線程結(jié)束生命周期戈毒。
我們運(yùn)行之前的那個(gè)死鎖代碼 SimpleDeadLock.java艰猬。
20、為什么我們調(diào)用 start()方法時(shí)會(huì)執(zhí)行 run()方法埋市,為什么我們不能直接調(diào)用 run()方法冠桃?
問題1:因?yàn)轭怲hread中的start方法中,調(diào)用了Thread中的run方法道宅。順便說下食听,類A繼承了Tread類,在A中寫run方法污茵,就會(huì)覆蓋掉Thread中的run方法樱报,所以此時(shí)調(diào)用start方法后,實(shí)現(xiàn)的是自己的run方法體里面的代碼泞当。
問題2:如果我們直接調(diào)用子線程的run()方法迹蛤,其方法還是運(yùn)行在主線程中,代碼在程序中是順序執(zhí)行的襟士,所以不會(huì)有解決耗時(shí)操作的問題盗飒。所以不能直接調(diào)用線程的run()方法,只有子線程開始了敌蜂,才會(huì)有異步的效果箩兽。當(dāng)thread.start()方法執(zhí)行了以后,子線程才會(huì)執(zhí)行run()方法章喉,這樣的效果和在主線程中直接調(diào)用run()方法的效果是截然不同的。
21身坐、Java 中你怎樣喚醒一個(gè)阻塞的線程秸脱?
1、在 Java 發(fā)展史上曾經(jīng)使用 suspend()部蛇、resume()方法對(duì)于線程進(jìn)行阻塞喚醒摊唇,但隨之出現(xiàn)很多問題,比較典型的還是死鎖問題涯鲁。
2巷查、解決方案可以使用以對(duì)象為目標(biāo)的阻塞有序,即利用 Object 類的 wait()和 notify()方法實(shí)現(xiàn)線程阻塞。
3岛请、首先旭寿,wait、notify 方法是針對(duì)對(duì)象的崇败,調(diào)用任意對(duì)象的 wait()方法都將導(dǎo)致線程阻塞盅称,阻塞的同時(shí)也將釋放該對(duì)象的鎖,相應(yīng)地后室,調(diào)用任意對(duì)象的 notify()方法則將隨機(jī)解除該對(duì)象阻塞的線程缩膝,但它需要重新獲取改對(duì)象的鎖,直到獲取成功才能往下執(zhí)行岸霹;
4疾层、其次,wait贡避、notify 方法必須在 synchronized 塊或方法中被調(diào)用痛黎,并且要保證同步塊或方法的鎖對(duì)象與調(diào)用 wait、notify 方法的對(duì)象是同一個(gè)贸桶,如此一來在調(diào)用 wait 之前當(dāng)前線程就已經(jīng)成功獲取某對(duì)象的鎖舅逸,執(zhí)行 wait 阻塞后當(dāng)前線程就將之前獲取的對(duì)象鎖釋放。
22皇筛、在 Java 中 CycliBarriar 和 CountdownLatch 有什么區(qū)別琉历?
1、CyclicBarrier 可以重復(fù)使用水醋,而 CountdownLatch 不能重復(fù)使用旗笔。
CountdownLatch :
1、Java 的 concurrent 包里面的 CountDownLatch 其實(shí)可以把它看作一個(gè)計(jì)數(shù)器拄踪,只不過這個(gè)計(jì)數(shù)器的操作是原子操作蝇恶,同時(shí)只能有一個(gè)線程去操作這個(gè)計(jì)數(shù)器,也就是同時(shí)只能有一個(gè)線程去減這個(gè)計(jì)數(shù)器里面的值惶桐。你可以向 CountDownLatch 對(duì)象設(shè)置一個(gè)初始的數(shù)字作為計(jì)數(shù)值撮弧,任何調(diào)用這個(gè)對(duì)象上的 wait()方法都會(huì)阻塞,直到這個(gè)計(jì)數(shù)器的計(jì)數(shù)值被其他的線程減為 0 為止姚糊。
2贿衍、所以在當(dāng)前計(jì)數(shù)到達(dá)零之前,wait 方法會(huì)一直受阻塞救恨。之后贸辈,會(huì)釋放所有等待的線程,await 的所有后續(xù)調(diào)用都將立即返回肠槽。這種現(xiàn)象只出現(xiàn)一次——計(jì)數(shù)無法被重置擎淤。如果需要重置計(jì)數(shù)奢啥,請(qǐng)考慮使用CyclicBarrier。
3嘴拢、CountDownLatch 的一個(gè)非常典型的應(yīng)用場景是:有一個(gè)任務(wù)想要往下執(zhí)行桩盲,但必須要等到其他的任務(wù)執(zhí)行完畢后才可以繼續(xù)往下執(zhí)行。假如我們這個(gè)想要繼續(xù)往下執(zhí)行的任務(wù)調(diào)用一個(gè) CountDownLatch 對(duì)象的 wait()方法炊汤,其他的任務(wù)執(zhí)行完自己的任務(wù)后調(diào)用同一個(gè) CountDownLatch 對(duì)象上的 countDown()方法正驻,
這個(gè)調(diào)用 await()方法的任務(wù)將一直阻塞等待,直到這個(gè) CountDownLatch 對(duì)象的計(jì)數(shù)值減到 0 為止抢腐。
CyclicBarrier :
1姑曙、CyclicBarrier 是一個(gè)同步輔助類,它允許一組線程互相等待迈倍,直到到達(dá)某個(gè)公共屏障點(diǎn) (common barrier point)伤靠。在涉及一組固定大小的線程的程序中,這些線程必須不時(shí)地互相等待啼染,此時(shí) CyclicBarrier 很有用宴合。因?yàn)樵?barrier 在釋放等待線程后可以重用,所以稱它為循環(huán) 的 barrier迹鹅。
23卦洽、什么是不可變對(duì)象,它對(duì)寫并發(fā)應(yīng)用有什么幫助斜棚?
1阀蒂、不可變對(duì)象即對(duì)象一旦被創(chuàng)建它的狀態(tài)(對(duì)象的數(shù)據(jù),也即對(duì)象屬性值)就不能改變弟蚀,反之即為可變對(duì)象蚤霞。
2、不可變對(duì)象的類即為不可變類(Immutable Class)义钉。Java 平臺(tái)類庫中包含許多不可變類昧绣,如 String、基本類型的包裝類捶闸、BigInteger 和 BigDecimal 等夜畴。
3、不可變對(duì)象天生是線程安全的删壮。它們的常量(域)是在構(gòu)造函數(shù)中創(chuàng)建的斩启。既然它們的狀態(tài)無法修改,這些常量永遠(yuǎn)不會(huì)變
4醉锅、只有滿足如下狀態(tài),一個(gè)對(duì)象才是不可變的:它的狀態(tài)不能在創(chuàng)建后再被修改发绢;所有域都是 final 類型硬耍;并且垄琐,它被正確創(chuàng)建(創(chuàng)建期間沒有發(fā)生 this 引用的溢出)。
24经柴、什么是多線程中的上下文切換狸窘?
1、在上下文切換過程中坯认,CPU 會(huì)停止處理當(dāng)前運(yùn)行的程序翻擒,并保存當(dāng)前程序運(yùn)行的具體位置以便之后繼續(xù)運(yùn)行。從這個(gè)角度來看牛哺,
2陋气、上下文切換有點(diǎn)像我們同時(shí)閱讀幾本書,在來回切換書本的同時(shí)我們需要記住每本書當(dāng)前讀到的頁碼引润。在程序中巩趁,上下文切換過程中的“頁碼”信息是保存在進(jìn)程控制塊(PCB)中的。PCB 還經(jīng)常被稱作“切換楨”(switchframe)淳附。
3议慰、“頁碼”信息會(huì)一直保存到 CPU 的內(nèi)存中,直到他們被再次使用奴曙。上下文切換是存儲(chǔ)和恢復(fù) CPU 狀態(tài)的過程别凹,它使得線程執(zhí)行能夠從中斷點(diǎn)恢復(fù)執(zhí)行。上下文切換是多任務(wù)操作系統(tǒng)和多線程環(huán)境的基本特征洽糟。