1. 程式人生 > >java一些面試題

java一些面試題

key 普通 導致 訪問 字節 fail rom 非阻塞 理論

java虛擬機

什麽時候會觸發full gc

  1. System.gc()方法的調用
  2. 老年代空間不足
  3. 永生區空間不足(JVM規範中運行時數據區域中的方法區,在HotSpot虛擬機中又被習慣稱為永生代或者永生區,Permanet Generation中存放的為一些class的信息、常量、靜態變量等數據)
  4. GC時出現promotion failed和concurrent mode failure
  5. 統計得到的Minor GC晉升到舊生代平均大小大於老年代剩余空間
  6. 堆中分配很大的對象

可以作為root的對象:

  1. 類中的靜態變量,當它持有一個指向一個對象的引用時,它就作為root
  2. 活動著的線程,可以作為root
  3. 一個Java方法的參數或者該方法中的局部變量,這兩種對象可以作為root
  4. JNI方法中的局部變量或者參數,這兩種對象可以作為root

例子:下述的Something和Apple都可以作為root對象。

技術分享圖片

Java方法的參數和方法中的局部變量,可以作為root.

技術分享圖片

新生代轉移到老年代的觸發條件

  1. 長期存活的對象
  2. 大對象直接進入老年代
  3. minor gc後,survivor仍然放不下
  4. 動態年齡判斷 ,大於等於某個年齡的對象超過了survivor空間一半 ,大於等於某個年齡的對象直接進入老年代

redis

redis單線程問題

單線程指的是網絡請求模塊使用了一個線程(所以不需考慮並發安全性),即一個線程處理所有網絡請求,其他模塊仍用了多個線程。

為什麽說redis能夠快速執行

  1. 絕大部分請求是純粹的內存操作(非常快速)
  2. 采用單線程,避免了不必要的上下文切換和競爭條件
  3. 非阻塞IO - IO多路復用

redis的內部實現

內部實現采用epoll,采用了epoll+自己實現的簡單的事件框架。epoll中的讀、寫、關閉、連接都轉化成了事件,然後利用epoll的多路復用特性,絕不在io上浪費一點時間 這3個條件不是相互獨立的,特別是第一條,如果請求都是耗時的,采用單線程吞吐量及性能可想而知了。應該說redis為特殊的場景選擇了合適的技術方案。

Redis關於線程安全問題

redis實際上是采用了線程封閉的觀念,把任務封閉在一個線程,自然避免了線程安全問題,不過對於需要依賴多個redis操作的復合操作來說,依然需要鎖,而且有可能是分布式鎖。

使用redis有哪些好處?

  1. 速度快,因為數據存在內存中,類似於HashMap,HashMap的優勢就是查找和操作的時間復雜度都是O(1)
  2. 支持豐富數據類型,支持string,list,set,sorted set,hash
  3. 支持事務,操作都是原子性,所謂的原子性就是對數據的更改要麽全部執行,要麽全部不執行
  4. 豐富的特性:可用於緩存,消息,按key設置過期時間,過期後將會自動刪除

redis相比memcached有哪些優勢?

  1. memcached所有的值均是簡單的字符串,redis作為其替代者,支持更為豐富的數據類型
  2. redis的速度比memcached快很多
  3. redis可以持久化其數據

數據庫

B樹和B+樹的區別

  1. B樹,每個節點都存儲key和data,所有節點組成這棵樹,並且葉子節點指針為nul,葉子結點不包含任何關鍵字信息。
技術分享圖片
  1. B+樹,所有的葉子結點中包含了全部關鍵字的信息,及指向含有這些關鍵字記錄的指針,且葉子結點本身依關鍵字的大小自小而大的順序鏈接,所有的非終端結點可以看成是索引部分,結點中僅含有其子樹根結點中最大(或最小)關鍵字。 (而B 樹的非終節點也包含需要查找的有效信息)
技術分享圖片

為什麽說B+比B樹更適合實際應用中操作系統的文件索引和數據庫索引?

  1. B+的磁盤讀寫代價更低 B+的內部結點並沒有指向關鍵字具體信息的指針。因此其內部結點相對B樹更小。如果把所有同一內部結點的關鍵字存放在同一盤塊中,那麽盤塊所能容納的關鍵字數量也越多。一次性讀入內存中的需要查找的關鍵字也就越多。相對來說IO讀寫次數也就降低了。
  2. B+-tree的查詢效率更加穩定 由於非終結點並不是最終指向文件內容的結點,而只是葉子結點中關鍵字的索引。所以任何關鍵字的查找必須走一條從根結點到葉子結點的路。所有關鍵字查詢的路徑長度相同,導致每一個數據的查詢效率相當。

java高並發

JAVA 線程狀態轉換圖示

技術分享圖片

synchronized 的底層怎麽實現

  1. 同步代碼塊(Synchronization)基於進入和退出管程(Monitor)對象實現。每個對象有一個監視器鎖(monitor)。當monitor被占用時就會處於鎖定狀態,線程執行monitorenter指令時嘗試獲取monitor的所有權,過程如下:
  • 如果monitor的進入數為0,則該線程進入monitor,然後將進入數設置為1,該線程即為monitor的所有者。
  • 如果線程已經占有該monitor,只是重新進入,則進入monitor的進入數加1.
  • 如果其他線程已經占用了monitor,則該線程進入阻塞狀態,直到monitor的進入數為0,再重新嘗試獲取monitor的所有權。
  1. 被 synchronized 修飾的同步方法並沒有通過指令monitorenter和monitorexit來完成(理論上其實也可以通過這兩條指令來實現),不過相對於普通方法,其常量池中多了ACC_SYNCHRONIZED標示符。JVM就是根據該標示符來實現方法的同步的:當方法調用時,調用指令將會檢查方法的 ACC_SYNCHRONIZED 訪問標誌是否被設置,如果設置了,執行線程將先獲取monitor,獲取成功之後才能執行方法體,方法執行完後再釋放monitor。在方法執行期間,其他任何線程都無法再獲得同一個monitor對象。 其實本質上沒有區別,只是方法的同步是一種隱式的方式來實現,無需通過字節碼來完成

java一些面試題