求职学习笔记|并发编程知识点常见问题总结(一)
1. 什么是阻塞隊(duì)列?阻塞隊(duì)列的實(shí)現(xiàn)原理是什么?
阻塞隊(duì)列(BlockingQueue)是一個支持兩個附加操作的隊(duì)列。
這兩個附加的操作是:在隊(duì)列為空時,獲取元素的線程會等待隊(duì)列變?yōu)榉强铡.?dāng)隊(duì)列滿時,存儲元素的線程會等待隊(duì)列可用。
阻塞隊(duì)列常用于生產(chǎn)者和消費(fèi)者的場景,生產(chǎn)者是往隊(duì)列里添加元素的線程,消費(fèi)者是從隊(duì)列里拿元素的線程。阻塞隊(duì)列就是生產(chǎn)者存放元素的容器,而消費(fèi)者也只從容器里拿元素。
2. 什么是 Callable 和 Future?
Callable接口類似于 Runnable,從名字就可以看出來了,但是Runnable不會返回結(jié)果,并且無法拋出返回結(jié)果的異常,而 Callable功能更強(qiáng)大一些,被線程執(zhí)行后,可以返回值,這個返回值可以被Future拿到,也就是說,Future 可以拿到異步執(zhí)行任務(wù)的返回值。可以認(rèn)為是帶有回調(diào)的 Runnable。
Future接口表示異步任務(wù),是還沒有完成的任務(wù)給出的未來結(jié)果。所以說 Callable 用于產(chǎn)生結(jié)果,Future 用于獲取結(jié)果。
3. 什么是 FutureTask?
在 Java 并發(fā)程序中FutureTask表示一個可以取消的異步運(yùn)算。它有啟動和取消運(yùn)算、查詢運(yùn)算是否完成和取回運(yùn)算結(jié)果等方法。只有當(dāng)運(yùn)算完成的時候結(jié)果才能取回,如果運(yùn)算尚未完成 get方法將會阻塞。一個FutureTask對象可以對調(diào)用了 Callable 和 Runnable 的對象進(jìn)行包裝,由于FutureTask也是調(diào)用了 Runnable接口所以它可以提交給 Executor 來執(zhí)行。
4. notify ()和 notifyAll ()有什么區(qū)別?
當(dāng)一個線程進(jìn)入 wait 之后,就必須等其他線程notify/notifyall,使用 notifyall,可以喚醒所有處于 wait 狀態(tài)的線程,使其重新進(jìn)入鎖的爭奪隊(duì)列中,而 notify只能喚醒一個。
如果沒把握,建議notifyAll,防止notify因?yàn)樾盘杹G失而造成程序異常。
5. 什么是可重入鎖( ReentrantLock )?談?wù)勊膶?shí)現(xiàn)
線程可以重復(fù)進(jìn)入任何一個它已經(jīng)擁有的鎖所同步著的代碼塊,synchronized、ReentrantLock都是可重入的鎖。在實(shí)現(xiàn)上,就是線程每次獲取鎖時判定如果獲得鎖的線程是它自己時,簡單將計(jì)數(shù)器累積即可,每 釋放一次鎖,進(jìn)行計(jì)數(shù)器累減,直到計(jì)算器歸零,表示線程已經(jīng)徹底釋放鎖。
6. 樂觀鎖和悲觀鎖的理解及如何實(shí)現(xiàn),有哪些實(shí)現(xiàn)方式?
悲觀鎖:總是假設(shè)最壞的情況,每次去拿數(shù)據(jù)的時候都認(rèn)為別人會修改,所以每次在拿數(shù)據(jù)的時候都會上鎖,這樣別人想拿這個數(shù)據(jù)就會阻塞直到它拿到鎖。Java里面的同步原語synchronized關(guān)鍵字的實(shí)現(xiàn)是悲觀鎖。
樂觀鎖:顧名思義,就是很樂觀,每次去拿數(shù)據(jù)的時候都認(rèn)為別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數(shù)據(jù),可以使用版本號等機(jī)制。在Java中原子變量類就是使用了樂觀鎖的一種實(shí)現(xiàn)方式 CAS 實(shí)現(xiàn)的。
樂觀鎖的實(shí)現(xiàn)方式:
使用版本標(biāo)識來確定讀到的數(shù)據(jù)與提交時的數(shù)據(jù)是否一致。提交后修改版本標(biāo)識,不一致時可以采取丟棄和再次嘗試的策略。
java 中的 Compare and Swap 即 CAS ,當(dāng)多個線程嘗試使用 CAS 同時更新同一個變量時,只有其中一個線程能更新變量的值,而其它線程都失敗,失敗的線程并不會被掛起,而是被告知這次競爭中失敗,并可以再次嘗試。Java開發(fā)交流君樣:756584822
7. 什么是 CAS 操作,缺點(diǎn)是什么?
CAS 的基本思路就是,如果這個地址上的值和期望的值相等,則給其賦予新值,否則不做任何事兒,但是要返回原值是多少。每一個 CAS 操作過程都包含三個運(yùn)算符:一個內(nèi)存地址 V,一個期望的值 A 和一個新值 B,操作的時候如果這個地址上存放的值等于這個期望的值 A,則將地址上的值賦為新值 B,否則不做任何操作。
CAS 缺點(diǎn)
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開始J DK 的 atomic包里提供了一個類 AtomicStampedReference 來解決 ABA 問題。
循環(huán)時間長開銷大:
對于資源競爭嚴(yán)重(線程沖突嚴(yán)重)的情況,CAS自旋的概率會比較大,從而浪費(fèi)更多的 CPU 資源,效率低于 synchronized。
只能保證一個共享變量的原子操作:
當(dāng)對一個共享變量執(zhí)行操作時,我們可以使用循環(huán) CAS 的方式來保證原子操作,但是對多個共享變量操作時,循環(huán) CAS 就無法保證操作的原子性,這個時候就可以用鎖。
8. SynchronizedMap 和 ConcurrentHashMap 有什么區(qū)別?
1. Executor框架是一個根據(jù)一組執(zhí)行策略調(diào)用,調(diào)度,執(zhí)行和控制的異步任務(wù)的框架。每次執(zhí)行任務(wù)創(chuàng)建線程 new
Thread()比較消耗性能,創(chuàng)建一個線程是比較耗時、耗資源的。
2. 調(diào)用 new
Thread()創(chuàng)建的線程缺乏管理,而且可以無限制的創(chuàng)建,線程之間的相互競爭會導(dǎo)致過多占用系統(tǒng)資源而導(dǎo)致系統(tǒng)癱瘓,還有線程之間的頻繁交替也會消耗很多系統(tǒng)資源。
接使用 new Thread()啟動的線程不利于擴(kuò)展,比如定時執(zhí)行、定期執(zhí)行、定時定期執(zhí)行、線程中斷等都不便實(shí)現(xiàn)。
9. 在 Java 中 wait 和 sleep 方法的不同?
最大的不同是在等待時 wait 會釋放鎖,而 sleep 一直持有鎖。Wait 通常被用于線程間交互,sleep 通常被用于暫停執(zhí)行。
10. 一個線程運(yùn)行時發(fā)生異常會怎樣?
如果異常沒有被捕獲該線程將會停止執(zhí)行。Thread.UncaughtExceptionHandler是用于處理未捕獲異常造成線程突然中斷情況的一個內(nèi)嵌接口。當(dāng)一個未捕獲異常將造成線程中斷的時候 JVM 會使用 Thread.getUncaughtExceptionHandler ( ) 來查詢線程的UncaughtExceptionHandler并將線程和異常作為參數(shù)傳遞給handler的uncaughtException()方法進(jìn)行處理。
最后,祝大家早日學(xué)有所成,拿到滿意offer
總結(jié)
以上是生活随笔為你收集整理的求职学习笔记|并发编程知识点常见问题总结(一)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 花呗延期后下个月可以最低还款吗?
- 下一篇: 股票分红钱打到哪里?