溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Java線程面試題的知識點(diǎn)有哪些

發(fā)布時(shí)間:2022-06-30 09:14:42 來源:億速云 閱讀:163 作者:iii 欄目:編程語言

本篇內(nèi)容主要講解“Java線程面試題的知識點(diǎn)有哪些”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“Java線程面試題的知識點(diǎn)有哪些”吧!

Java線程面試題的知識點(diǎn)有哪些

一、sychronied 修飾普通方法和靜態(tài)方法的區(qū)別?什么是可見性?

對象鎖是用于對象實(shí)例方法,或者一個(gè)對象實(shí)例上的,類鎖是用于類的靜態(tài)方法或者一個(gè)類的 class 對象上的。我們知道,類的對象實(shí)例可以有很多個(gè),但是每個(gè)類只有一個(gè) class 對象,所以不同對象實(shí)例的對象鎖是互不干擾的,但是每個(gè)類只有一個(gè)類鎖。
       有一點(diǎn)必須注意的是,其實(shí)類鎖只是一個(gè)概念上的東西,并不是真實(shí)存 在的,類鎖其實(shí)鎖的是每個(gè)類的對應(yīng)的 class 對象。類鎖和對象鎖之間也是互不干擾的。
       可見性是指當(dāng)多個(gè)線程訪問同一個(gè)變量時(shí),一個(gè)線程修改了這個(gè)變量的值,其他線程能夠立即看得到修改的值。
       由于線程對變量的所有操作都必須在工作內(nèi)存中進(jìn)行,而不能直接讀寫主內(nèi)存中的變量,那么對于共享變量 V,它們首先是在自己的工作內(nèi)存,之后再同步到主內(nèi)存??墒遣⒉粫皶r(shí)的刷到主存中,而是會有一定時(shí)間差。很明顯,這個(gè)時(shí)候線程 A 對變量 V 的操作對于線程 B 而言就不具備可見性了 。
       要解決共享對象可見性這個(gè)問題,我們可以使用 volatile 關(guān)鍵字或者是加鎖。

二、鎖分為哪幾類。

Java線程面試題的知識點(diǎn)有哪些

三、CAS 無鎖編程的原理。

使用當(dāng)前的處理器基本都支持 CAS()的指令,只不過每個(gè)廠家所實(shí)現(xiàn)的算法并不一樣,每一個(gè) CAS 操作過程都包含三個(gè)運(yùn)算符:一個(gè)內(nèi)存地址 V,一個(gè)期望的值 A 和一個(gè)新值 B,操作的時(shí)候如果這個(gè)地址上存放的值等于這個(gè)期望的值 A,則將地址上的值賦為新值 B,否則不做任何操作。
       CAS 的基本思路就是,如果這個(gè)地址上的值和期望的值相等,則給其賦予新值, 否則不做任何事兒,但是要返回原值是多少。循環(huán) CAS 就是在一個(gè)循環(huán)里不斷的 做 cas 操作,直到成功為止。 還可以說說 CAS 的三大問題。

四、ReentrantLock 的實(shí)現(xiàn)原理。

線程可以重復(fù)進(jìn)入任何一個(gè)它已經(jīng)擁有的鎖所同步著的代碼塊, synchronized、ReentrantLock 都是可重入的鎖。在實(shí)現(xiàn)上,就是線程每次獲取鎖時(shí)判定如果獲得鎖的線程是它自己時(shí),簡單將計(jì)數(shù)器累積即可,每釋放一次鎖, 進(jìn)行計(jì)數(shù)器累減,直到計(jì)算器歸零,表示線程已經(jīng)徹底釋放鎖。底層則是利用了 JUC 中的 AQS 來實(shí)現(xiàn)的。

五、AQS 原理。

是用來構(gòu)建鎖或者其他同步組件的基礎(chǔ)框架,比如 ReentrantLock、 ReentrantReadWriteLock 和 CountDownLatch 就是基于 AQS 實(shí)現(xiàn)的。它使用了一 個(gè) int 成員變量表示同步狀態(tài),通過內(nèi)置的 FIFO 隊(duì)列來完成資源獲取線程的排隊(duì)工作。它是 CLH 隊(duì)列鎖的一種變體實(shí)現(xiàn)。它可以實(shí)現(xiàn) 2 種同步方式:獨(dú)占式,共 享式。
       AQS 的主要使用方式是繼承,子類通過繼承 AQS 并實(shí)現(xiàn)它的抽象方法來管理同步狀態(tài),同步器的設(shè)計(jì)基于模板方法模式,所以如果要實(shí)現(xiàn)我們自己的同步工具類就需要覆蓋其中幾個(gè)可重寫的方法,如 tryAcquire、tryReleaseShared 等等。
       這樣設(shè)計(jì)的目的是同步組件(比如鎖)是面向使用者的,它定義了使用者與同步組件交互的接口(比如可以允許兩個(gè)線程并行訪問),隱藏了實(shí)現(xiàn)細(xì)節(jié);同步器面向的是鎖的實(shí)現(xiàn)者,它簡化了鎖的實(shí)現(xiàn)方式,屏蔽了同步狀態(tài)管理、線程的排隊(duì)、等待與喚醒等底層操作。這樣就很好地隔離了使用者和實(shí)現(xiàn)者所需關(guān)注的領(lǐng)域。
       在內(nèi)部,AQS 維護(hù)一個(gè)共享資源 state,通過內(nèi)置的 FIFO 來完成獲取資源線程的排隊(duì)工作。該隊(duì)列由一個(gè)一個(gè)的 Node 結(jié)點(diǎn)組成,每個(gè) Node 結(jié)點(diǎn)維護(hù)一個(gè) prev 引用和 next 引用,分別指向自己的前驅(qū)和后繼結(jié)點(diǎn),構(gòu)成一個(gè)雙端雙向鏈 表。

六、Synchronized 的原理以及與ReentrantLock 的區(qū)別。

synchronized (this)原理:涉及兩條指令:monitorenter,monitorexit;再說同步方法,從同步方法反編譯的結(jié)果來看,方法的同步并沒有通過指令 monitorenter 和 monitorexit 來實(shí)現(xiàn),相對于普通方法,其常量池中多了 ACC_SYNCHRONIZED 標(biāo)示符。
       JVM 就是根據(jù)該標(biāo)示符來實(shí)現(xiàn)方法的同步的:當(dāng)方法被調(diào)用時(shí),調(diào)用指令將會檢查方法的 ACC_SYNCHRONIZED 訪問標(biāo)志是否被設(shè)置,如果設(shè)置了,執(zhí)行線程將先獲取 monitor,獲取成功之后才能執(zhí)行方法體,方法執(zhí)行完后再釋放 monitor。在方法執(zhí)行期間,其他任何線程都無法再獲得同一個(gè) monitor 對象。

七、Synchronized 做了哪些優(yōu)化

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

  • 逃逸分析:如果證明一個(gè)對象不會逃逸方法外或者線程外,則可針對此變量進(jìn)行優(yōu)化:

  • 同步消除: synchronization Elimination,如果一個(gè)對象不會逃逸出線程,則對此變量的同步措施可消除。

  • 鎖消除和粗化鎖消除:虛擬機(jī)的運(yùn)行時(shí)編譯器在運(yùn)行時(shí)如果檢測到一些要求同步的代碼上不可能發(fā)生共享數(shù)據(jù)競爭,則會去掉這些鎖。

  • 鎖粗化:將臨近的代碼塊用同一個(gè)鎖合并起來。 消除無意義的鎖獲取和釋放,可以提高程序運(yùn)行性能。

八、Synchronized static 與非 static 鎖的區(qū)別和范圍。

對象鎖是用于對象實(shí)例方法,或者一個(gè)對象實(shí)例上的,類鎖是用于類的靜態(tài)方法或者一個(gè)類的 class 對象上的。我們知道,類的對象實(shí)例可以有很多個(gè),但是每個(gè)類只有一個(gè) class 對象,所以不同對象實(shí)例的對象鎖是互不干擾的,但是每個(gè)類只有一個(gè)類鎖。
       有一點(diǎn)必須注意的是,其實(shí)類鎖只是一個(gè)概念上的東西,并不是真實(shí)存 在的,類鎖其實(shí)鎖的是每個(gè)類的對應(yīng)的 class 對象。類鎖和對象鎖之間也是互不干擾的。

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

不能保證,在 DCL 的作用是:volatile 是會保證被修飾的變量的可見性和有序性, 保證了單例模式下,保證在創(chuàng)建對象的時(shí)候的執(zhí)行順序一定是

  1. 分配內(nèi)存空間

  2. 實(shí)例化對象 instance

  3. 把 instance 引用指向已分配的內(nèi)存空間,此時(shí) instance 有了內(nèi)存地址,不再為 null 了的步驟, 從而保證了 instance 要么為 null 要么是已經(jīng)完全初始化好的對象。

十、volatile 和 synchronize 有什么區(qū)別?

volatile 是最輕量的同步機(jī)制。 volatile 保證了不同線程對這個(gè)變量進(jìn)行操作時(shí)的可見性,即一個(gè)線程修改了某個(gè)變量的值,這新值對其他線程來說是立即可見的。但是 volatile 不能保證操作的原子性,因此多線程下的寫復(fù)合操作會導(dǎo)致線程安全問題。
       關(guān)鍵字 synchronized 可以修飾方法或者以同步塊的形式來進(jìn)行使用,它主要確保多個(gè)線程在同一個(gè)時(shí)刻,只能有一個(gè)線程處于方法或者同步塊中,它保證了線程對變量訪問的可見性和排他性,又稱為內(nèi)置鎖機(jī)制。

十一、什么是守護(hù)線程?你是如何退出一個(gè)線程的?

Daemon(守護(hù))線程是一種支持型線程,因?yàn)樗饕挥米鞒绦蛑泻笈_調(diào) 度以及支持性工作。這意味著,當(dāng)一個(gè) Java 虛擬機(jī)中不存在非 Daemon 線程的時(shí)候,Java 虛擬機(jī)將會退出??梢酝ㄟ^調(diào)用 Thread.setDaemon(true)將線程設(shè)置為 Daemon 線程。我們一般用不上,比如垃圾回收線程就是 Daemon 線程。
       線程的中止:要么是 run 執(zhí)行完成了,要么是拋出了一個(gè)未處理的異常導(dǎo)致線程提前結(jié)束。 暫停、恢復(fù)和停止操作對應(yīng)在線程 Thread 的 API 就是 suspend()、resume()和 stop()。 但是這些 API 是過期的,也就是不建議使用的。因?yàn)闀?dǎo)致程序可能工作在不確定狀態(tài)下。
       安全的中止則是其他線程通過調(diào)用某個(gè)線程 A 的 interrupt()方法對其進(jìn)行中斷操作,被中斷的線程則是通過線程通過方法 isInterrupted()來進(jìn)行判斷是否被中斷, 也可以調(diào)用靜態(tài)方法 Thread.interrupted()來進(jìn)行判斷當(dāng)前線程是否被中斷,不過 Thread.interrupted()會同時(shí)將中斷標(biāo)識位改寫為 false。

十二、sleep 、wait、yield 的區(qū)別,wait 的線程如何喚醒它?

yield()方法:使當(dāng)前線程讓出 CPU 占有權(quán),但讓出的時(shí)間是不可設(shè)定的。也不會釋放鎖資源。所有執(zhí)行 yield()的線程有可能在進(jìn)入到就緒狀態(tài)后會被操作系統(tǒng)再次選中馬上又被執(zhí)行。
       yield() 、sleep()被調(diào)用后,都不會釋放當(dāng)前線程所持有的鎖。
       調(diào)用 wait()方法后,會釋放當(dāng)前線程持有的鎖,而且當(dāng)前被喚醒后,會重新去競爭鎖,鎖競爭到后才會執(zhí)行 wait 方法后面的代碼。
       Wait 通常被用于線程間交互,sleep 通常被用于暫停執(zhí)行,yield()方法使當(dāng)前線程讓出 CPU 占有權(quán)。
       wait 的線程使用 notify/notifyAll()進(jìn)行喚醒。

十三、sleep 是可中斷的么?

sleep 本身就支持中斷,如果線程在 sleep 期間被中斷,則會拋出一個(gè)中斷異常。

十四、線程生命周期。

Java 中線程的狀態(tài)分為 6 種:

  1. 初始(NEW):新創(chuàng)建了一個(gè)線程對象,但還沒有調(diào)用 start()方法。

  2. 運(yùn)行(RUNNABLE):Java 線程中將就緒(ready)和運(yùn)行中(running)兩種狀態(tài)籠統(tǒng)的稱為“運(yùn)行”。 線程對象創(chuàng)建后,其他線程(比如 main 線程)調(diào)用了該對象的 start()方法。 該狀態(tài)的線程位于可運(yùn)行線程池中,等待被線程調(diào)度選中,獲取 CPU 的使用權(quán), 此時(shí)處于就緒狀態(tài)(ready)。就緒狀態(tài)的線程在獲得 CPU 時(shí)間片后變?yōu)檫\(yùn)行中 狀態(tài)(running)。

  3. 阻塞(BLOCKED):表示線程阻塞于鎖。

  4. 等待(WAITING):進(jìn)入該狀態(tài)的線程需要等待其他線程做出一些特定動(dòng)作 (通知或中斷)。

  5. 超時(shí)等待(TIMED_WAITING):該狀態(tài)不同于 WAITING,它可以在指定的時(shí) 間后自行返回。

  6. 終止(TERMINATED):表示該線程已經(jīng)執(zhí)行完畢。

Java線程面試題的知識點(diǎn)有哪些

十五、ThreadLocal 是什么?

ThreadLocal 是 Java 里一種特殊的變量。ThreadLocal 為每個(gè)線程都提供了變量的副本,使得每個(gè)線程在某一時(shí)間訪問到的并非同一個(gè)對象,這樣就隔離了多個(gè)線程對數(shù)據(jù)的數(shù)據(jù)共享。
       在內(nèi)部實(shí)現(xiàn)上,每個(gè)線程內(nèi)部都有一個(gè) ThreadLocalMap,用來保存每個(gè)線程所擁有的變量副本。

十六、線程池基本原理。

在開發(fā)過程中,合理地使用線程池能夠帶來 3 個(gè)好處。
第一:降低資源消耗。
第二:提高響應(yīng)速度。
第三:提高線程的可管理性。

  1. 如果當(dāng)前運(yùn)行的線程少于 corePoolSize,則創(chuàng)建新線程來執(zhí)行任務(wù)(注意, 執(zhí)行這一步驟需要獲取全局鎖)。

  2. 如果運(yùn)行的線程等于或多于 corePoolSize,則將任務(wù)加入 BlockingQueue。

  3. 如果無法將任務(wù)加入 BlockingQueue(隊(duì)列已滿),則創(chuàng)建新的線程來處理任務(wù)。

  4. 如果創(chuàng)建新線程將使當(dāng)前運(yùn)行的線程超出 maximumPoolSize,任務(wù)將被拒絕,并調(diào)用 RejectedExecutionHandler.rejectedExecution()方法。

十七、有三個(gè)線程 T1,T2,T3,怎么確保它們按順序執(zhí)行?

可以用 join 方法實(shí)現(xiàn)。

到此,相信大家對“Java線程面試題的知識點(diǎn)有哪些”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI