Java并发编程—常见面试题
建議:
- 學習java并發(fā)前需要先掌握JVM知識
- 關于下面問題檔案的詳細解析都在后面推薦的相關系列文章中
?
一、線程安全相關
1、什么叫線程安全?
線程安全就是說多線程訪問同一代碼,不會產(chǎn)生不確定的結果。
2、為什么會存在線程安全的問題?
- 共享性:多個線程操作同一個類實例時,類屬性是共享的。
- 互斥性:為保證數(shù)據(jù)安全性,同一時刻只有一個線程可以修改數(shù)據(jù)
3、如何保證線程安全?
- 原子性:針對代碼塊
- 可見性:數(shù)據(jù)從線程工作內(nèi)存刷新到JVM主存中這個動作必須是同步的
- 有序性:指令重排,操作系統(tǒng)對指令進行重排序時只保證單線程時最終結果的正確性,不能保證多線程情況下最終結果的正確性
4、同步有幾種實現(xiàn)方法?(或者問Java 程序中怎么保證多線程的運行安全?)?
JDK內(nèi)置的syncchronized關鍵字、共享變量(volatile)實現(xiàn)線程同步、JUC的可重入鎖ReentrantLock類、使用局部變量實現(xiàn)線程同步
5、volatile關鍵字有什么作用?弊端是什么?適用場景是什么?
1)作用:通過volatile關鍵字可以保證變量的可見性和有序性,但不能保證原子性
- 可見性:變量修改被立即刷新到主存中;變量讀取不能從工作內(nèi)存讀取,必須從主存讀取。(通過硬件鎖保證線程安全的)
- 有序性:volatile變量前的代碼不能重排到volatile變量后,volatile變量后的代碼也不能重排到volatile變量前。
2)弊端
- 原子性:i++操作是非線程安全的,即使通過volatile關鍵字修飾也不能保證其原子性
3)適用場景
6、volatile與synchronized區(qū)別是什么?什么場景下可以使用volatile替換synchronized?
volatile只能保證可見性和有序性,synchronized可以保證原子性、可見性、有序性
- 狀態(tài)標志:把簡單地volatile變量作為狀態(tài)標志,來達成線程之間通訊的目的,省去了用synchronized還要wait、notify或者interrupt的編碼麻煩。
- 替換重量級鎖:如果某個變量僅是單次讀或者單次寫操作,沒有復合操作(i++,先檢查后判斷之類的)就可以用volatile替換synchronized。
二、CAS相關
1、CAS是什么
CAS是樂觀鎖思想的一種實現(xiàn)方式,也是無鎖保證變量線程安全的一種方式。原理是將變量的新值寫入主存前,需要比較工作內(nèi)存中的舊值和主存中的舊值是否相等(相等說明主存中的變量沒有被其他線程修改過),相等則將新值寫入主存中。
2、ABA問題
比如說一個線程one從內(nèi)存位置V取出value_A,這時候另一個線程two也從內(nèi)存中取出value_A,并且線程two進行了一些操作變成了value_B,然后two又將V位置的數(shù)據(jù)變成value_A,這時候線程one進行CAS操作發(fā)現(xiàn)內(nèi)存中仍然是A,然后one操作成功。盡管線程one的CAS操作成功,但是不代表這個過程就是沒有問題的。解決方法:通過版本號(version)的方式來解決,每次比較要比較數(shù)據(jù)的值和版本號兩項內(nèi)容即可。
3、atomic 的原理?
?
三、鎖的種類
1、分類
- 樂觀鎖/悲觀鎖:假設每次操作都不會沖突,若是遇到?jīng)_突失敗就重試直到成功;悲觀鎖是讓其他線程都等待,等鎖釋放完了再競爭鎖。
- 共享鎖/獨占鎖:也叫讀寫鎖/互斥鎖
- 公平鎖/非公平鎖
- 可重入鎖:線程可以進入任何一個它持有鎖的線程
- 自旋鎖
- 自適應自旋鎖
- 無鎖/偏向鎖/輕量級鎖/重量級鎖
2、樂觀鎖/悲觀鎖實現(xiàn)方式?
- 樂觀鎖實現(xiàn)方式:cas,volatile
- 悲觀鎖實現(xiàn)方式:synchronized,Lock
3、讀寫鎖可以用于什么場景?
適用于少寫多讀的情況,互斥鎖效率低,而多線程都是讀的情況不需要互斥,只有讀-寫、寫-寫沖突時才需要互斥,通過讀寫鎖可以提高效率,具體工具類是ReentrantReadWriteLock
4、什么時候應該使用可重入鎖?
可重入鎖指的是同一線程外層函數(shù)獲得鎖之后 ,內(nèi)層遞歸函數(shù)仍然有獲取該鎖的代碼,ReentrantLock 和synchronized都是可重入鎖,所以大部分情況下使用的都是可重入鎖
5、鎖的4種狀態(tài)以及膨脹過程
膨脹方向:無鎖 → 偏向鎖 → 輕量級鎖 → 重量級鎖(只能單向膨脹,不能逆膨脹)
膨脹原因:多線程競爭加劇,導致鎖升級
6、什么是死鎖??怎么防止死鎖?
?
三、Synchoronied
1、Synchoronied是什么?
關鍵詞:重量級鎖、悲觀鎖、互斥鎖、
2、使用方法
用于修飾普通函數(shù)、靜態(tài)函數(shù)、代碼塊
3、底層原理:
通過底層cpu的monitorenter和monitorexit對線程的出入進行控制
4、優(yōu)化:
輕量級鎖、偏向鎖
5、當一個線程進入某個對象的一個synchronized的實例方法后,其它線程是否可進入此對象的其它方法?
- 如果其他方法前加了synchronized關鍵字,就不能,如果沒加synchronized,則能夠進去。因為一個對象只有一個monitor鎖,當一個線程進入synchronized的實例方法后便獲得了當前對象的monitor鎖,其他線程由于無法獲得monitor鎖,所以無法進入此對象的其它被synchronized修飾的方法。
- 如果這個方法內(nèi)部調(diào)用了wait(),則釋放了monitor鎖,則可以進入其他加synchronized的方法。如果其他方法加了synchronized關鍵字,并且沒有調(diào)用wai方法,則不能。
四、Lock類
1、底層原理:
依賴于AQS
2、AQS原理?
關鍵詞:juc包的Lock類的基石
數(shù)據(jù)結構:帶有頭尾指針的雙向鏈表,節(jié)點Node中包含頭指針、尾指針、搶占狀態(tài)3個重要的屬性
作用:實現(xiàn)線程的搶鎖、釋放鎖、排隊等待、阻塞喚醒等操作
3、Lock鎖、ReentrantLock、ReentrantWriteReadLock、LockSupport?
?
4、CountDownLatch、CyclicBarrier?、Semaphore?
?
5、wait/notify()/notifyAll()、await()/signal/signalAll區(qū)別?
?
6、synchronized和java.util.concurrent.locks.Lock的異同?
- 主要相同點:Lock能完成Synchronized所實現(xiàn)的所有功能。
- 主要不同點:
?
五、多線程操作相關
1、并行和并發(fā)有什么區(qū)別?
2、線程和進程的區(qū)別?
3、 守護線程是什么?
4、創(chuàng)建線程有哪幾種方式?
5、說一下 runnable 和 callable 有什么區(qū)別?
6、線程有哪些狀態(tài)?
7、 sleep() 和 wait() 有什么區(qū)別?
8、notify()和 notifyAll()有什么區(qū)別?
9、 線程的 run() 和 start() 有什么區(qū)別?
10、創(chuàng)建線程池有哪幾種方式?
11、線程池都有哪些狀態(tài)?
12、線程池中 submit() 和 execute() 方法有什么區(qū)別?
13. ThreadLocal 是什么?有哪些使用場景?
六、并發(fā)編程實戰(zhàn)
1、如何實現(xiàn)一個流控程序,用于控制請求的調(diào)用次數(shù)?
?
答案參考:Java并發(fā)編程—實戰(zhàn)
?
Java并發(fā)編程系列文章:
- Java 并發(fā)編程—核心理論
- Java并發(fā)編程—volatile關鍵字(保證變量的可見性、有序性機制)
- Java并發(fā)編程—無鎖互斥機制及CAS原理
- Java并發(fā)編程—鎖的基本概念
- Java 并發(fā)編程—Synchronized關鍵字
- Java并發(fā)編程—Synchronized底層優(yōu)化(偏向鎖、輕量級鎖)
- Java 并發(fā)編程—有鎖互斥機制及AQS理論
- Java并發(fā)編程—AQS原理分析
- Java并發(fā)編程—自旋鎖CLHLock、MCSLock原理
- Java并發(fā)編程—JUC的Lock鎖
- Java并發(fā)編程—線程同步類
- Java并發(fā)編程—線程間協(xié)作方式wait()、notify()、notifyAll()和Condition
- Java并發(fā)編程—為什么 wait() 方法需要寫在 while 里,而不是 if?
總結
以上是生活随笔為你收集整理的Java并发编程—常见面试题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java并发编程—自旋锁CLHLock原
- 下一篇: Java并发编程—Atomic原子类