1. 程式人生 > 程式設計 >2019年Java併發精選面試題,哪些你還不會?(含答案和思維導圖)

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

Java 併發程式設計

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 執行緒數過多會造成什麼異常?

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

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、執行緒的狀態流轉圖

執行緒的生命週期及五種基本狀態:

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 為使用提供了底層支撐,如何組裝實現,使用者可以自由發揮。

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 之後,作業系統會根據執行緒優先順序、執行緒飢餓情況等資料算出一個總的優先順序並分配下一個時間片給某個執行緒執行。

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檔案,歡迎大家關注我的公種浩【程式設計師追風】,文章都會在裡面更新,整理的資料也會放在裡面。



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

最後

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