更新時間:2023-01-10 11:11:51 來源:動力節點 瀏覽1417次
說道Java工程師面試題,相信大家最先想到的就是馬上要到金三銀四的時間段了,潛意識里對于就業現狀不太滿意的同學開始進行跳槽的準備,對于程序員的跳槽,準備工作肯定是要充足的,一套合理的高級java工程師面試題,能夠讓面試的成功率大大提高,但未必每個人都能找到合適的面試題,為了大家能夠把握機會,小編整理了一些大廠面試出現率很高的java工程師面試題,希望可以幫助到大家:
1.volatile有三個特性:可見性,不保證原子性,禁止指令重排。
可見性:線程1從主內存中拿數據1到自己的線程工作空間進行操作(假設是加1)這個時候數據1已經改為數據2了,將數據2寫回主內存時通知其他線程(線程2,線程3),主內存中的數據1已改為數據2了,讓其他線程重新拿新的數據(數據2)。
不保證原子性:線程1從主內存中拿了一個值為1的數據到自己的工作空間里面進行加1的操作,值變為2,寫回主內存,然后還沒有來得及通知其他線程,線程1就被線程2搶占了,CPU分配,線程1被掛起,線程2還是拿著原來主內存中的數據值為1進行加1,值變成2,寫回主內存,將主內存值為2的替換成2,這時線程1的通知到了,線程2重新去主內存拿值為2的數據。
禁止指令重排:首先指令重排是程序執行的時候不總是從上往下執行的,就像高考答題,可以先做容易的題目再做難的,這時做題的順序就不是從上往下了。禁止指令重排就杜絕了這種情況。
(一般面試官開始問你會從java基礎問起,一問大多數會問到集合這一塊,而集合問的較多的是HashMap,這個時候你就可以往這些方向帶著面試官問你,而且擴展的深度也夠,所以上面的干貨夠你說個十來分鐘吧,第一個問題拿下后,面試官心里至少簡單你的基礎夠扎實,第一印象分就留下了)
Spring的AOP和IOC是什么?使用場景有哪些?Spring事務與數據庫事務,傳播行為,數據庫隔離級別
2.AOP:面向切面編程。
即在一個功能模塊中新增其他功能,比方說你要下樓取個快遞,你同事對你說幫我也取一下唄,你就順道取了。在工作中如果系統中有些包和類中沒有使用AOP,例如日志,事務和異常處理,那么就必須在每個類和方法中去實現它們。 代碼糾纏每個類和方法中都包含日志,事務以及異常處理甚至是業務邏輯。在一個這樣的方法中,很難分清代碼中實際做的是什么處理。AOP 所做的就是將所有散落各處的事務代碼集中到一個事務切面中。
場景
比方說我現在要弄一個日志,記錄某些個接口調用的方法時間。使用Aop我可以在這個接口前插入一段代碼去記錄開始時間,在這個接口后面去插入一段代碼記錄結束時間。
又或者你去訪問數據庫,而你不想管事務(太煩),所以,Spring在你訪問數據庫之前,自動幫你開啟事務,當你訪問數據庫結束之后,自動幫你提交/回滾事務!
異常處理你可以開啟環繞通知,一旦運行接口報錯,環繞通知捕獲異常跳轉異常處理頁面。
3.動態代理
Spring AOP使用的動態代理,所謂的動態代理就是說AOP框架不會去修改字節碼,而是在內存中臨時為方法生成一個AOP對象,這個AOP對象包含了目標對象的全部方法,并且在特定的切點做了增強處理,并回調原對象的方法。它的動態代理主要有兩種方式,JDK動態代理和CGLIB動態代理。JDK動態代理通過反射來接收被代理的類,并且要求被代理的類必須實現一個接口。JDK動態代理的核心是InvocationHandler接口和Proxy類。如果目標類沒有實現接口,那么Spring AOP會選擇使用CGLIB來動態代理目標類。CGLIB是一個代碼生成的類庫,可以在運行時動態的生成某個類的子類,注意,CGLIB是通過繼承的方式做的動態代理,因此如果某個類被標記為final,那么它是無法使用CGLIB做動態代理的。
4.IOC:依賴注入或者叫做控制反轉。
正常情況下我們使用一個對象時都是需要new Object()的。而ioc是把需要使用的對象提前創建好,放到spring的容器里面。
所有需要使用的類都會在spring容器中登記,告訴spring你是個什么東西,你需要什么東西,然后spring會在系統運行到適當的時候,把你要的東西主動給你,同時也把你交給其他需要你的東西。所有的類的創建、銷毀都由 spring來控制,也就是說控制對象生存周期的不再是引用它的對象,而是spring。DI(依賴注入)其實就是IOC的另外一種說法,其實它們是同一個概念的不同角度描述。
場景:
正常情況下我們使用一個對象時都是需要new Object() 的。而ioc是把需要使用的對象提前創建好,放到spring的容器里面。需要使用的時候直接使用就行,而且可以設置單例或多例,非常靈活。
我們在service層想調用另外一個service的方法,不需要去new了,直接把它交給spring管理,然后用注解的方式引入就能使用。
5.HashMap底層實現原理,紅黑樹,B+樹,B樹的結構原理,volatile關鍵字,CAS(比較與交換)實現原理
首先HashMap是Map的一個實現類,而Map存儲形式是鍵值對(key,value)的。可以看成是一個一個的Entry。Entry所存放的位置是由key來決定的。
Map中的key是無序的且不可重復的,所有的key可以看成是一個set集合,如果出現Map中的key如果是自定義類的對象,則必須重寫hashCode和equals方法,因為如果不重寫,使用的是Object類中的hashCode和equals方法,比較的是內存地址值不是比內容。
Map中的value是無序的可重復的,所有的value可以看成是Collection集合,Map中的value如果是自定義類的對象必須重寫equals方法。
至于要重寫hashCode和equals分別做什么用,拿hashMap底層原理來說:
當我們向HashMap中存放一個元素(k1,v1),先根據k1的hashCode方法來決定在數組中存放的位置。
如果這個位置沒有其它元素,將(k1,v1)直接放入Node類型的數組中,這個數組初始化容量是16,默認的加載因子是0.75,也就是當元素加到12的時候,底層會進行擴容,擴容為原來的2倍。如果該位置已經有其它元素(k2,v2),那就調用k1的equals方法和k2進行比較二個元素是否相同,如果結果為true,說明二個元素是一樣的,用v1替換v2,如果返回值為false,二個元素不一樣,就用鏈表的形式將(k1,v1)存放。
不過當鏈表中的數據較多時,查詢的效率會下降,所以在JDK1.8版本后做了一個升級,hashmap就是當鏈表中的元素達到8并且元素數量大于64時,會將鏈表替換成紅黑樹才會樹化時,會將鏈表替換成紅黑樹,來提高查找效率。因為對于搜索,插入,刪除操作多的情況下,使用紅黑樹的效率要高一些。
原因是因為紅黑樹是一種特殊的二叉查找樹,二叉查找樹所有節點的左子樹都小于該節點,所有節點的右子樹都大于該節點,就可以通過大小比較關系來進行快速的檢索。
在紅黑樹上插入或者刪除一個節點之后,紅黑樹就發生了變化,可能不滿足紅黑樹的5條性質,也就不再是一顆紅黑樹了,而是一顆普通的樹,可以通過左旋和右旋,使這顆樹重新成為紅黑樹。紅黑樹的5條性質(根節點是黑色,每個節點是黑色或者是紅色,每個葉子節點是黑色,如果一個節點是紅色它的子節點必須是黑色的,從一個節點到該節點的子孫外部節點的所有路徑上包含相同數目的黑點)
而且像這種二叉樹結構比較常見的使用場景是Mysql二種引擎的索引,Myisam使用的是B樹,InnoDB使用的是B+樹。
首先B樹它的每個節點都是Key.value的二元組,它的key都是從左到右遞增的排序,value中存儲數據。這種模式在讀取數據方面的性能很高,因為有單獨的索引文件,Myisam 的存儲文件有三個.frm是表的結構文件,.MYD是數據文件,.MYI是索引文件。不過Myisam 也有些缺點它只支持表級鎖,不支持行級鎖也不支持事務,外鍵等,所以一般用于大數據存儲。
然后是InnoDB,它的存儲文件相比Myisam少一個索引文件,它是以 ID 為索引的數據存儲,數據現在都被存在了葉子結點,索引在非葉結點上。而這些節點分散在索引頁上。在InnoDB里,每個頁默認16KB,假設索引的是8B的long型數據,每個key后有個頁號4B,還有6B的其他數據,那么每個頁的扇出系數為16KB/(8B+4B+6B)≈1000,即每個頁可以索引1000個key。在高度h=3時,s=1000^3=10億!!也就是說,InnoDB通過三次索引頁的I/O,即可索引10億的key,而非葉節點這一行存儲的索引,數量就多了,I/O的次數就少了。而Myisam在每個節點都存儲數據和索引,這樣就減少了每頁存儲的索引數量。而且InnoDB它還支持行級,表級鎖,也支持事務,外鍵.
另外對于HashMap實際使用過程中還是會出現一些線程安全問題:
HashMap是線程不安全的,在多線程環境下,使用Hashmap進行put操作會引起死循環,導致CPU利用率接近100%,而且會拋出并發修改異常,導致原因是并發爭取線程資源,修改數據導致的,一個線程正在寫,一個線程過來爭搶,導致線程寫的過程被其他線程打斷,導致數據不一致。
HashTable是線程安全的,只不過實現代價卻太大了,簡單粗暴,get/put所有相關操作都是synchronized的,這相當于給整個哈希表加了一把大鎖。多線程訪問時候,只要有一個線程訪問或操作該對象,那其他線程只能阻塞,相當于將所有的操作串行化,在競爭激烈的并發場景中性能就會非常差。
為了應對hashmap在并發環境下不安全問題可以使用,ConcurrentHashMap大量的利用了volatile,CAS等技術來減少鎖競爭對于性能的影響。
在JDK1.7版本中ConcurrentHashMap避免了對全局加鎖,改成了局部加鎖(分段鎖),分段鎖技術,將數據分成一段一段的存儲,然后給每一段數據配一把鎖,當一個線程占用鎖訪問其中一個段數據的時候,其他段的數據也能被其他線程訪問,能夠實現真正的并發訪問。不過這種結構的帶來的副作用是Hash的過程要比普通的HashMap要長。
所以在JDK1.8版本中CurrentHashMap內部中的value使用volatile修飾,保證并發的可見性以及禁止指令重排,只不過volatile不保證原子性,使用為了確保原子性,采用CAS(比較交換)這種樂觀鎖來解決。
CAS 操作包含三個操作數 —— 內存位置(V)、預期原值(A)和新值(B)。
如果內存地址里面的值和A的值是一樣的,那么就將內存里面的值更新成B。CAS是通過無限循環來獲取數據的,若果在第一輪循環中,a線程獲取地址里面的值被b線程修改了,那么a線程需要自旋,到下次循環才有可能機會執行。
以上就是“2023年高質量的Java高級工程師面試題”,你能回答上來嗎?如果想要了解更多的Java面試題相關內容,可以關注動力節點Java官網。
0基礎 0學費 15天面授
有基礎 直達就業
業余時間 高薪轉行
工作1~3年,加薪神器
工作3~5年,晉升架構
提交申請后,顧問老師會電話與您溝通安排學習