首頁  >  文章  >  Java  >  Java線程面試題的相關知識點有哪些?

Java線程面試題的相關知識點有哪些?

WBOY
WBOY轉載
2023-04-23 23:07:061043瀏覽

Java線程面試題的相關知識點有哪些?

一、sychronied 修飾普通方法和靜態方法的差別?什麼是可見性?

物件鎖是用於物件實例方法,或一個物件實例上的,類別鎖是用於類別的靜態方法或一個類別的 class 物件上的。我們知道,類別的物件實例可以有很多個,但是每個類別只有一個 class 對象,所以不同物件實例的物件鎖是互不干擾的,但是每個類別只有一個類別鎖。
       有一點必須注意的是,其實類別鎖定只是一個概念上的東西,並不是真實存 在的,類別鎖其實鎖的是每個類別的對應的 class 物件。類鎖和物件鎖之間也是互不干擾的。
       可見性是指當多個執行緒存取同一個變數時,一個執行緒修改了這個變數的值,其他執行緒能夠立即看得到修改的值。
       由於線程對變量的所有操作都必須在工作內存中進行,而不能直接讀寫主內存中的變量,那麼對於共享變量V,它們首先是在自己的工作內存,之後再同步到主內存。可是並不會及時的刷到主記憶體中,而是會有一定時間差。很明顯,這個時候線程 A 對變數 V 的操作對於線程 B 而言就不具備可見性了 。
       要解決共享物件可見性這個問題,我們可以使用 volatile 關鍵字或是加鎖。

二、鎖分為哪幾類。

Java線程面試題的相關知識點有哪些?

三、CAS 無鎖定程式設計的原理。

使用目前的處理器基本上都支援CAS()的指令,只不過每個廠商所實現的演算法並不一樣,每一個CAS 操作過程都包含三個運算子:一個記憶體位址V,一個期望的值A 和一個新值B,操作的時候如果這個位址上存放的值等於這個期望的值A,則將位址上的值賦為新值B,否則不做任何操作。
       CAS 的基本想法是,如果這個位址上的值和期望的值相等,則給其賦予新值, 否則不做任何事兒,但是要傳回原值是多少。循環 CAS 就是在一個循環裡不斷的 做 cas 操作,直到成功為止。還可以說說 CAS 的三大問題。

四、ReentrantLock 的實作原理。

執行緒可以重複進入任何一個它已經擁有的鎖所同步著的程式碼區塊, synchronized、ReentrantLock 都是可重入的鎖。在實現上,就是線程每次獲取鎖時判定如果獲得鎖的線程是它自己時,簡單將計數器累積即可,每釋放一次鎖, 進行計數器累減,直到計算器歸零,表示線程已經徹底釋放鎖。底層則是利用了 JUC 中的 AQS 來實現的。

五、AQS 原理。

是用來建立鎖或其他同步元件的基礎框架,像是 ReentrantLock、 ReentrantReadWriteLock 和 CountDownLatch 就是基於 AQS 實現的。它使用了一 個 int 成員變數表示同步狀態,透過內建的 FIFO 佇列來完成資源取得執行緒的排隊工作。它是 CLH 隊列鎖的變體實作。它可以實現 2 種同步方式:獨佔式,共 享式。
       AQS 的主要使用方式是繼承,子類別透過繼承AQS 並實現它的抽象方法來管理同步狀態,同步器的設計是基於模板方法模式,所以如果要實現我們自己的同步工具類別就需要覆寫其中幾個可重寫的方法,如tryAcquire、tryReleaseShared 等等。
       這樣設計的目的是同步元件(例如鎖定)是使用者導向的,它定義了使用者與同步元件互動的介面(例如可以允許兩個執行緒並行存取),隱藏了實作細節;同步器面向的是鎖的實現者,它簡化了鎖的實作方式,屏蔽了同步狀態管理、執行緒的排隊、等待與喚醒等底層操作。這樣就很好地隔離了使用者和實作者所需關注的領域。
       在內部,AQS 維護一個共享資源 state,透過內建的 FIFO 來完成取得資源執行緒的排隊工作。這個佇列由一個一個的 Node 結點組成,每個 Node 結點維護一個 prev 引用和 next 引用,分別指向自己的前驅和後繼結點,構成一個雙端雙向鏈 表。

六、Synchronized 的原理以及與ReentrantLock 的區別。

synchronized (this)原理:涉及兩個指令:monitorenter,monitorexit;再說同步方法,從同步方法反編譯的結果來看,方法的同步並沒有透過指令monitorenter 和monitorexit 來實現,相對於普通方法,其常數池中多了ACC_SYNCHRONIZED 標示符。
       JVM 就是根據該標示符來實現方法的同步的:當方法被呼叫時,呼叫指令將會檢查方法的ACC_SYNCHRONIZED 存取標誌是否被設置,如果設定了,執行緒將先取得monitor,取得成功之後才能執行方法體,方法執行完後再釋放monitor。在方法執行期間,其他任何執行緒都無法再取得同一個 monitor 物件。

七、Synchronized 做了哪些優化

引入如自旋鎖、適應性自旋鎖、鎖消除、鎖粗化、偏向鎖、輕量級鎖、逃逸分析等技術來減少鎖定操作的開銷。

  • 逃逸分析:如果證明一個物件不會逃逸方法外或執行緒外,則可針對此變數進行最佳化:

  • #同步消除: synchronization Elimination,如果一個物件不會逃逸出線程,則對此變數的同步措施可消除。

  • 鎖定消除和粗化鎖消除:虛擬機的運行時編譯器在運行時如果檢測到一些要求同步的程式碼上不可能發生共享數據競爭,則會去掉這些鎖。

  • 鎖定粗化:將臨近的程式碼區塊用同一個鎖定合併。消除無意義的鎖定獲取和釋放,可以提高程式運作效能。

八、Synchronized static 與非 static 鎖定的差異與範圍。

物件鎖定是用於物件實例方法,或一個物件實例上的,類別鎖定是用於類別的靜態方法或一個類別的 class 物件上的。我們知道,類別的物件實例可以有很多個,但是每個類別只有一個 class 對象,所以不同物件實例的物件鎖是互不干擾的,但是每個類別只有一個類別鎖。
       有一點必須注意的是,其實類別鎖定只是一個概念上的東西,並不是真實存 在的,類別鎖其實鎖的是每個類別的對應的 class 物件。類鎖和物件鎖之間也是互不干擾的。

九、volatile 能否保證線程安全?在 DCL 上的作用是什麼?

不能保證,在DCL 的作用是:volatile 是會保證被修飾的變數的可見性和有序性, 保證了單例模式下,保證在創建物件的時候的執行順序一定是

  1. 分配記憶體空間

  2. 實例化物件instance

  3. 把instance 引用指向已分配的記憶體空間,此時instance 有了內存地址,不再為null 了的步驟, 從而保證了instance 要么為null 要么是已經完全初始化好的對象。

十、volatile 和 synchronize 有什麼差別?

volatile 是最輕量的同步機制。 volatile 保證了不同執行緒對這個變數進行操作時的可見性,即一個執行緒修改了某個變數的值,這新值對其他執行緒來說是立即可見的。但是 volatile 不能保證操作的原子性,因此多執行緒下的寫入複合操作會導致執行緒安全性問題。
       關鍵字synchronized 可以修飾方法或以同步區塊的形式來進行使用,它主要確保多個執行緒在同一個時刻,只能有一個執行緒處於方法或同步區塊中,它保證了執行緒對變數存取的可見性和排他性,又稱為內建鎖定機制。

十一、什麼是守護線程?你是如何退出一個執行緒的?

Daemon(守護)線程是一種支援型線程,因為它主要被用作程式中後台調度以及支援性工作。這意味著,當一個 Java 虛擬機器中不存在非 Daemon 執行緒的時候,Java 虛擬機器將會退出。可以透過呼叫 Thread.setDaemon(true)將執行緒設定為 Daemon 執行緒。我們通常用不上,例如垃圾回收線程就是 Daemon 線程。
       執行緒的中止:要麼是 run 執行完成了,要麼是拋出了一個未處理的例外狀況導致執行緒提前結束。暫停、恢復和停止操作對應在線程 Thread 的 API 就是 suspend()、resume()和 stop()。但是這些 API 是過期的,也就是不建議使用的。因為會導致程式可能工作在不確定狀態下。
       安全的中止則是其他執行緒透過呼叫某個執行緒A 的interrupt()方法對其進行中斷操作,被中斷的執行緒則是透過執行緒透過方法isInterrupted()來判斷是否被中斷, 也可以呼叫靜態方法Thread.interrupted()來進行判斷目前執行緒是否被中斷,不過Thread.interrupted()會同時將中斷識別位元改寫為false。

十二、sleep 、wait、yield 的區別,wait 的執行緒如何喚醒它?

yield()方法:讓目前執行緒讓出 CPU 佔有權,但讓出的時間是不可設定的。也不會釋放鎖定資源。所有執行 yield()的執行緒有可能在進入就緒狀態後會被作業系統再次選取馬上又被執行。
       yield() 、sleep()被呼叫後,都不會釋放目前執行緒所持有的鎖定。
       呼叫 wait()方法後,會釋放目前執行緒所持有的鎖定,而且目前被喚醒後,會重新去競爭鎖,鎖定競爭到後才會執行 wait 方法後面的程式碼。
       Wait 通常用於線程間交互,sleep 通常用於暫停執行,yield()方法使當前線程讓出 CPU 佔有權。
       wait 的執行緒使用 notify/notifyAll()來喚醒。

十三、sleep 是可中斷的麼?

sleep 本身就支援中斷,如果執行緒在 sleep 期間被中斷,則會拋出中斷例外。

十四、線程生命週期。

Java 中執行緒的狀態分為 6 種:

  1. 初始(NEW):新建立了一個執行緒對象,但還沒有呼叫 start()方法。

  2. 運行(RUNNABLE):Java 執行緒中將就緒(ready)和運行中(running)兩種狀態籠統的稱為「運行」。線程物件創建後,其他線程(例如 main 線程)呼叫了該物件的 start()方法。此狀態的執行緒位於可運行執行緒池中,等待被執行緒調度選中,取得 CPU 的使用權, 此時處於就緒狀態(ready)。就緒狀態的執行緒在獲得 CPU 時間片後變成運行 狀態(running)。

  3. 阻斷(BLOCKED):表示執行緒阻塞於鎖定。

  4. 等待(WAITING):進入該狀態的執行緒需要等待其他執行緒做出一些特定動作(通知或中斷)。

  5. 逾時等待(TIMED_WAITING):此狀態不同於 WAITING,它可以在指定的時 間後自行回傳。

  6. 終止(TERMINATED):表示該執行緒已經執行完畢。

Java線程面試題的相關知識點有哪些?

十五、ThreadLocal 是什麼?

ThreadLocal 是 Java 裡一種特殊的變數。 ThreadLocal 為每個線程都提供了變數的副本,使得每個線程在某一時間訪問到的並非同一個對象,這樣就隔離了多個線程對資料的資料共享。
       在內部實作上,每個執行緒內部都有一個 ThreadLocalMap,用來保存每個執行緒所擁有的變數副本。

十六、執行緒池基本原理。

在開發過程中,合理地使用執行緒池能夠帶來 3 個好處。
第一:降低資源消耗。
第二:提高反應速度。
第三:提高執行緒的可管理性。

  1. 如果目前執行的執行緒少於 corePoolSize,則建立新執行緒來執行任務(注意, 執行此步驟需要取得全域鎖定)。

  2. 如果執行的執行緒等於或多於 corePoolSize,則將任務加入 BlockingQueue。

  3. 如果無法將任務加入 BlockingQueue(佇列已滿),則建立新的執行緒來處理任務。

  4. 如果建立新執行緒將使目前執行的執行緒超出 maximumPoolSize,任務將被拒絕,並呼叫 RejectedExecutionHandler.rejectedExecution()方法。

十七、有三個執行緒 T1,T2,T3,怎麼確保它們按順序執行?

可以用 join 方法實作。

以上是Java線程面試題的相關知識點有哪些?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除