程序員的金三銀四求職寶典
隨著春天的腳步漸近,對于許多程序員來說,一年中最繁忙、最重要的面試季節也隨之而來。金三銀四,即三月和四月,被廣大程序員視為求職的黃金時期。在這兩個月里,各大公司紛紛開放招聘,求職者們則通過一輪又一輪的面試,力爭心儀的職位。而如何在這關鍵的時期脫穎而出,成為每個求職者關注的焦點。在金三銀四的關鍵時期如何準備,快來看看吧
面試題解析
接著上一篇面試題解析(java程序員的金三銀四求職寶典),咱們繼續……
21、使用submit和execute向線程池提交任務的區別?
答:這兩種提交方式都是JDK提供的。
- 來源不同:execute是頂級接口executor中定義的,submit(好幾種重載形式)是executorService接口中定義的;
- 接收參數不同:execute方法只能接收Runnable接口任務,而submit可以接收Runnable和Callable的任務;
- 返回值不同:execute返回void,submit返回Future。
- 異常:execute執行任務時,如果遇到任務會拋出異常,subumit不會直接拋出異常,只有在使用Future的get方法獲取返回值時,才拋出異常。
22、進程和線程
答:進程有自己獨立的內存空間。進程時應用程序,,一個進程可以有多個線程。
進程是操作系統級別的,線程是CPU級別的。
線程的生命周期:
- 新建狀態;
- 可運行狀態(分為就緒和運行);
- 阻塞狀態;
- 等待狀態;----wait
- 超時等待狀態;---sleep
- 死亡狀態。
23、死鎖產生的原因?怎么避免?
- 互斥:一個資源每次只能被一個進程使用;
- 請求和保持:一個進程因請求資源而阻塞時,不釋放獲得資源;
- 不剝奪:進程已獲得的資源,在未使用之前,不能強行剝奪;
- 循環等待:進程之間循環等待資源
避免死鎖那就打破產生死鎖的原因:
- 加鎖保證互斥;
- 一次性申請所有資源;
- 按序申請資源;
- 占有部分資源時,線程進一步申請資源,如果申請不到那就釋放占有的資源。
24、Synchronized的底層原理?
答:簡單來說,底層就是內部有一個計數器,當計數器為0的時候表示可以成功獲取到鎖,獲取到后將計數器設置為1;當線程執行完后,在將計數器設置為0.
25、Volatile和synchronized的區別?
答:
- Volatile只能作用在變量上,synchronized可以作用在類、方法、代碼塊、變量上;
- Volatile只能保證可見性,synchronized可以保證可見性和原子性;
- Volatile禁用指令重排,synchronized不會;
- Volatile不會造成阻塞,synchronized會。
26、synchronized和lock的區別?
答:
1、synchronized作用在類、方法、代碼塊、變量上,lock作用在方法中;
2、synchronized不知道是否將鎖釋放,lock是手動釋放鎖的,所以知道;lock一般使用ReentrantLock類做為鎖。
27、Threadlocal與synchronized的區別?
答:
- synchronized用于線程間的數據共享,Threadlocal則用于線程間的數據隔離;
- synchronized是利用鎖的機制,是變量或者代碼塊在某一時刻只能被一個線程訪問。而Threadlocal為每一個線程都提供一個變量副本。
- 上述兩個都是解決多線程并發訪問的問題。
28、Threadlocal內存泄露?
答:每個線程都有一個ThreadLocalMap,Map中的元素key為ThreadLocal,值對應線程的變量副本。
垃圾回收時會自動回收key,而value的回收取決與thread對象的生命周期。一般都是使用線程池進行線程復用操作的,這就導致線程對象的生命周期比較長,這樣便會一直存在一條強引用鏈的關系。隨著任務的執行,value可能就會越來越多且無法釋放,最終導致內存泄露。
29、內存泄露和內存溢出的區別?
答:內存溢出就是在申請內存空間時,內存空間不夠。內存泄露是指程序申請內存后,無法釋放已申請的內存,一次內存泄漏的危害可以忽略,,但是內存泄露堆積后果很嚴重。內存泄露最終會導致內存溢出。
30、紅黑樹是怎么調整平衡的?
答:
- 左旋;
- 右旋;
- 改變顏色。
31、什么是回表查詢?如何避免回表查詢?
答:回表查詢的本質:是普通索引找不到我們要的完整信息,迫不得已要執行回表操作。也就是多次B+樹的查詢操作,會導致效率低。
怎么解決?就是可以建立聯合索引。
32、使用了范圍查找還能走索引嗎?
答:如果嚴格意義上來說,使用了范圍查找是不會走索引的。但是像in這種范圍查詢本質上是等值查詢,它也會走索引的。
33、Redis分布式鎖?Redis持久化方式?
答:先理解一下,為啥會問redis的持久化方式呢?因為redis的特點就是單線程也快,歸結于redis是一個內存數據庫。但是內存數據庫一般有個缺點就是,內存相對于磁盤存儲來說,存儲空間太小了,空間很容易就不足了。因此,會有持久化操作方式。redis持久化就是將數據寫在磁盤,可以有效地避免因進程退出造成的數據丟失問題,當下次重啟時利用之前持久化的文件即可實現數據恢復。
Redis的持久化方式:1、RDB;2、AOF。
1、RDB(Redis DataBase):把當前進程數據生成快照保存到硬盤的過程。所謂內存快照就是將內存中的數據在某一時刻的狀態記錄下來。類似于拍照,把一瞬間的美記錄下來。
那么RDB是給哪些數據做快照呢?
RDB是將所有數據都記錄到磁盤中,但是,RDB文件越大,往磁盤上寫數據的時間開銷就越大。
RDB文件的生成是否會阻塞主線程?
Redis提供兩個手動命令來生成RDB文件,save和bgsave。
Save:會導致主線程阻塞,線上環境不建議使用。在主線程中使用的
Bgsave:創建一個子線程,專門用于寫入RDB文件,避免了主線程阻塞。Redis默認選擇bgsave作為RDB文件的生成方式。
2、AOF:以獨立日志的方式記錄每次寫命令,重啟時再重新執行AOF文件中的命令達到回復數據目的。AOF的主要作用是解決了數據持久化的實時性,目前是redis持久化的主流方式。AOF默認不開啟,默認RDB。
分布式鎖
首先要達到分布式鎖,必須要求redis有互斥(就是一個客戶端加了鎖,另一個客戶端就加不了鎖)的能力。我們可以使用SETNX命令,這個命令表示SET if Not Exists,即如果key不存在,才會設置它的值,否則什么也不做。
兩個客戶端進程執行這個命令,可以達到互斥,實現分布式鎖。
客戶端1:申請加鎖,加鎖成功;
客戶端2:申請加鎖,因為它后達到,加鎖失敗。
此時,加鎖成功的客戶端,就可以操作共享資源。操作完成后,需要及時釋放鎖。直接執行DEL命令刪除key即可。
但是,這種方式存在很大的問題!!!當客戶端1拿到鎖后,如果發生如下情況,就會造成死鎖:
- 進程處理業務邏輯異常,沒有及時釋放鎖;
- 進程掛了,沒有機會釋放鎖。
這時,客戶端1就會一直占用鎖,其他客戶端就永遠拿不到鎖。怎么解決這個問題?
- 將key設置有效時間;
上述操作還會有問題,因為redis釋放鎖是一個無腦操作,萬一釋放了別人的鎖呢?萬一執行業務時間較長,設置鎖的有效期到了怎么辦?
解決方案:客戶端加鎖時,設置一個只有客戶端自己知道的唯一標識進去。
解決方案:分布式鎖加看門狗。加鎖時,先設置一個過期時間,然后客戶端開啟一個守護線程,定時去檢測這個鎖的失效時間,如果鎖快要過期了,操作共享資源還未完成,那就自動對鎖進行續費,重新設置有效時間。
34、Redis的主從復制過程?
答:主從復制是為了達成高可用。
- 為了避免單點redis服務器故障,準備多臺服務器,互相連通。將數據復制多個副本保存再不同的服務器上,連接再一起,并保證數據是同步的。
- 即使有一臺服務器宕機,其他服務器依然可以繼續提供服務。
主服務器:master(數據提供方)
從服務器:slave(數據接收方)
需要解決:數據同步問題;核心工作:master的數據復制都slave中。
主從復制:數據的復制只能是單向的,只能從主節點到從節點。
主從復制工作流程:
- 建立連接階段(連接)--總體是建立了socket連接;
1.1設置master的地址和端口,保存master信息;
1.2建立socket連接;
1.3發送ping命令(定時器任務)
1.4身份驗證
1.5發送slave端口信息
- 數據同步階段---slave初次連接master后,復制master的所有數據到slave中,slave數據庫狀態更新為master當前數據庫狀態;
2.1請求同步數據;
2.2創建RDB同步數據;
2.3恢復RDB同步數據;
2.4請求部分同步數據;
2.5回復部分同步數據;
- 命令傳播階段---當master數據庫狀態修改后,導致主從服務器數據庫狀態不一致,此時需要讓主從數據同步到一致的狀態,同步的動作成為命令傳播。
35、聯合索引失效了怎么辦?
答:
聯合索引失效場景:
- 條件中不使用聯合索引的第一個字段;
- 條件中使用了范圍查詢--聯合索引只能對多個字段進行等值查詢進行優化,對范圍查詢的優化效果有限;
- 條件中使用了函數或者表達式--無法使用索引優化;
- 聯合索引的字段順序不合理--如果聯合索引的字段順序與查詢語句中的條件順尋不一致,那么聯合索引將失效。
避免來聯合索引失效方法:
- 查詢優化條件:避免范圍查詢、函數和表達式,盡量將聯合索引第一個字段包含再查詢條件中;
- 重新設計索引;
- 拆分聯合索引。
36、當運行一個項目時cpu的load過高,該怎么去解決呢?
答:
- 從編程語言層面上,full gc(垃圾回收機制)次數的增大或者死循環都可能造成cpu load增高;
- 尋找最占cpu的進程--ps ux;top -c;
- 尋找最耗cpu的線程;
37、Hashmap面試題?
答:
hashmap是一個線程不安全的map集合。
怎么實現線程安全的hashmap集合?
- 使用ConcurrentHashMap集合;
- 使用Collections類提供的synchronizedMap方法包裝HashMap,將HashMap對象包裝成一個線程安全的map對象。
- 使用ReentrantReadWriteLock類實現:使用ReentrantReadWriteLock類來控制HashMap中的讀寫操作,這樣就能夠在多個線程同時讀取HashMap的情況下,避免出現競爭條件。而寫操作則需要獨占鎖,保證只有一個線程執行寫操作,防止數據沖突。
- 使用sychronized關鍵字實現:這樣可以控制對hashmap的并發訪問,保證同一時刻只有一個線程再訪問hashmap。
Hashmap的底層是:數組+鏈表/紅黑樹;
當鏈表元素超過8時,自動裝換成紅黑樹存儲,重新創建一個hashmap復制。當紅黑樹元素為6時,自動轉換成鏈表存儲。Hashmap默認數組大小為16,擴容因子為0.75.當數組元素超過數組大小的0.75倍時,就擴容。Hashmap擴容后的長度直接變成之前的2倍。
紅黑樹:
- 只有黑或紅色節點;
- 一個路徑上的節點不允許有兩個連續的紅色節點;
- 根節點是黑色節點;
- 葉子節點都是黑色;
- 紅色節點的父親都是黑色節點。
為啥用紅黑樹不用鏈表?
就是時間復雜度的問題
Put方法最大能放多少對象?--就是數組的容量
如果內存足夠大,能夠一直擴容下去嗎?理論上是可以的。
如果一直擴容,對象多了后,會影響讀取嗎?擴容過程本身不會影響讀取操作,因為hashmap在進行擴容時,會使用一個新的更大的數組,并在后臺將元素逐個重新計算哈希碼、確定新的存儲位置,并復制到新的數組中。在這個過程中,原來的數組仍然可以被讀取,而新的數組是在后臺構建的。
38、java內存分區?類的加載過程?
答:
- 堆區--又稱GC堆;
是所有線程所共享的一塊內存區域,在虛擬機啟動時創建。唯一的目的就是存放實例對象(new的對象還有數組)。也是java垃圾收集器管理的主要區域。
- 棧區;
是線程私有的區域,它的生命周期和線程相同。每個方法在執行的時候都會同時創建一個棧用于存儲局部變量表、操作棧、動態鏈接、方法返回地址等信息。每一個方法從被調用到執行完成的過程,就對應這一個棧在虛擬機中從入棧到出棧的過程。
- 方法區--又稱Non-Heap;
與堆一樣是所有線程共享的內存區域,用于存儲被虛擬機加載的類信息、常量、靜態變量和即使編譯器編譯后的代碼等數據。
相對而言,垃圾收集器很少在這個區域回收垃圾。但是不代表不回收。這個區域的內存回收目標主要針對常量池的回收和類型的卸載。
- 程序計數器;
程序計數器可以看作是當前線程所執行的字節碼的行號指示器。在虛擬機中,字節碼解釋器工作時就是通過這個計數器的值來選取下一條需要執行的字節碼指令,分支、循環、跳轉、異常處理和線程恢復。
- 本地方法棧。
和棧的作用很像,區別是本地方法棧則為虛擬機提供使用到的Native方法服務。
類的加載過程:加載--->驗證--->準備--->解析--->初始化--->使用--->卸載
- 加載:獲取二進制流轉化為.class文件;
- 驗證:確保被加載的類的正確性;.class文件頭;
- 準備:為類的靜態變量分配內存,并將其初始化默認值;
- 解析:把類中的符號引用轉換為直接引用(符號引用就是來描述所引用的目標,JVM并不知道所引用的類的地址,所以解析階段就是把符號引用轉換為直接引用的地址);
- 初始化:
5.1類什么時候初始化:new、調用類的靜態方法、反射等;
5.2類的初始化順序:
- 假如這個類存在直接父類,并且這個類沒有被初始化(類只能被初始化一次),那就直接初始化直接父類;
- 加入類中存在初始化語句(static),那就依次執行
39、get請求和post請求有什么區別?
答:
- get請求一般是去獲取數據,post一般是去提交數據。
- get請求的參數會放在url路徑中,安全性較差,請求數據長度有限制,post請求的數據長度沒有限制,請求數據放在body中。
- 通常get請求產生一個TCP數據包,post請求會產生兩個TCP數據包。
40、介紹悲觀鎖和樂觀鎖一級使用場景?
答:
樂觀鎖:就是線程在操作數據時,不會去加鎖,認為沒有人修改數據;
悲觀鎖:比較悲觀,認為線程在操作數據時,會去修改數據,所以會加鎖。
樂觀鎖和悲觀鎖沒有優劣之分,只有合適的場景而已。
樂觀鎖適合讀多寫少,并發沖突小的場景。
悲觀鎖適合讀少寫多,并發沖突較多的場景。
接一個題外話,最近想學習以下高并發高可用的項目,請問有哪些項目推薦的呀?大家可以打在評論區討論以下,謝謝?