前言
多線程和併發問題是Java技術面試中面試官比較喜歡問的問題之一。在這裏,從面試的角度列出了大部分重要的問題,可是你仍然應該牢固的掌握Java多線程基礎知識來對應往後碰到的問題。面試
1、基礎知識
1. 爲何要使用併發編程
- 充分利用多核CPU的計算能力:經過併發編程的形式能夠將多核CPU的計算能力發揮到極致,性能獲得提高
- 方便進行業務拆分,提高系統併發能力和性能:在特殊的業務場景下,先天的就適合於併發編程。如今的系統動不動就要求百萬級甚至千萬級的併發量,而多線程併發編程正是開發高併發系統的基礎,利用好多線程機制能夠大大提升系統總體的併發能力以及性能。面對複雜業務模型,並行程序會比串行程序更適應業務需求,而併發編程更能吻合這種業務拆分 。
2. 多線程應用場景
3. 併發編程有什麼缺點
併發編程的目的就是爲了能提升程序的執行效率,提升程序運行速度,可是併發編程並不老是能提升程序運行速度的,並且併發編程可能會遇到不少問題,好比**:內存泄漏、上下文切換、線程安全、死鎖**等問題。算法
4. 併發編程三個必要因素是什麼?
併發編程三要素(線程的安全性問題體如今):編程
原子性:原子,即一個不可再被分割的顆粒。原子性指的是一個或多個操做要麼所有執行成功要麼所有執行失敗。數組
可見性:一個線程對共享變量的修改,另外一個線程可以馬上看到。(synchronized,volatile)緩存
有序性:程序執行的順序按照代碼的前後順序執行。(處理器可能會對指令進行重排序)安全
出現線程安全問題的緣由:網絡
- 線程切換帶來的原子性問題
- 緩存致使的可見性問題
- 編譯優化帶來的有序性問題
解決辦法:多線程
- JDK Atomic開頭的原子類、synchronized、LOCK,能夠解決原子性問題
- synchronized、volatile、LOCK,能夠解決可見性問題
- Happens-Before 規則能夠解決有序性問題
5. Java 程序中怎麼保證多線程的運行安全?
6. 並行和併發有什麼區別?
7. 什麼是多線程
多線程:多線程是指程序中包含多個執行流,即在一個程序中能夠同時運行多個不一樣的線程來執行不一樣的任務。併發
8. 多線程的好處
能夠提升 CPU 的利用率。在多線程程序中,一個線程必須等待的時候,CPU 能夠運行其它的線程而不是等待,這樣就大大提升了程序的效率。也就是說容許單個程序建立多個並行執行的線程來完成各自的任務。app
9. 多線程的劣勢:
- 線程也是程序,因此線程須要佔用內存,線程越多佔用內存也越多;
- 多線程須要協調和管理,因此須要 CPU 時間跟蹤線程;
- 線程之間對共享資源的訪問會相互影響,必須解決競用共享資源的問題。
10. 線程和進程區別
進程
一個在內存中運行的應用程序。每一個進程都有本身獨立的一塊內存空間,一個進程能夠有多個線程,好比在Windows系統中,一個運行的xx.exe就是一個進程。
線程
進程中的一個執行任務(控制單元),負責當前進程中程序的執行。一個進程至少有一個線程,一個進程能夠運行多個線程,多個線程可共享數據。
線程具備許多傳統進程所具備的特徵,故又稱爲輕型進程(Light—Weight Process)或進程元;而把傳統的進程稱爲重型進程(Heavy—Weight Process),它至關於只有一個線程的任務。在引入了線程的操做系統中,一般一個進程都有若干個線程,至少包含一個線程。
根本區別:進程是操做系統資源分配的基本單位,而線程是處理器任務調度和執行的基本單位
資源開銷:每一個進程都有獨立的代碼和數據空間(程序上下文),程序之間的切換會有較大的開銷;線程能夠看作輕量級的進程,同一類線程共享代碼和數據空間,每一個線程都有本身獨立的運行棧和程序計數器(PC),線程之間切換的開銷小。
包含關係:若是一個進程內有多個線程,則執行過程不是一條線的,而是多條線(線程)共同完成的;線程是進程的一部分,因此線程也被稱爲輕權進程或者輕量級進程。
內存分配:同一進程的線程共享本進程的地址空間和資源,而進程之間的地址空間和資源是相互獨立的
影響關係:一個進程崩潰後,在保護模式下不會對其餘進程產生影響,可是一個線程崩潰整個進程都死掉。因此多進程要比多線程健壯。
執行過程:每一個獨立的進程有程序運行的入口、順序執行序列和程序出口。可是線程不能獨立執行,必須依存在應用程序中,由應用程序提供多個線程執行控制,二者都可併發執行
11. 什麼是上下文切換?
多線程編程中通常線程的個數都大於 CPU 核心的個數,而一個 CPU 核心在任意時刻只能被一個線程使用,爲了讓這些線程都能獲得有效執行,CPU 採起的策略是爲每一個線程分配時間片並輪轉的形式。當一個線程的時間片用完的時候就會從新處於就緒狀態讓給其餘線程使用,這個過程就屬於一次上下文切換。
歸納來講就是:當前任務在執行完 CPU 時間片切換到另外一個任務以前會先保存本身的狀態,以便下次再切換回這個任務時,能夠再加載這個任務的狀態。任務從保存到再加載的過程就是一次上下文切換。
上下文切換一般是計算密集型的。也就是說,它須要至關可觀的處理器時間,在每秒幾十上百次的切換中,每次切換都須要納秒量級的時間。因此,上下文切換對系統來講意味着消耗大量的 CPU 時間,事實上,多是操做系統中時間消耗最大的操做。
Linux 相比與其餘操做系統(包括其餘類 Unix 系統)有不少的優勢,其中有一項就是,其上下文切換和模式切換的時間消耗很是少。
12. 守護線程和用戶線程有什麼區別呢?
守護線程和用戶線程
- 用戶 (User) 線程:運行在前臺,執行具體的任務,如程序的主線程、鏈接網絡的子線程等都是用戶線程
- 守護 (Daemon) 線程:運行在後臺,爲其餘前臺線程服務。也能夠說守護線程是 JVM 中非守護線程的 「傭人」。一旦全部用戶線程都結束運行,守護線程會隨 JVM 一塊兒結束工做
main 函數所在的線程就是一個用戶線程啊,main 函數啓動的同時在 JVM 內部同時還啓動了好多守護線程,好比垃圾回收線程。
比較明顯的區別之一是用戶線程結束,JVM 退出,無論這個時候有沒有守護線程運行。而守護線程不會影響 JVM 的退出。
注意事項:
setDaemon(true)
必須在start()
方法前執行,不然會拋出 IllegalThreadStateException
異常
- 在守護線程中產生的新線程也是守護線程
- 不是全部的任務均可以分配給守護線程來執行,好比讀寫操做或者計算邏輯
- 守護 (Daemon) 線程中不能依靠 finally 塊的內容來確保執行關閉或清理資源的邏輯。由於咱們上面也說過了一旦全部用戶線程都結束運行,守護線程會隨 JVM 一塊兒結束工做,因此守護 (Daemon) 線程中的 finally 語句塊可能沒法被執行。
13. 如何在 Windows 和 Linux 上查找哪一個線程cpu利用率最高?
14. 什麼是線程死鎖
15. 造成死鎖的四個必要條件是什麼
16. 如何避免線程死鎖
17. 建立線程的四種方式
18. 說一下 runnable 和 callable 有什麼區別
19. 線程的 run()和 start()有什麼區別?
20. 爲何咱們調用 start() 方法時會執行 run() 方法,爲何咱們不能直接調用 run() 方法?
21. 什麼是 Callable 和 Future?
22. 什麼是 FutureTask
23. 線程的狀態
24. Java 中用到的線程調度算法是什麼?
25. 線程的調度策略
26. 什麼是線程調度器(Thread Scheduler)和時間分片(Time Slicing )?
27. 請說出與線程同步以及線程調度相關的方法。
28. sleep() 和 wait() 有什麼區別?
29. 你是如何調用 wait() 方法的?使用 if 塊仍是循環?爲何?
30. 爲何線程通訊的方法 wait(), notify()和 notifyAll()被定義在 Object 類裏?
31. 爲何 wait(), notify()和 notifyAll()必須在同步方法或者同步塊中被調用?
32. Thread 類中的 yield 方法有什麼做用?
33. 爲何 Thread 類的 sleep()和 yield ()方法是靜態的?
34. 線程的 sleep()方法和 yield()方法有什麼區別?
35. 如何中止一個正在運行的線程?
36. Java 中 interrupted 和 isInterrupted 方法的區別?
37. 什麼是阻塞式方法?
38. Java 中你怎樣喚醒一個阻塞的線程?
39. notify() 和 notifyAll() 有什麼區別?
40. 如何在兩個線程間共享數據?
41. Java 如何實現多線程之間的通信和協做?
42. 同步方法和同步塊,哪一個是更好的選擇?
43. 什麼是線程同步和線程互斥,有哪幾種實現方式?
44. 在監視器(Monitor)內部,是如何作線程同步的?程序應該作哪一種級別的同步?
45. 若是你提交任務時,線程池隊列已滿,這時會發生什麼
46. 什麼叫線程安全?servlet 是線程安全嗎?
47. 在 Java 程序中怎麼保證多線程的運行安全?
48. 你對線程優先級的理解是什麼?
49. 線程類的構造方法、靜態塊是被哪一個線程調用的
50. Java 中怎麼獲取一份線程 dump 文件?你如何在 Java 中獲取線程堆棧?
51. 一個線程運行時發生異常會怎樣?
52. Java 線程數過多會形成什麼異常?
53. 多線程的經常使用方法
部分面試題展現,詳細的【答案解析】關注公種浩:麒麟改 bug,獲取。
2、併發理論
1. Java中垃圾回收有什麼目的?何時進行垃圾回收?
2. 線程之間如何通訊及線程之間如何同步
3. Java內存模型
4. 若是對象的引用被置爲null,垃圾收集器是否會當即釋放對象佔用的內存?
5. finalize()方法何時被調用?析構函數(finalization)的目的是什麼?
6. 什麼是重排序
7. 重排序實際執行的指令步驟
8. 重排序遵照的規則
9. as-if-serial規則和happens-before規則的區別
10. 併發關鍵字 synchronized ?
11. 說說本身是怎麼使用 synchronized 關鍵字,在項目中用到了嗎
12. 單例模式瞭解嗎?給我解釋一下雙重檢驗鎖方式實現單例模式!」
13. 說一下 synchronized 底層實現原理?
14. synchronized可重入的原理
15. 什麼是自旋
16. 多線程中 synchronized 鎖升級的原理是什麼?
17. 線程 B 怎麼知道線程 A 修改了變量
18. 當一個線程進入一個對象的 synchronized 方法 A 以後,其它線程是否可進入此對象的 synchronized 方法 B?
19. synchronized、volatile、CAS 比較
20. synchronized 和 Lock 有什麼區別?
21. synchronized 和 ReentrantLock 區別是什麼?
22. volatile 關鍵字的做用
23. Java 中能建立 volatile 數組嗎?
24. volatile 變量和 atomic 變量有什麼不一樣?
25. volatile 能使得一個非原子操做變成原子操做嗎?
26. synchronized 和 volatile 的區別是什麼?
27. final不可變對象,它對寫併發應用有什麼幫助?
28. Lock 接口和synchronized 對比同步它有什麼優點?
29. 樂觀鎖和悲觀鎖的理解及如何實現,有哪些實現方式?
30. 什麼是 CAS
31. CAS 的會產生什麼問題?
32. 什麼是原子類
33. 原子類的經常使用類
34. 說一下 Atomic的原理?
35. 死鎖與活鎖的區別,死鎖與飢餓的區別?
部分面試題展現,詳細的【答案解析】關注公種浩:麒麟改 bug,獲取。
3、線程池
1. 什麼是線程池?
2. 線程池做用?
3. 線程池有什麼優勢?
4. 什麼是ThreadPoolExecutor?
5. 什麼是Executors?
6. 線程池四種建立方式?
7. 在 Java 中 Executor 和 Executors 的區別?
8. 四種構建線程池的區別及特色?
9. 線程池都有哪些狀態?
10. 線程池中 submit() 和 execute() 方法有什麼區別?
11. 什麼是線程組,爲何在 Java 中不推薦使用?
12. ThreadPoolExecutor飽和策略有哪些?、
13. 如何自定義線程線程池?
14. 線程池的執行原理?
15. 如何合理分配線程池大小?
4、併發容器
1. 你常用什麼併發容器,爲何?
2. 什麼是Vector
3. ArrayList和Vector有什麼不一樣之處?
4. 爲何HashTable是線程安全的?
5. 用過ConcurrentHashMap,講一下他和HashTable的不一樣之處?
6. Collections.synchronized * 是什麼?
7. Java 中 ConcurrentHashMap 的併發度是什麼?
8. 什麼是併發容器的實現?
9. Java 中的同步集合與併發集合有什麼區別?
10. SynchronizedMap 和 ConcurrentHashMap 有什麼區別?
11. CopyOnWriteArrayList 是什麼?
12. CopyOnWriteArrayList 的使用場景?
13. CopyOnWriteArrayList 的缺點?
14. CopyOnWriteArrayList 的設計思想?
5、併發隊列
1. 什麼是併發隊列:
- 消息隊列不少人知道:消息隊列是分佈式系統中重要的組件,是系統與系統直接的通訊
- 併發隊列是什麼:併發隊列多個線程以有次序共享數據的重要組件
2. 併發隊列和併發集合的區別:
- 隊列遵循「先進先出」的規則,能夠想象成排隊檢票,隊列通常用來解決大數據量採集處理和顯示 的。
- 併發集合就是在多個線程中共享數據的
3. 怎麼判斷併發隊列是阻塞隊列仍是非阻塞隊列
在併發隊列上JDK提供了Queue接口,一個是以Queue接口下的BlockingQueue接口爲表明的阻塞 隊列,另外一個是高性能(無堵塞)隊列。
4. 阻塞隊列和非阻塞隊列區別
- 當隊列阻塞隊列爲空的時,從隊列中獲取元素的操做將會被阻塞。
- 或者當阻塞隊列是滿時,往隊列裏添加元素的操做會被阻塞。
- 或者試圖從空的阻塞隊列中獲取元素的線程將會被阻塞,直到其餘的線程往空的隊列插入新的元素。
- 試圖往已滿的阻塞隊列中添加新元素的線程一樣也會被阻塞,直到其餘的線程使隊列從新變得空閒起來
5. 經常使用併發列隊的介紹:
併發隊列的經常使用方法
6、併發工具類
1. 經常使用的併發工具類有哪些?
乾貨不夠多?小編這裏還整理了一份Java併發編程線程學習筆記分享給到你,
Java併發編程線程學習筆記
因爲篇幅有限,下面只展現部分併發編程內容。
第1 章 併發編程線程基礎
1.1 什麼是線程
1.2 線程建立與運行
1.3 線程通知與等待
1.4 等待線程執行終止的join 方法
1.5 讓線程睡眠的sleep 方法
1.6 讓出CPU 執行權的yield 方法
1.8 理解線程上下文切換
1.9 線程死鎖
1.10 守護線程與用戶線程
1.11 ThreadLocal
第2 章 併發編程的其餘基礎知識
2.1 什麼是多線程併發編程
2.2 爲何要進行多線程併發編程
2.3 Java 中的線程安全問題
2.4 Java 中共享變量的內存可見性問題
2.5 Java 中的synchronized 關鍵字
2.6 Java 中的volatile 關鍵字
2.7 Java 中的原子性操做
2.8 Java 中的CAS 操做
2.9 Unsafe 類
2.10 Java 指令重排序
2.11 僞共享
2.12 鎖的概述
2.13 總結
第3 章 Java 併發包中ThreadLocalRandom 類原理剖析
3.1 Random 類及其侷限性
3.2 ThreadLocalRandom
3.3 源碼分析
3.4 總結
第4 章 Java 併發包中原子操做類原理剖析
4.1 原子變量操做類
4.2 JDK 8 新增的原子操做類LongAdder
4.3 LongAccumulator 類原理探究
4.4 總結
第5 章 Java 併發包中併發List 源碼剖析
5.1 介紹
5.2 主要方法源碼解析
5.3 總結
第6 章 Java 併發包中鎖原理剖析
6.1 LockSupport 工具類
6.2 抽象同步隊列AQS 概述
6.3 獨佔鎖ReentrantLock 的原理
6.4 讀寫鎖ReentrantReadWriteLock 的原理
6.5 JDK 8 中新增的StampedLock 鎖探究
第7 章 Java 併發包中併發隊列原理剖析
7.1 ConcurrentLinkedQueue 原理探究
7.2 LinkedBlockingQueue 原理探究
7.3 ArrayBlockingQueue 原理探究
7.4 PriorityBlockingQueue 原理探究
7.5 DelayQueue 原理探究
第8 章 Java 併發包中線程池ThreadPoolExecutor 原理探究
8.1 介紹
8.2 類圖介紹
8.3 源碼分析
8.4 總結
第9 章 Java 併發包中ScheduledThreadPoolExecutor 原理探究
9.1 介紹
9.2 類圖介紹
9.3 原理剖析
9.3.2 scheduleWithFixedDelay(Runnable command,long initialDelay, long delay,
TimeUnit unit) 方法
9.3.3 scheduleAtFixedRate(Runnable command,long initialDelay,long period,
TimeUnit unit) 方法
9.4 總結
第10 章 Java 併發包中線程同步器原理剖析
10.1 CountDownLatch 原理剖析
10.2 迴環屏障CyclicBarrier原理探究
11.1 ArrayBlockingQueue的使用
11.2 Tomcat的NioEndPoint中ConcurrentLinkedQueue的使用
11.3 併發組件ConcurrentHashMap使用注意事項
11.4 SimpleDateFormat是線程不安全的
11.5 使用Timer時須要注意的事情
11.6 對須要複用可是會被下游修改的參數要進行深複製
11.7 建立線程和線程池時要指定與業務相關的名稱
11.8 使用線程池的狀況下當程序結束時記得調用shutdown關閉線程池
11.9 線程池使用FutureTask時須要注意的事情
11.10 使用ThreadLocal不當可能會致使內存泄漏
11.11 總結
因爲篇幅有限,獲取完整面試題和答案解析能夠關注公種浩:麒麟改 bug,獲取。