1. 多線程使用的優缺點?
優點:
(1)多線程技術使程序的響應速度更快
(2)當前沒有進行處理的任務可以將處理器時間讓給其它任務
(3)佔用大量處理時間的任務可以定期將處理器時間讓給其它任務
(4)可以隨時停止任務
(5)可以分別設置各個任務的優先級以及優化性能
缺點:
(1)等候使用共享資源時造成程序的運行速度變慢
(2)對線程進行管理要求額外的cpu開銷
(3)可能出現線程死鎖情況。即較長時間的等待或資源競爭以及死鎖等症狀。
2. start()方法和run()方法簡介和區別?
start()方法:
1)用start方法來啟動線程,真正實現了多線程運行,這時無需等待run方法體代碼執行完畢而直接繼續執行下面的代碼。
2)通過調用Thread類的start()方法來啟動一個線程,這時此線程處於就緒(可運行)狀態,並沒有運行,一旦得到CPU時間片,就開始執行run()方法。
run()方法:
1)run()方法只是類的一個普通方法而已,如果直接調用Run方法,程序中依然只有主線程這一個線程,其程序執行路徑還是隻有一條。
總結:
1)調用start方法方可啟動線程,
2)而run方法只是thread的一個普通方法調用,還是在主線程裡執行。
3)把需要並行處理的代碼放在run()方法中,start()方法啟動線程將自動調用run()方法,這是由jvm的內存機制規定的。
4)並且run()方法必須是public訪問權限,返回值類型為void.。
3. Runnable接口和Callable接口的相同點和不同點?
4. volatile關鍵字的作用是什麼?
(1)多線程使用volatile關鍵字修飾的變量,保證了其在多線程之間的可見性,即每次讀取到volatile變量,一定是最新的數據
(2)Java代碼執行中,為了獲取更好的性能JVM可能會對指令進行重排序,多線程下可能會出現一些意想不到的問題。使用volatile則會對禁止語義重排序,當然這也一定程度上降低了代碼執行效率
5. CyclicBarrier和CountDownLatch的區別是什麼?
6. volatile和synchronized對比?
1)volatile本質是在告訴jvm當前變量在寄存器中的值是不確定的,需要從主存中讀取,synchronized則是鎖定當前變量,只有當前線程可以訪問該變量,其他線程被阻塞住.
2)volatile僅能使用在變量級別,synchronized則可以使用在變量,方法.
3)volatile僅能實現變量的修改可見性,而synchronized則可以保證變量的修改可見性和原子性.
4)volatile不會造成線程的阻塞,而synchronized可能會造成線程的阻塞.
7. 怎麼喚醒一個阻塞的線程?
如果線程是因為調用了wait()、sleep()或者join()方法而導致的阻塞,可以中斷線程,並且通過拋出InterruptedException來喚醒它;如果線程遇到了IO阻塞,無能為力,因為IO是操作系統實現的,Java代碼並沒有辦法直接接觸到操作系統。
8. Java中如何獲取到線程dump文件?
dump文件的作用:
死循環、死鎖、阻塞、頁面打開慢等問題,打線程dump是最好的解決問題的途徑。因此,線程dump也就是線程堆棧。
獲取到線程堆棧dump文件內容分兩步:
(1)第一步:獲取到線程的pid,Linux環境下可以使用ps -ef | grep java
(2)第二步:打印線程堆棧,可以通過使用jstack pid命令
9. sleep方法和wait方法的相同點和不同點?
相同點:
二者都可以讓線程處於凍結狀態。
不同點:
1)首先應該明確sleep方法是Thread類中定義的方法,而wait方法是Object類中定義的方法。
2)sleep方法必須人為地為其指定時間。
wait方法既可以指定時間,也可以不指定時間。
3)sleep方法時間到,線程處於臨時阻塞狀態或者運行狀態。
wait方法如果沒有被設置時間,就必須要通過notify或者notifyAll來喚醒。
4)sleep方法不一定非要定義在同步中。
wait方法必須定義在同步中。
5)當二者都定義在同步中時,
線程執行到sleep,不會釋放鎖。
線程執行到wait,會釋放鎖。
10. 生產者和消費者模型的作用是什麼?
1)通過平衡生產者的生產能力和消費者的消費能力來提升整個系統的運行效率,這是生產者消費者模型最重要的作用
2)解耦,這是生產者消費者模型附帶的作用,解耦意味著生產者和消費者之間的聯繫少,聯繫越少越可以獨自發展而不需要收到相互的制約
11. ThreadLocal的作用是什麼?
1)ThreadLocal用來解決多線程程序的併發問題
2)ThreadLocal並不是一個Thread,而是Thread的局部變量,當使用ThreadLocal維護變量時,ThreadLocal為每個使用該變量的線程提供獨立的變量副本,所以每個線程都可以獨立地改變自己的副本,而不會影響其它線程所對應的副本.
3)從線程的角度看,目標變量就象是線程的本地變量,這也是類名中“Local”所要表達的意思。
4)線程局部變量並不是Java的新發明,Java沒有提供在語言級支持(語法上),而是變相地通過ThreadLocal的類提供支持.
12. wait方法和notify/notifyAll方法在放棄對象監視器時有什麼區別?
wait()方法立即釋放對象監視器;
notify()/notifyAll()方法則會等待線程剩餘代碼執行完畢才會放棄對象監視器。
13. Lock和synchronized對比?
1)Lock是一個接口,而synchronized是Java中的關鍵字,synchronized是內置的語言實現;
2)synchronized在發生異常時,會自動釋放線程佔有的鎖,因此不會導致死鎖現象發生;而Lock在發生異常時,如果沒有主動通過unLock()去釋放鎖,則很可能造成死鎖現象,因此使用Lock時需要在finally塊中釋放鎖;
3)Lock可以讓等待鎖的線程響應中斷,而synchronized卻不行,使用synchronized時,等待的線程會一直等待下去,不能夠響應中斷;
4)通過Lock可以知道有沒有成功獲取鎖,而synchronized卻無法辦到。
5)Lock可以提高多個線程進行讀操作的效率。
6)在JDK1.5中,synchronized是性能低效的。因為這是一個重量級操作,它對性能最大的影響是阻塞式的實現,掛起線程和恢復線程的操作都需要轉入內核態中完成,這些操作給系統的併發性帶來了很大的壓力。相比之下使用Java提供的Lock對象,性能更高一些。
但是,JDK1.6,發生了變化,對synchronize加入了很多優化措施,有自適應自旋,鎖消除,鎖粗化,輕量級鎖,偏向鎖等等。導致在JDK1.6上synchronize的性能並不比Lock差。因此。提倡優先考慮使用synchronized來進行同步。
14、ConcurrentHashMap的併發度是什麼?
ConcurrentHashMap的併發度就是segment的大小,默認為16,這意味著最多同時可以有16條線程操作ConcurrentHashMap,這也是ConcurrentHashMap對Hashtable的最大優勢,任何情況下,Hashtable能同時有兩條線程獲取Hashtable中的數據∂
15、ReadWriteLock是什麼?
ReadWriteLock是一個讀寫鎖接口,ReentrantReadWriteLock是ReadWriteLock接口的一個具體實現,實現了讀寫的分離,讀鎖是共享的,寫鎖是獨佔的,讀和讀之間不會互斥,讀和寫、寫和讀、寫和寫之間才會互斥,提升了讀寫的性能。
16、FutureTask是什麼?
FutureTask表示一個異步運算的任務。FutureTask裡面可以傳入一個Callable的具體實現類,可以對這個異步運算的任務的結果進行等待獲取、判斷是否已經完成、取消任務等操作。由於FutureTask也是Runnable接口的實現類,所以FutureTask也可以放入線程池中。
17、Java中用到的線程調度算法是什麼?
搶佔式。一個線程用完CPU之後,操作系統會根據線程優先級、線程飢餓情況等數據算出一個總的優先級並分配下一個時間片給某個線程執行。
18、單例模式的線程安全性?
單例模式的線程安全意味著:某個類的實例在多線程環境下只會被創建一次出來。單例模式有很多種的寫法,具體分析如下:
(1)餓漢式單例模式的寫法:線程安全
(2)懶漢式單例模式的寫法:非線程安全
(3)雙檢鎖單例模式的寫法:線程安全
19、什麼是樂觀鎖和悲觀鎖?
(1)樂觀鎖:對於併發間操作產生的線程安全問題持樂觀狀態,樂觀鎖認為競爭不總是會發生,因此它不需要持有鎖,將比較-設置這兩個動作作為一個原子操作嘗試去修改內存中的變量,如果失敗則表示發生衝突,那麼就應該有相應的重試邏輯。
(2)悲觀鎖:對於併發間操作產生的線程安全問題持悲觀狀態,悲觀鎖認為競爭總是會發生,因此每次對某資源進行操作時,都會持有一個獨佔的鎖,就像synchronized,直接對操作資源上了鎖。
20. Java編寫一個會導致死鎖的程序?
死鎖現象描述:
線程A和線程B相互等待對方持有的鎖導致程序無限死循環下去。
死鎖的實現步驟:
(1)兩個線程裡面分別持有兩個Object對象:lock1和lock2。這兩個lock作為同步代碼塊的鎖;
(2)線程1的run()方法中同步代碼塊先獲取lock1的對象鎖,Thread.sleep(xxx),時間不需要太多,100毫秒差不多了,然後接著獲取lock2的對象鎖。這麼做主要是為了防止線程1啟動一下子就連續獲得了lock1和lock2兩個對象的對象鎖
(3)線程2的run)(方法中同步代碼塊先獲取lock2的對象鎖,接著獲取lock1的對象鎖,當然這時lock1的對象鎖已經被線程1鎖持有,線程2肯定是要等待線程1釋放lock1的對象鎖的
這樣,線程1″睡覺”睡完,線程2已經獲取了lock2的對象鎖了,線程1此時嘗試獲取lock2的對象鎖,便被阻塞,此時一個死鎖就形成了。
死鎖的實現代碼:
輸出結果是:
線程A 鎖住資源O1,等待O2
線程B 鎖住資源O2,等待O1
此頭條號每天都會分享技術文章和麵試題講解,除了以上的面試題之外還發布了不少。比如:
京東的一道A、B線程面試題:兩個線程循環順序打印A、B(有代碼)
京東和騰訊精選12道Java筆試題並有答案
最近需要面試的同學可以關注這個頭條號,即可獲取面試題和技術文章。