2019年Java併發精選面試題,哪些你還不會?(含答案和思維導圖)

Java 併發編程

v2-3d43b51b56e806d01bb8eee4451002c7_hd.jpg

1、併發編程三要素?

2、實現可見性的方法有哪些?

3、多線程的價值?

4、創建線程的有哪些方式?

5、創建線程的三種方式的對比?

6、線程的狀態流轉圖

7、Java 線程具有五中基本狀態

8、什麼是線程池?有哪幾種創建方式?

9、四種線程池的創建:

10、線程池的優點?

11、常用的併發工具類有哪些?

12、CyclicBarrier 和 CountDownLatch 的區別

13、synchronized 的作用?

14、volatile 關鍵字的作用

15、什麼是 CAS

16、CAS 的問題

17、什麼是 Future?

18、什麼是 AQS

19、AQS 支持兩種同步方式:

20、ReadWriteLock 是什麼

21、FutureTask 是什麼

22、synchronized 和 ReentrantLock 的區別

23、什麼是樂觀鎖和悲觀鎖

24、線程 B 怎麼知道線程 A 修改了變量

25、synchronized、volatile、CAS 比較

26、sleep 方法和 wait 方法有什麼區別?

27、ThreadLocal 是什麼?有什麼用?

28、爲什麼 wait()方法和 notify()/notifyAll()方法要在同步塊中被調用

29、多線程同步有哪幾種方法?

30、線程的調度策略

31、ConcurrentHashMap 的併發度是什麼

32、Linux 環境下如何查找哪個線程使用 CPU 最長

33、Java 死鎖以及如何避免?

34、死鎖的原因

35、怎麼喚醒一個阻塞的線程

36、不可變對象對多線程有什麼幫助

37、什麼是多線程的上下文切換

38、如果你提交任務時,線程池隊列已滿,這時會發生什麼

39、Java 中用到的線程調度算法是什麼

40 、 什 麼 是 線 程 調 度 器 (Thread Scheduler) 和 時 間 分 片 (TimeSlicing)?

41、什麼是自旋

42、Java Concurrency API 中的 Lock 接口(Lock interface)是什麼?對比同步它有什麼優勢?

43、單例模式的線程安全性

44、Semaphore 有什麼作用

45、Executors 類是什麼?

46、線程類的構造方法、靜態塊是被哪個線程調用的

47、同步方法和同步塊,哪個是更好的選擇?

48、Java 線程數過多會造成什麼異常?


併發編程的知識點整理了一個思維導圖

v2-81c0c0b77202bb79dc8c3334ae554da1_hd.jpg

1、併發編程三要素?

(1)原子性

原子性指的是一個或者多個操作,要麼全部執行並且在執行的過程中不被其他操作打斷,要麼就全部都不執行。

(2)可見性

可見性指多個線程操作一個共享變量時,其中一個線程對變量進行修改後,其他線程可以立即看到修改的結果。

(3)有序性

有序性,即程序的執行順序按照代碼的先後順序來執行。

2、實現可見性的方法有哪些?

synchronized 或者 Lock:保證同一個時刻只有一個線程獲取鎖執行代碼,鎖釋放之前把最新的值刷新到主內存,實現可見性。

3、多線程的價值?

(1)發揮多核 CPU 的優勢

多線程,可以真正發揮出多核 CPU 的優勢來,達到充分利用 CPU 的目的,採用多線程的方式去同時完成幾件事情而不互相干擾。

(2)防止阻塞

從程序運行效率的角度來看,單核 CPU 不但不會發揮出多線程的優勢,反而會因爲在單核 CPU 上運行多線程導致線程上下文的切換,而降低程序整體的效率。但是單核 CPU 我們還是要應用多線程,就是爲了防止阻塞。試想,如果單核 CPU 使用單線程,那麼只要這個線程阻塞了,比方說遠程讀取某個數據吧,對端遲遲未返回又沒有設置超時時間,那麼你的整個程序在數據返回來之前就停止運行了。多線程可以防止這個問題,多條線程同時運行,哪怕一條線程的代碼執行讀取數據阻塞,也不會影響其它任務的執行。

(3)便於建模

這是另外一個沒有這麼明顯的優點了。假設有一個大的任務 A,單線程編程,那麼就要考慮很多,建立整個程序模型比較麻煩。但是如果把這個大的任務 A 分解成幾個小任務,任務 B、任務 C、任務 D,分別建立程序模型,並通過多線程分別運行這幾個任務,那就簡單很多了。

4、創建線程的有哪些方式?

(1)繼承 Thread 類創建線程類

(2)通過 Runnable 接口創建線程類

(3)通過 Callable 和 Future 創建線程

(4)通過線程池創建

5、創建線程的三種方式的對比?

(1)採用實現 Runnable、Callable 接口的方式創建多線程。

優勢是:

線程類只是實現了 Runnable 接口或 Callable 接口,還可以繼承其他類。在這種方式下,多個線程可以共享同一個 target 對象,所以非常適合多個相同線程來處理同一份資源的情況,從而可以將 CPU、代碼和數據分開,形成清晰的模型,較好地體現了面向對象的思想。

劣勢是:

編程稍微複雜,如果要訪問當前線程,則必須使用 Thread.currentThread()方法。

(2)使用繼承 Thread 類的方式創建多線程

優勢是:

編寫簡單,如果需要訪問當前線程,則無需使用 Thread.currentThread()方法,直接使用 this 即可獲得當前線程。

劣勢是:

線程類已經繼承了 Thread 類,所以不能再繼承其他父類。

(3)Runnable 和 Callable 的區別

1、Callable 規定(重寫)的方法是 call(),Runnable 規定(重寫)的方法是 run()。

2、Callable 的任務執行後可返回值,而 Runnable 的任務是不能返回值的。

3、Call 方法可以拋出異常,run 方法不可以。

4、運行 Callable 任務可以拿到一個 Future 對象,表示異步計算的結果。它提供了檢查計算是否完成的方法,以等待計算的完成,並檢索計算的結果。通過 Future對象可以瞭解任務執行情況,可取消任務的執行,還可獲取執行結果。

6、線程的狀態流轉圖

線程的生命週期及五種基本狀態:

v2-983ddfcc4df887736526505fdcb1ad25_hd.jpg


7、Java 線程具有五中基本狀態

(1)新建狀態(New):當線程對象對創建後,即進入了新建狀態,如:Thread t= new MyThread();

(2)就緒狀態(Runnable):當調用線程對象的 start()方法(t.start();),線程即進入就緒狀態。處於就緒狀態的線程,只是說明此線程已經做好了準備,隨時等待 CPU 調度執行,並不是說執行了t.start()此線程立即就會執行;

(3)運行狀態(Running):當 CPU 開始調度處於就緒狀態的線程時,此時線程才得以真正執行,即進入到運行狀態。注:就 緒狀態是進入到運行狀態的唯一入口,也就是說,線程要想進入運行狀態執行,首先必須處於就緒狀態中;

(4)阻塞狀態(Blocked):處於運行狀態中的線程由於某種原因,暫時放棄對 CPU的使用權,停止執行,此時進入阻塞狀態,直到其進入到就緒狀態,才 有機會再次被 CPU 調用以進入到運行狀態。

根據阻塞產生的原因不同,阻塞狀態又可以分爲三種:

1)等待阻塞:運行狀態中的線程執行 wait()方法,使本線程進入到等待阻塞狀態;

2)同步阻塞:線程在獲取 synchronized 同步鎖失敗(因爲鎖被其它線程所佔用),

它會進入同步阻塞狀態;

3)其他阻塞:通過調用線程的 sleep()或 join()或發出了 I/O 請求時,線程會進入到阻塞狀態。當 sleep()狀態超時、join()等待線程終止或者超時、或者 I/O 處理完畢時,線程重新轉入就緒狀態。

(5)死亡狀態(Dead):線程執行完了或者因異常退出了 run()方法,該線程結束生命週期。

8、什麼是線程池?有哪幾種創建方式?

線程池就是提前創建若干個線程,如果有任務需要處理,線程池裏的線程就會處理任務,處理完之後線程並不會被銷燬,而是等待下一個任務。由於創建和銷燬線程都是消耗系統資源的,所以當你想要頻繁的創建和銷燬線程的時候就可以考慮使用線程池來提升系統的性能。

java 提供了一個 java.util.concurrent.Executor 接口的實現用於創建線程池。

9、四種線程池的創建:

(1)newCachedThreadPool 創建一個可緩存線程池

(2)newFixedThreadPool 創建一個定長線程池,可控制線程最大併發數。

(3)newScheduledThreadPool 創建一個定長線程池,支持定時及週期性任務執行。

(4)newSingleThreadExecutor 創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務。

10、線程池的優點?

(1)重用存在的線程,減少對象創建銷燬的開銷。

(2)可有效的控制最大併發線程數,提高系統資源的使用率,同時避免過多資源競爭,避免堵塞。

(3)提供定時執行、定期執行、單線程、併發數控制等功能。

11、常用的併發工具類有哪些?

(1)CountDownLatch

(2)CyclicBarrier

(3)Semaphore

(4)Exchanger

12、CyclicBarrier 和 CountDownLatch 的區別

(1)CountDownLatch 簡單的說就是一個線程等待,直到他所等待的其他線程都執行完成並且調用 countDown()方法發出通知後,當前線程纔可以繼續執行。

(2)cyclicBarrier 是所有線程都進行等待,直到所有線程都準備好進入 await()方法之後,所有線程同時開始執行!

(3)CountDownLatch 的計數器只能使用一次。而 CyclicBarrier 的計數器可以使用 reset() 方法重置。所以 CyclicBarrier 能處理更爲複雜的業務場景,比如如果計算髮生錯誤,可以重置計數器,並讓線程們重新執行一次。

(4)CyclicBarrier 還提供其他有用的方法,比如 getNumberWaiting 方法可以獲得 CyclicBarrier 阻塞的線程數量。isBroken 方法用來知道阻塞的線程是否被中斷。如果被中斷返回 true,否則返回 false。

13、synchronized 的作用?

在 Java 中,synchronized 關鍵字是用來控制線程同步的,就是在多線程的環境下,控制 synchronized 代碼段不被多個線程同時執行。synchronized 既可以加在一段代碼上,也可以加在方法上。

14、volatile 關鍵字的作用

對於可見性,Java 提供了 volatile 關鍵字來保證可見性。當一個共享變量被 volatile 修飾時,它會保證修改的值會立即被更新到主存,當有其他線程需要讀取時,它會去內存中讀取新值。從實踐角度而言,volatile 的一個重要作用就是和 CAS 結合,保證了原子性,詳細的可以參見 java.util.concurrent.atomic 包下的類,比如 AtomicInteger。

15、什麼是 CAS

CAS 是 compare and swap 的縮寫,即我們所說的比較交換。

cas 是一種基於鎖的操作,而且是樂觀鎖。在 java 中鎖分爲樂觀鎖和悲觀鎖。悲觀鎖是將資源鎖住,等一個之前獲得鎖的線程釋放鎖之後,下一個線程纔可以訪問。而樂觀鎖採取了一種寬泛的態度,通過某種方式不加鎖來處理資源,比如通過給記錄加 version 來獲取數據,性能較悲觀鎖有很大的提高。

CAS 操作包含三個操作數 —— 內存位置(V)、預期原值(A)和新值(B)。如果內存地址裏面的值和 A 的值是一樣的,那麼就將內存裏面的值更新成 B。CAS是通過無限循環來獲取數據的,若果在第一輪循環中,a 線程獲取地址裏面的值被b 線程修改了,那麼 a 線程需要自旋,到下次循環纔有可能機會執行。

java.util.concurrent.atomic 包下的類大多是使用 CAS 操作來實現的(AtomicInteger,AtomicBoolean,AtomicLong)。

16、CAS 的問題

(1)CAS 容易造成 ABA 問題

一個線程 a 將數值改成了 b,接着又改成了 a,此時 CAS 認爲是沒有變化,其實是已經變化過了,而這個問題的解決方案可以使用版本號標識,每操作一次version 加 1。在 java5 中,已經提供了 AtomicStampedReference 來解決問題。

(2)不能保證代碼塊的原子性

CAS 機制所保證的知識一個變量的原子性操作,而不能保證整個代碼塊的原子性。比如需要保證 3 個變量共同進行原子性的更新,就不得不使用 synchronized 了。

(3)CAS 造成 CPU 利用率增加

之前說過了 CAS 裏面是一個循環判斷的過程,如果線程一直沒有獲取到狀態,cpu資源會一直被佔用。

17、什麼是 Future?

在併發編程中,我們經常用到非阻塞的模型,在之前的多線程的三種實現中,不管是繼承 thread 類還是實現 runnable 接口,都無法保證獲取到之前的執行結果。通過實現 Callback 接口,並用 Future 可以來接收多線程的執行結果。

Future 表示一個可能還沒有完成的異步任務的結果,針對這個結果可以添加Callback 以便在任務執行成功或失敗後作出相應的操作。

18、什麼是 AQS

AQS 是 AbustactQueuedSynchronizer 的簡稱,它是一個 Java 提高的底層同步工具類,用一個 int 類型的變量表示同步狀態,並提供了一系列的 CAS 操作來管理這個同步狀態。

AQS 是一個用來構建鎖和同步器的框架,使用 AQS 能簡單且高效地構造出應用廣泛的大量的同步器,比如我們提到的 ReentrantLock,Semaphore,其他的諸如ReentrantReadWriteLock,SynchronousQueue,FutureTask 等等皆是基於AQS 的。

19、AQS 支持兩種同步方式:

(1)獨佔式

(2)共享式

這樣方便使用者實現不同類型的同步組件,獨佔式如 ReentrantLock,共享式如Semaphore,CountDownLatch,組 合 式 的 如 ReentrantReadWriteLock。總之,AQS 爲使用提供了底層支撐,如何組裝實現,使用者可以自由發揮。

v2-c0e09b46c01e2d651fe54967d21026e4_hd.png

20、ReadWriteLock 是什麼

首先明確一下,不是說 ReentrantLock 不好,只是 ReentrantLock 某些時候有侷限。如果使用 ReentrantLock,可能本身是爲了防止線程 A 在寫數據、線程 B 在讀數據造成的數據不一致,但這樣,如果線程 C 在讀數據、線程 D 也在讀數據,讀數據是不會改變數據的,沒有必要加鎖,但是還是加鎖了,降低了程序的性能。因爲這個,才誕生了讀寫鎖 ReadWriteLock。ReadWriteLock 是一個讀寫鎖接口,ReentrantReadWriteLock 是 ReadWriteLock 接口的一個具體實現,實現了讀寫的分離,讀鎖是共享的,寫鎖是獨佔的,讀和讀之間不會互斥,讀和寫、寫和讀、寫和寫之間纔會互斥,提升了讀寫的性能。

21、FutureTask 是什麼

這個其實前面有提到過,FutureTask 表示一個異步運算的任務。FutureTask 裏面可以傳入一個 Callable 的具體實現類,可以對這個異步運算的任務的結果進行等待獲取、判斷是否已經完成、取消任務等操作。當然,由於 FutureTask 也是Runnable 接口的實現類,所以 FutureTask 也可以放入線程池中。

22、synchronized 和 ReentrantLock 的區別

synchronized 是和 if、else、for、while 一樣的關鍵字,ReentrantLock 是類,這是二者的本質區別。既然 ReentrantLock 是類,那麼它就提供了比synchronized 更多更靈活的特性,可以被繼承、可以有方法、可以有各種各樣的類變量,ReentrantLock 比 synchronized 的擴展性體現在幾點上:

(1)ReentrantLock 可以對獲取鎖的等待時間進行設置,這樣就避免了死鎖

(2)ReentrantLock 可以獲取各種鎖的信息

(3)ReentrantLock 可以靈活地實現多路通知

另外,二者的鎖機制其實也是不一樣的。ReentrantLock 底層調用的是 Unsafe 的park 方法加鎖,synchronized 操作的應該是對象頭中 mark word,這點我不能確定。

23、什麼是樂觀鎖和悲觀鎖

(1)樂觀鎖:就像它的名字一樣,對於併發間操作產生的線程安全問題持樂觀狀態,樂觀鎖認爲競爭不總是會發生,因此它不需要持有鎖,將比較-替換這兩個動作作爲一個原子操作嘗試去修改內存中的變量,如果失敗則表示發生衝突,那麼就應該有相應的重試邏輯。

(2)悲觀鎖:還是像它的名字一樣,對於併發間操作產生的線程安全問題持悲觀狀態,悲觀鎖認爲競爭總是會發生,因此每次對某資源進行操作時,都會持有一個獨佔的鎖,就像 synchronized,不管三七二十一,直接上了鎖就操作資源了。

24、線程 B 怎麼知道線程 A 修改了變量

(1)volatile 修飾變量

(2)synchronized 修飾修改變量的方法

(3)wait/notify

(4)while 輪詢

25、synchronized、volatile、CAS 比較

(1)synchronized 是悲觀鎖,屬於搶佔式,會引起其他線程阻塞。

(2)volatile 提供多線程共享變量可見性和禁止指令重排序優化。

(3)CAS 是基於衝突檢測的樂觀鎖(非阻塞)

26、sleep 方法和 wait 方法有什麼區別?

這個問題常問,sleep 方法和 wait 方法都可以用來放棄 CPU 一定的時間,不同點在於如果線程持有某個對象的監視器,sleep 方法不會放棄這個對象的監視器,wait 方法會放棄這個對象的監視器

27、ThreadLocal 是什麼?有什麼用?

ThreadLocal 是一個本地線程副本變量工具類。主要用於將私有線程和該線程存放的副本對象做一個映射,各個線程之間的變量互不干擾,在高併發場景下,可以實現無狀態的調用,特別適用於各個線程依賴不通的變量值完成操作的場景。簡單說 ThreadLocal 就是一種以空間換時間的做法,在每個 Thread 裏面維護了一個以開地址法實現的 ThreadLocal.ThreadLocalMap,把數據進行隔離,數據不共享,自然就沒有線程安全方面的問題了。

28、爲什麼 wait()方法和 notify()/notifyAll()方法要在同步塊中被調用

這是 JDK 強制的,wait()方法和 notify()/notifyAll()方法在調用前都必須先獲得對象的鎖

29、多線程同步有哪幾種方法?

Synchronized 關鍵字,Lock 鎖實現,分佈式鎖等。

30、線程的調度策略

線程調度器選擇優先級最高的線程運行,但是,如果發生以下情況,就會終止線程的運行:

(1)線程體中調用了 yield 方法讓出了對 cpu 的佔用權利

(2)線程體中調用了 sleep 方法使線程進入睡眠狀態

(3)線程由於 IO 操作受到阻塞

(4)另外一個更高優先級線程出現

(5)在支持時間片的系統中,該線程的時間片用完

31、ConcurrentHashMap 的併發度是什麼

ConcurrentHashMap 的併發度就是 segment 的大小,默認爲 16,這意味着最多同時可以有 16 條線程操作 ConcurrentHashMap,這也是ConcurrentHashMap 對 Hashtable 的最大優勢,任何情況下,Hashtable 能同時有兩條線程獲取 Hashtable 中的數據嗎?

32、Linux 環境下如何查找哪個線程使用 CPU 最長

(1)獲取項目的 pid,jps 或者 ps -ef | grep java

(2)top -H -p pid,順序不能改變

33、Java 死鎖以及如何避免?

Java 中的死鎖是一種編程情況,其中兩個或多個線程被永久阻塞,Java 死鎖情況出現至少兩個線程和兩個或更多資源。

Java 發生死鎖的根本原因是:在申請鎖時發生了交叉閉環申請。

34、死鎖的原因

(1)是多個線程涉及到多個鎖,這些鎖存在着交叉,所以可能會導致了一個鎖依賴的閉環。

例如:線程在獲得了鎖 A 並且沒有釋放的情況下去申請鎖 B,這時,另一個線程已經獲得了鎖 B,在釋放鎖 B 之前又要先獲得鎖 A,因此閉環發生,陷入死鎖循環。

(2)默認的鎖申請操作是阻塞的。

所以要避免死鎖,就要在一遇到多個對象鎖交叉的情況,就要仔細審查這幾個對象的類中的所有方法,是否存在着導致鎖依賴的環路的可能性。總之是儘量避免在一個同步方法中調用其它對象的延時方法和同步方法。

35、怎麼喚醒一個阻塞的線程

如果線程是因爲調用了 wait()、sleep()或 者 join()方法而導致的阻塞,可以中斷線程,並且通過拋出 InterruptedException 來喚醒它;如果線程遇到了 IO 阻塞,無能爲力,因爲 IO 是操作系統實現的,Java 代碼並沒有辦法直接接觸到操作系統。

36、不可變對象對多線程有什麼幫助

前面有提到過的一個問題,不可變對象保證了對象的內存可見性,對不可變對象的讀取不需要進行額外的同步手段,提升了代碼執行效率。

37、什麼是多線程的上下文切換

多線程的上下文切換是指 CPU 控制權由一個已經正在運行的線程切換到另外一個就緒並等待獲取 CPU 執行權的線程的過程。

38、如果你提交任務時,線程池隊列已滿,這時會發生什麼

這裏區分一下:

(1)如果使用的是***隊列 LinkedBlockingQueue,也就是***隊列的話,沒關係,繼續添加任務到阻塞隊列中等待執行,因爲 LinkedBlockingQueue 可以近乎認爲是一個無窮大的隊列,可以無限存放任務

(2)如果使用的是有界隊列比如 ArrayBlockingQueue,任務首先會被添加到ArrayBlockingQueue 中,ArrayBlockingQueue 滿了,會根據maximumPoolSize 的值增加線程數量,如果增加了線程數量還是處理不過來,ArrayBlockingQueue 繼續滿,那麼則會使用拒絕策略RejectedExecutionHandler 處理滿了的任務,默認是 AbortPolicy

39、Java 中用到的線程調度算法是什麼

搶佔式。一個線程用完 CPU 之後,操作系統會根據線程優先級、線程飢餓情況等數據算出一個總的優先級並分配下一個時間片給某個線程執行。

v2-9cc2e125f3dcbe9702827fb9850fff4f_hd.png

40、什麼是線程調度器(Thread Scheduler)和時間分片(TimeSlicing)?

線程調度器是一個操作系統服務,它負責爲 Runnable 狀態的線程分配 CPU 時間。一旦我們創建一個線程並啓動它,它的執行便依賴於線程調度器的實現。時間分片是指將可用的 CPU 時間分配給可用的 Runnable 線程的過程。分配 CPU 時間可以基於線程優先級或者線程等待的時間。線程調度並不受到 Java 虛擬機控制,所以由應用程序來控制它是更好的選擇(也就是說不要讓你的程序依賴於線程的優先級)。

41、什麼是自旋

很多 synchronized 裏面的代碼只是一些很簡單的代碼,執行時間非常快,此時等待的線程都加鎖可能是一種不太值得的操作,因爲線程阻塞涉及到用戶態和內核態切換的問題。既然 synchronized 裏面的代碼執行得非常快,不妨讓等待鎖的線程不要被阻塞,而是在 synchronized 的邊界做忙循環,這就是自旋。如果做了多次忙循環發現還沒有獲得鎖,再阻塞,這樣可能是一種更好的策略。

42、Java Concurrency API 中的 Lock 接口(Lock interface)是什麼?對比同步它有什麼優勢?

Lock 接口比同步方法和同步塊提供了更具擴展性的鎖操作。他們允許更靈活的結構,可以具有完全不同的性質,並且可以支持多個相關類的條件對象。

它的優勢有:

(1)可以使鎖更公平

(2)可以使線程在等待鎖的時候響應中斷

(3)可以讓線程嘗試獲取鎖,並在無法獲取鎖的時候立即返回或者等待一段時間

(4)可以在不同的範圍,以不同的順序獲取和釋放鎖

43、單例模式的線程安全性

老生常談的問題了,首先要說的是單例模式的線程安全意味着:某個類的實例在多線程環境下只會被創建一次出來。單例模式有很多種的寫法,我總結一下:

(1)餓漢式單例模式的寫法:線程安全

(2)懶漢式單例模式的寫法:非線程安全

(3)雙檢鎖單例模式的寫法:線程安全

44、Semaphore 有什麼作用

Semaphore 就是一個信號量,它的作用是限制某段代碼塊的併發數。Semaphore有一個構造函數,可以傳入一個 int 型整數 n,表示某段代碼最多隻有 n 個線程可以訪問,如果超出了 n,那麼請等待,等到某個線程執行完畢這段代碼塊,下一個線程再進入。由此可以看出如果 Semaphore 構造函數中傳入的 int 型整數 n=1,相當於變成了一個 synchronized 了。

45、Executors 類是什麼?

Executors 爲 Executor,ExecutorService,ScheduledExecutorService,ThreadFactory 和 Callable 類提供了一些工具方法。Executors 可以用於方便的創建線程池

46、線程類的構造方法、靜態塊是被哪個線程調用的

這是一個非常刁鑽和狡猾的問題。請記住:線程類的構造方法、靜態塊是被 new這個線程類所在的線程所調用的,而 run 方法裏面的代碼纔是被線程自身所調用的。

如果說上面的說法讓你感到困惑,那麼我舉個例子,假設 Thread2 中 new 了Thread1,main 函數中 new 了 Thread2,那麼:

(1)Thread2 的構造方法、靜態塊是 main 線程調用的,Thread2 的 run()方法是Thread2 自己調用的

(2)Thread1 的構造方法、靜態塊是 Thread2 調用的,Thread1 的 run()方法是Thread1 自己調用的

47、同步方法和同步塊,哪個是更好的選擇?

同步塊,這意味着同步塊之外的代碼是異步執行的,這比同步整個方法更提升代碼的效率。請知道一條原則:同步的範圍越小越好。

48、Java 線程數過多會造成什麼異常?

(1)線程的生命週期開銷非常高

(2)消耗過多的 CPU 資源

如果可運行的線程數量多於可用處理器的數量,那麼有線程將會被閒置。大量空閒的線程會佔用許多內存,給垃圾回收器帶來壓力,而且大量的線程在競爭 CPU資源時還將產生其他性能的開銷。

(3)降低穩定性

JVM 在可創建線程的數量上存在一個限制,這個限制值將隨着平臺的不同而不同,並且承受着多個因素制約,包括 JVM 的啓動參數、Thread 構造函數中請求棧的大小,以及底層操作系統對線程的限制等。如果破壞了這些限制,那麼可能拋出OutOfMemoryError 異常。

耗時1個月時間,整理了1000道2019年多家公司java面試題400多頁pdf文檔,歡迎大家關注我的公種浩【程序員追風】,文章都會在裏面更新,整理的資料也會放在裏面。

v2-186d0574ffdf9d5bf6a4ca6595dc15c0_hd.jpg

v2-4f6dc1696b8858d2a8e3014d99c51f56_hd.jpg

針對於上面的面試問到的知識點我總結出了互聯網公司Java程序員面試涉及到的絕大部分面試題及答案做成了文檔和架構資料分享給大家,家希望能幫助到您面試前的複習且找到一個好的工作,也節省大家在網上搜索資料的時間來學習。

最後

歡迎大家一起交流,整理資料不易,喜歡文章記得關注我點個贊喲,感謝支持!


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章