網上摘錄一部分java基礎面試題目

 

總結 == 對於基本類型來講是值比較,對於引用類型來講是比較的是引用;而 equals 默認狀況下是引用比較,只是不少類從新了 equals 方法,好比 StringInteger 等把它變成了值比較,因此通常狀況下 equals 比較的是值是否相等。java

 

代碼解讀:很顯然通話重地hashCode() 相同,然而 equals() 則爲 false,由於在散列表中,hashCode() 相等即兩個鍵值對的哈希值相等,然而哈希值相等,並不必定能得出鍵值對相等。node

 

接口和抽象類有什麼區別?nginx

  • 實現:抽象類的子類使用 extends 來繼承;接口必須使用 implements 來實現接口。
  • 構造函數:抽象類能夠有構造函數;接口不能有。
  • 實現數量:類能夠實現不少個接口;可是隻能繼承一個抽象類。
  • 訪問修飾符:接口中的方法默認使用 public 修飾;抽象類中的方法能夠是任意訪問修飾符。

 

Java 容器分爲 Collection Map 兩大類,其下又有不少子類,以下所示:面試

  • Collection
  • List
  • ArrayList
  • LinkedList
  • Vector
  • Stack
  • Set
  • HashSet
  • LinkedHashSet
  • TreeSet
  • Map
  • HashMap
  • LinkedHashMap
  • TreeMap
  • ConcurrentHashMap
  • Hashtable

 

Collection Collections 有什麼區別?正則表達式

  • Collection 是一個集合接口,它提供了對集合對象進行基本操做的通用接口方法,全部集合都是它的子類,好比 ListSet 等。
  • Collections 是一個包裝類,包含了不少靜態方法,不能被實例化,就像一個工具類,好比提供的排序方法: Collections. sort(list)

 

20. ListSetMap 之間的區別是什麼?算法

ListSetMap 的區別主要體如今兩個方面:元素是否有序、是否容許元素重複。spring

三者之間的區別,以下表:數據庫

 

 

 

 如何決定使用 HashMap 仍是 TreeMapjson

對於在 Map 中插入、刪除、定位一個元素這類操做,HashMap 是最好的選擇,由於相對而言 HashMap 的插入會更快,但若是你要對一個 key 集合進行有序的遍歷,那 TreeMap 是更好的選擇。後端

 

 說一下 HashMap 的實現原理?

HashMap 基於 Hash 算法實現的,咱們經過 put(key,value)存儲,get(key)來獲取。當傳入 key 時,HashMap 會根據 key. hashCode() 計算出 hash 值,根據 hash 值將 value 保存在 bucket 裏。當計算出的 hash 值相同時,咱們稱之爲 hash 衝突,HashMap 的作法是用鏈表和紅黑樹存儲相同 hash 值的 value。當 hash 衝突的個數比較少時,使用鏈表不然使用紅黑樹。

 

 說一下 HashSet 的實現原理?

HashSet 是基於 HashMap 實現的,HashSet 底層使用 HashMap 來保存全部元素,所以 HashSet 的實現比較簡單,相關 HashSet 的操做,基本上都是直接調用底層 HashMap 的相關方法來完成,HashSet 不容許重複的值。

 

 ArrayList Vector 的區別是什麼?

  • 線程安全:Vector 使用了 Synchronized 來實現線程同步,是線程安全的,而 ArrayList 是非線程安全的。
  • 性能:ArrayList 在性能方面要優於 Vector
  • 擴容:ArrayList Vector 都會根據實際的須要動態的調整容量,只不過在 Vector 擴容每次會增長 1 倍,而 ArrayList 只會增長 50%

 

 哪些集合類是線程安全的?

VectorHashtableStack 都是線程安全的,而像 HashMap 則是非線程安全的,不過在 JDK 1.5 以後隨着 Java. util. concurrent 併發包的出現,它們也有了本身對應的線程安全類,好比 HashMap 對應的線程安全類就是 ConcurrentHashMap

 

併發 = 兩個隊列和一臺咖啡機。

並行 = 兩個隊列和兩臺咖啡機。

 

 建立線程有哪幾種方式?

建立線程有三種方式:

  • 繼承 Thread 重寫 run 方法;
  • 實現 Runnable 接口;
  • 實現 Callable 接口。

 

說一下 runnable callable 有什麼區別?

runnable 沒有返回值,callable 能夠拿到有返回值,callable 能夠看做是 runnable 的補充。

 

建立線程池有哪幾種方式?

線程池建立有七種方式,最核心的是最後一種:

  • newSingleThreadExecutor():它的特色在於工做線程數目被限制爲 1,操做一個無界的工做隊列,因此它保證了全部任務的都是被順序執行,最多會有一個任務處於活動狀態,而且不容許使用者改動線程池實例,所以能夠避免其改變線程數目;
  • newCachedThreadPool():它是一種用來處理大量短期工做任務的線程池,具備幾個鮮明特色:它會試圖緩存線程並重用,當無緩存線程可用時,就會建立新的工做線程;若是線程閒置的時間超過 60 秒,則被終止並移出緩存;長時間閒置時,這種線程池,不會消耗什麼資源。其內部使用 SynchronousQueue 做爲工做隊列;
  • newFixedThreadPool(int nThreads):重用指定數目(nThreads)的線程,其背後使用的是無界的工做隊列,任什麼時候候最多有 nThreads 個工做線程是活動的。這意味着,若是任務數量超過了活動隊列數目,將在工做隊列中等待空閒線程出現;若是有工做線程退出,將會有新的工做線程被建立,以補足指定的數目 nThreads
  • newSingleThreadScheduledExecutor():建立單線程池,返回 ScheduledExecutorService,能夠進行定時或週期性的工做調度;
  • newScheduledThreadPool(int corePoolSize):和newSingleThreadScheduledExecutor()相似,建立的是個 ScheduledExecutorService,能夠進行定時或週期性的工做調度,區別在於單一工做線程仍是多個工做線程;
  • newWorkStealingPool(int parallelism):這是一個常常被人忽略的線程池,Java 8 才加入這個建立方法,其內部會構建ForkJoinPool,利用Work-Stealing算法,並行地處理任務,不保證處理順序;
  • ThreadPoolExecutor():是最原始的線程池建立,上面1-3建立方式都是對ThreadPoolExecutor的封裝。

 

多線程中 synchronized 鎖升級的原理是什麼?

synchronized 鎖升級原理:在鎖對象的對象頭裏面有一個 threadid 字段,在第一次訪問的時候 threadid 爲空,jvm 讓其持有偏向鎖,並將 threadid 設置爲其線程 id,再次進入的時候會先判斷 threadid 是否與其線程 id 一致,若是一致則能夠直接使用此對象,若是不一致,則升級偏向鎖爲輕量級鎖,經過自旋循環必定次數來獲取鎖,執行必定次數以後,若是尚未正常獲取到要使用的對象,此時就會把鎖從輕量級升級爲重量級鎖,此過程就構成了 synchronized 鎖的升級。

鎖的升級的目的:鎖升級是爲了減低了鎖帶來的性能消耗。在 Java 6 以後優化 synchronized 的實現方式,使用了偏向鎖升級爲輕量級鎖再升級到重量級鎖的方式,從而減低了鎖帶來的性能消耗。

 

怎麼防止死鎖?

  • 儘可能使用 tryLock(long timeout, TimeUnit unit)的方法(ReentrantLockReentrantReadWriteLock),設置超時時間,超時能夠退出防止死鎖。
  • 儘可能使用 Java. util. concurrent 併發類代替本身手寫鎖。
  • 儘可能下降鎖的使用粒度,儘可能不要幾個功能用同一把鎖。
  • 儘可能減小同步的代碼塊。

 

ThreadLocal 是什麼?有哪些使用場景?

ThreadLocal 爲每一個使用該變量的線程提供獨立的變量副本,因此每個線程均可以獨立地改變本身的副本,而不會影響其它線程所對應的副本。

ThreadLocal 的經典使用場景是數據庫鏈接和 session 管理等。

 

說一下 synchronized 底層實現原理?

synchronized 是由一對 monitorenter/monitorexit 指令實現的,monitor 對象是同步的基本實現單元。在 Java 6 以前,monitor 的實現徹底是依靠操做系統內部的互斥鎖,由於須要進行用戶態到內核態的切換,因此同步操做是一個無差異的重量級操做,性能也很低。但在 Java 6 的時候,Java 虛擬機 對此進行了大刀闊斧地改進,提供了三種不一樣的 monitor 實現,也就是常說的三種不一樣的鎖:偏向鎖(Biased Locking)、輕量級鎖和重量級鎖,大大改進了其性能。

 

synchronized volatile 的區別是什麼?

  • volatile 是變量修飾符;synchronized 是修飾類、方法、代碼段。
  • volatile 僅能實現變量的修改可見性,不能保證原子性;而 synchronized 則能夠保證變量的修改可見性和原子性。
  • volatile 不會形成線程的阻塞;synchronized 可能會形成線程的阻塞。

 

synchronized Lock 有什麼區別?

  • synchronized 能夠給類、方法、代碼塊加鎖;而 lock 只能給代碼塊加鎖。
  • synchronized 不須要手動獲取鎖和釋放鎖,使用簡單,發生異常會自動釋放鎖,不會形成死鎖;而 lock 須要本身加鎖和釋放鎖,若是使用不當沒有 unLock()去釋放鎖就會形成死鎖。
  • 經過 Lock 能夠知道有沒有成功獲取鎖,而 synchronized 卻沒法辦到。

 

synchronized ReentrantLock 區別是什麼?

synchronized 早期的實現比較低效,對比 ReentrantLock,大多數場景性能都相差較大,可是在 Java 6 中對 synchronized 進行了很是多的改進。

主要區別以下:

  • ReentrantLock 使用起來比較靈活,可是必須有釋放鎖的配合動做;
  • ReentrantLock 必須手動獲取與釋放鎖,而 synchronized 不須要手動釋放和開啓鎖;
  • ReentrantLock 只適用於代碼塊鎖,而 synchronized 可用於修飾方法、代碼塊等。

.

說一下 atomic 的原理?

atomic 主要利用 CAS (Compare And Wwap) volatile native 方法來保證原子操做,從而避免 synchronized 的高開銷,執行效率大爲提高。

 

動態代理是什麼?有哪些應用?

動態代理是運行時動態生成代理類。

動態代理的應用有 spring aophibernate 數據查詢、測試框架的後端 mockrpcJava註解對象獲取等。

 

怎麼實現動態代理?

JDK 原生動態代理和 cglib 動態代理。JDK 原生動態代理是基於接口實現的,而 cglib 是基於繼承當前類的子類實現的。

 

如何實現對象克隆?

  • 實現 Cloneable 接口並重寫 Object 類中的 clone() 方法。
  • 實現 Serializable 接口,經過對象的序列化和反序列化實現克隆,能夠實現真正的深度克隆。

 

深拷貝和淺拷貝區別是什麼?

  • 淺克隆:當對象被複制時只複製它自己和其中包含的值類型的成員變量,而引用類型的成員對象並無複製。
  • 深克隆:除了對象自己被複制外,對象所包含的全部成員變量也將複製。

 

如何避免 SQL 注入?

  • 使用預處理 PreparedStatement
  • 使用正則表達式過濾掉字符中的特殊字符。

 

常見的異常類有哪些?

  • NullPointerException 空指針異常
  • ClassNotFoundException 指定類不存在
  • NumberFormatException 字符串轉換爲數字異常
  • IndexOutOfBoundsException 數組下標越界異常
  • ClassCastException 數據類型轉換異常
  • FileNotFoundException 文件未找到異常
  • NoSuchMethodException 方法不存在異常
  • IOException IO 異常
  • SocketException Socket 異常

 

二者的區別大體以下:

  • tcp 面向鏈接,udp 面向非鏈接即發送數據前不須要創建連接;
  • tcp 提供可靠的服務(數據傳輸),udp 沒法保證;
  • tcp 面向字節流,udp 面向報文;
  • tcp 數據傳輸慢,udp 數據傳輸快;

 

 get post 請求有哪些區別?

  • get 請求會被瀏覽器主動緩存,而 post 不會。
  • get 傳遞參數有大小限制,而 post 沒有。
  • post 參數傳輸更安全,get 的參數會明文限制在 url 上,post 不會。

 

如何實現跨域?

實現跨域有如下幾種方案:

  • 服務器端運行跨域 設置 CORS 等於 *
  • 在單個接口使用註解 @CrossOrigin 運行跨域;
  • 使用 jsonp 跨域;

 

說一下 spring mvc 運行流程?

  • spring mvc 先將請求發送給 DispatcherServlet
  • DispatcherServlet 查詢一個或多個 HandlerMapping,找處處理請求的 Controller
  • DispatcherServlet 再把請求提交到對應的 Controller
  • Controller 進行業務邏輯處理後,會返回一個ModelAndView
  • Dispathcher 查詢一個或多個 ViewResolver 視圖解析器,找到 ModelAndView 對象指定的視圖對象。
  • 視圖對象負責渲染返回給客戶端。

 

 

spring cloud 的核心組件有哪些?

  • Eureka:服務註冊於發現。
  • Feign:基於動態代理機制,根據註解和選擇的機器,拼接請求 url 地址,發起請求。
  • Ribbon:實現負載均衡,從一個服務的多臺機器中選擇一臺。
  • Hystrix:提供線程池,不一樣的服務走不一樣的線程池,實現了不一樣服務調用的隔離,避免了服務雪崩的問題。
  • Zuul:網關管理,由 Zuul 網關轉發請求給對應的服務。

 

說一下 hibernate 的緩存機制?

hibernate 經常使用的緩存有一級緩存和二級緩存:

一級緩存:也叫 Session 緩存,只在 Session 做用範圍內有效,不須要用戶干涉,由 hibernate 自身維護,能夠經過:evict(object)清除 object 的緩存;clear()清除一級緩存中的全部緩存;flush()刷出緩存;

二級緩存:應用級別的緩存,在全部 Session 中都有效,支持配置第三方的緩存,如:EhCache

 

MyBatis 有幾種分頁方式?

分頁方式:邏輯分頁和物理分頁。

邏輯分頁: 使用 MyBatis 自帶的 RowBounds 進行分頁,它是一次性查詢不少數據,而後在數據中再進行檢索。

物理分頁: 本身手寫 SQL 分頁或使用分頁插件 PageHelper,去數據庫查詢指定條數的分頁數據的形式。

 

MyBatis 邏輯分頁和物理分頁的區別是什麼?

  • 邏輯分頁是一次性查詢不少數據,而後再在結果中檢索分頁的數據。這樣作弊端是須要消耗大量的內存、有內存溢出的風險、對數據庫壓力較大。
  • 物理分頁是從數據庫查詢指定條數的數據,彌補了一次性所有查出的全部數據的種種缺點,好比須要大量的內存,對數據庫查詢壓力較大等問題。

 

說一下 MyBatis 的一級緩存和二級緩存?

  • 一級緩存:基於 PerpetualCache HashMap 本地緩存,它的聲明週期是和 SQLSession 一致的,有多個 SQLSession 或者分佈式的環境中數據庫操做,可能會出現髒數據。當 Session flush close 以後,該 Session 中的全部 Cache 就將清空,默認一級緩存是開啓的。
  • 二級緩存:也是基於 PerpetualCache HashMap 本地緩存,不一樣在於其存儲做用域爲 Mapper 級別的,若是多個SQLSession之間須要共享緩存,則須要使用到二級緩存,而且二級緩存可自定義存儲源,如 Ehcache。默認不打開二級緩存,要開啓二級緩存,使用二級緩存屬性類須要實現 Serializable 序列化接口(可用來保存對象的狀態)

 

RabbitMQ 有哪些重要的組件?

  • ConnectionFactory(鏈接管理器):應用程序與Rabbit之間創建鏈接的管理器,程序代碼中使用。
  • Channel(信道):消息推送使用的通道。
  • Exchange(交換器):用於接受、分配消息。
  • Queue(隊列):用於存儲生產者的消息。
  • RoutingKey(路由鍵):用於把生成者的數據分配到交換器上。
  • BindingKey(綁定鍵):用於把交換器的消息綁定到隊列上。

 

RabbitMQ 有幾種廣播類型?

  • direct(默認方式):最基礎最簡單的模式,發送方把消息發送給訂閱方,若是有多個訂閱者,默認採起輪詢的方式進行消息發送。
  • headers:與 direct 相似,只是性能不好,此類型幾乎用不到。
  • fanout:分發模式,把消費分發給全部訂閱者。
  • topic:匹配訂閱模式,使用正則匹配到消息隊列,能匹配到的都能接收到。

 

RabbitMQ 怎麼實現延遲消息隊列?

延遲隊列的實現有兩種方式:

  • 經過消息過時後進入死信交換器,再由交換器轉發到延遲消費隊列,實現延遲功能;
  • 使用 RabbitMQ-delayed-message-exchange 插件實現延遲功能。

 

RabbitMQ 集羣有什麼用?

集羣主要有如下兩個用途:

  • 高可用:某個服務器出現問題,整個 RabbitMQ 還能夠繼續使用;
  • 高容量:集羣能夠承載更多的消息量。

 

RabbitMQ 節點的類型有哪些?

  • 磁盤節點:消息會存儲到磁盤。
  • 內存節點:消息都存儲在內存中,重啓服務器消息丟失,性能高於磁盤類型。

 

RabbitMQ 集羣搭建須要注意哪些問題?

  • 各節點之間使用「--link」鏈接,此屬性不能忽略。
  • 各節點使用的 erlang cookie 值必須相同,此值至關於祕鑰的功能,用於各節點的認證。
  • 整個集羣中必須包含一個磁盤節點。

 

RabbitMQ 集羣中惟一一個磁盤節點崩潰了會發生什麼狀況?

若是惟一磁盤的磁盤節點崩潰了,不能進行如下操做:

  • 不能建立隊列
  • 不能建立交換器
  • 不能建立綁定
  • 不能添加用戶
  • 不能更改權限
  • 不能添加和刪除集羣節點

惟一磁盤節點崩潰了,集羣是能夠保持運行的,但你不能更改任何東西。

 

kafka 能夠脫離 zookeeper 單獨使用嗎?爲何?

kafka 不能脫離 zookeeper 單獨使用,由於 kafka 使用 zookeeper 管理和協調 kafka 的節點服務器。

 

kafka 有幾種數據保留的策略?

kafka 有兩種數據保存策略:按照過時時間保留和按照存儲的消息大小保留。

 

kafka 同時設置了 7 天和 10G 清除數據,到第五天的時候消息達到了 10G,這個時候 kafka 將如何處理?

這個時候 kafka 會執行數據清除工做,時間和大小不論那個知足條件,都會清空數據。

 

使用 kafka 集羣須要注意什麼?

  • 集羣的數量不是越多越好,最好不要超過 7 個,由於節點越多,消息複製須要的時間就越長,整個羣組的吞吐量就越低。
  • 集羣數量最好是單數,由於超過一半故障集羣就不能用了,設置爲單數容錯率更高。

 

 

zookeeper 都有哪些功能?

  • 集羣管理:監控節點存活狀態、運行請求等。
  • 主節點選舉:主節點掛掉了以後能夠從備用的節點開始新一輪選主,主節點選舉說的就是這個選舉的過程,使用 zookeeper 能夠協助完成這個過程。
  • 分佈式鎖:zookeeper 提供兩種鎖:獨佔鎖、共享鎖。獨佔鎖即一次只能有一個線程使用資源,共享鎖是讀鎖共享,讀寫互斥,便可以有多線線程同時讀同一個資源,若是要使用寫鎖也只能有一個線程使用。zookeeper能夠對分佈式鎖進行控制。
  • 命名服務:在分佈式系統中,經過使用命名服務,客戶端應用可以根據指定名字來獲取資源或服務的地址,提供者等信息。

 

 

zookeeper 有幾種部署模式?

zookeeper 有三種部署模式:

  • 單機部署:一臺集羣上運行;
  • 集羣部署:多臺集羣運行;
  • 僞集羣部署:一臺集羣啓動多個 zookeeper 實例運行。

 

數據庫的三範式是什麼?

  • 第一範式:強調的是列的原子性,即數據庫表的每一列都是不可分割的原子數據項。
  • 第二範式:要求實體的屬性徹底依賴於主關鍵字。所謂徹底依賴是指不能存在僅依賴主關鍵字一部分的屬性。
  • 第三範式:任何非主屬性不依賴於其它非主屬性。

 

如何獲取當前數據庫版本?

使用 select version() 獲取當前 MySQL 數據庫版本。

 

 char varchar 的區別是什麼?

  • char(n) :固定長度類型,好比訂閱 char(10),當你輸入"abc"三個字符的時候,它們佔的空間仍是 10 個字節,其餘 7 個是空字節。

chat 優勢:效率高;缺點:佔用空間;適用場景:存儲密碼的 md5 值,固定長度的,使用 char 很是合適。

  • varchar(n) :可變長度,存儲的值是每一個值佔用的字節再加上一個用來記錄其長度的字節的長度。

因此,從空間上考慮 varcahr 比較合適;從效率上考慮 char 比較合適,兩者使用須要權衡。

 

怎麼驗證 MySQL 的索引是否知足需求?

使用 explain 查看 SQL 是如何執行查詢語句的,從而分析你的索引是否知足需求。

explain 語法:explain select * from table where type=1

 

髒讀 :表示一個事務可以讀取另外一個事務中還未提交的數據。好比,某個事務嘗試插入記錄 A,此時該事務還未提交,而後另外一個事務嘗試讀取到了記錄 A

不可重複讀 :是指在一個事務內,屢次讀同一數據。

幻讀 :指同一個事務內屢次查詢返回的結果集不同。好比同一個事務 A 第一次查詢時候有 n 條記錄,可是第二次同等條件下查詢卻有 n+1 條記錄,這就好像產生了幻覺。發生幻讀的緣由也是另一個事務新增或者刪除或者修改了第一個事務結果集裏面的數據,同一個記錄的數據內容被修改了,全部數據行的記錄就變多或者變少了。

 

簡歷消息中間件MQ,只要你不寫百分百不會有面試機會,

只要你寫的了,百分百會開始問你了,

activeMQkafkarabbitMQrocketMQ,各自的優缺點你是如何判斷的。

 

說一下樂觀鎖和悲觀鎖?

  • 樂觀鎖:每次去拿數據的時候都認爲別人不會修改,因此不會上鎖,可是在提交更新的時候會判斷一下在此期間別人有沒有去更新這個數據。
  • 悲觀鎖:每次去拿數據的時候都認爲別人會修改,因此每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會阻止,直到這個鎖被釋放。

數據庫的樂觀鎖須要本身實現,在表裏面添加一個 version 字段,每次修改爲功值加 1,這樣每次修改的時候先對比一下,本身擁有的 version 和數據庫如今的 version 是否一致,若是不一致就不修改,這樣就實現了樂觀鎖。

 

 MySQL 問題排查都有哪些手段?

  • 使用 show processlist 命令查看當前全部鏈接信息。
  • 使用 explain 命令查詢 SQL 語句執行計劃。
  • 開啓慢查詢日誌,查看慢查詢的 SQL

 

如何作 MySQL 的性能優化?

  • 爲搜索字段建立索引。
  • 避免使用 select *,列出須要查詢的字段。
  • 垂直分割分表。
  • 選擇正確的存儲引擎。

 

Redis 使用場景:

  • 記錄帖子點贊數、點擊數、評論數;
  • 緩存近期熱帖;
  • 緩存文章詳情信息;
  • 記錄用戶會話信息。

 

Redis 有哪些功能?

  • 數據緩存功能
  • 分佈式鎖的功能
  • 支持數據持久化
  • 支持事務
  • 支持消息隊列

 

縮招,本科生被剔除出去,不會學習的人都被剔除了。

 

Redis memcache 有什麼區別?

  • 存儲方式不一樣:memcache 把數據所有存在內存之中,斷電後會掛掉,數據不能超過內存大小;Redis 有部份存在硬盤上,這樣能保證數據的持久性。
  • 數據支持類型:memcache 對數據類型支持相對簡單;Redis 有複雜的數據類型。
  • 使用底層模型不一樣:它們之間底層實現方式,以及與客戶端之間通訊的應用協議不同,Redis 本身構建了 vm 機制,由於通常的系統調用系統函數的話,會浪費必定的時間去移動和請求。
  • value 值大小不一樣:Redis 最大能夠達到 512mbmemcache 只有 1mb

 

Redis 爲何是單線程的?

由於 cpu 不是 Redis 的瓶頸,Redis 的瓶頸最有多是機器內存或者網絡帶寬。既然單線程容易實現,並且 cpu 又不會成爲瓶頸,那就瓜熟蒂落地採用單線程的方案了。

關於 Redis 的性能,官方網站也有,普通筆記本輕鬆處理每秒幾十萬的請求。

並且單線程並不表明就慢 nginx nodejs 也都是高性能單線程的表明。

 

什麼是緩存穿透?怎麼解決?

緩存穿透:指查詢一個必定不存在的數據,因爲緩存是不命中時須要從數據庫查詢,查不到數據則不寫入緩存,這將致使這個不存在的數據每次請求都要到數據庫去查詢,形成緩存穿透。

解決方案:最簡單粗暴的方法若是一個查詢返回的數據爲空(無論是數據不存在,仍是系統故障),咱們就把這個空結果進行緩存,但它的過時時間會很短,最長不超過五分鐘。

 

Redis 支持的 Java 客戶端都有哪些?

支持的 Java 客戶端有 Redissonjedislettuce 等。

 

 jedis Redisson 有哪些區別?

  • jedis:提供了比較全面的 Redis 命令的支持。
  • Redisson:實現了分佈式和可擴展的 Java 數據結構,與 jedis 相比 Redisson 的功能相對簡單,不支持排序、事務、管道、分區等 Redis 特性。

 

Redis 怎麼實現分佈式鎖?

Redis 分佈式鎖其實就是在系統裏面佔一個,其餘程序也要佔的時候,佔用成功了就能夠繼續執行,失敗了就只能放棄或稍後重試。

佔坑通常使用 setnx(set if not exists)指令,只容許被一個程序佔有,使用完調用 del 釋放鎖。

 

 

Redis 淘汰策略有哪些?

  • volatile-lru:從已設置過時時間的數據集(server. db[i]. expires)中挑選最近最少使用的數據淘汰。
  • volatile-ttl:從已設置過時時間的數據集(server. db[i]. expires)中挑選將要過時的數據淘汰。
  • volatile-random:從已設置過時時間的數據集(server. db[i]. expires)中任意選擇數據淘汰。
  • allkeys-lru:從數據集(server. db[i]. dict)中挑選最近最少使用的數據淘汰。
  • allkeys-random:從數據集(server. db[i]. dict)中任意選擇數據淘汰。
  • no-enviction(驅逐):禁止驅逐數據。

 

說一下 JVM 運行時數據區?

不一樣虛擬機的運行時數據區可能略微有所不一樣,但都會聽從 Java 虛擬機規範, Java 虛擬機規範規定的區域分爲如下 5 個部分:

  • 程序計數器(Program Counter Register):當前線程所執行的字節碼的行號指示器,字節碼解析器的工做是經過改變這個計數器的值,來選取下一條須要執行的字節碼指令,分支、循環、跳轉、異常處理、線程恢復等基礎功能,都須要依賴這個計數器來完成;
  • Java 虛擬機棧(Java Virtual Machine Stacks):用於存儲局部變量表、操做數棧、動態連接、方法出口等信息;
  • 本地方法棧(Native Method Stack):與虛擬機棧的做用是同樣的,只不過虛擬機棧是服務 Java 方法的,而本地方法棧是爲虛擬機調用 Native 方法服務的;
  • Java 堆(Java Heap):Java 虛擬機中內存最大的一塊,是被全部線程共享的,幾乎全部的對象實例都在這裏分配內存;
  • 方法區(Methed Area):用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯後的代碼等數據。

 

 

198. 什麼是雙親委派模型?

在介紹雙親委派模型以前先說下類加載器。對於任意一個類,都須要由加載它的類加載器和這個類自己一同確立在 JVM 中的惟一性,每個類加載器,都有一個獨立的類名稱空間。類加載器就是根據指定全限定名稱將 class 文件加載到 JVM 內存,而後再轉化爲 class 對象。

類加載器分類:

  • 啓動類加載器(Bootstrap ClassLoader),是虛擬機自身的一部分,用來加載Java_HOME/lib/目錄中的,或者被 -Xbootclasspath 參數所指定的路徑中而且被虛擬機識別的類庫;
  • 其餘類加載器:
  • 擴展類加載器(Extension ClassLoader):負責加載<java_home style="box-sizing: border-box; outline: 0px !important;">\lib\ext目錄或Java. ext. dirs系統變量指定的路徑中的全部類庫;
  • 應用程序類加載器(Application ClassLoader)。負責加載用戶類路徑(classpath)上的指定類庫,咱們能夠直接使用這個類加載器。通常狀況,若是咱們沒有自定義類加載器默認就是用這個加載器。

雙親委派模型:若是一個類加載器收到了類加載的請求,它首先不會本身去加載這個類,而是把這個請求委派給父類加載器去完成,每一層的類加載器都是如此,這樣全部的加載請求都會被傳送到頂層的啓動類加載器中,只有當父加載沒法完成加載請求(它的搜索範圍中沒找到所需的類)時,子加載器纔會嘗試去加載類。

 

說一下類裝載的執行過程?

類裝載分爲如下 5 個步驟:

  • 加載:根據查找路徑找到相應的 class 文件而後導入;
  • 檢查:檢查加載的 class 文件的正確性;
  • 準備:給類中的靜態變量分配內存空間;
  • 解析:虛擬機將常量池中的符號引用替換成直接引用的過程。符號引用就理解爲一個標示,而在直接引用直接指向內存中的地址;
  • 初始化:對靜態變量和靜態代碼塊執行初始化工做。

 

怎麼判斷對象是否能夠被回收?

通常有兩種方法來判斷:

  • 引用計數器:爲每一個對象建立一個引用計數,有對象引用時計數器 +1,引用被釋放時計數 -1,當計數器爲 0 時就能夠被回收。它有一個缺點不能解決循環引用的問題;
  • 可達性分析:從 GC Roots 開始向下搜索,搜索所走過的路徑稱爲引用鏈。當一個對象到 GC Roots 沒有任何引用鏈相連時,則證實此對象是能夠被回收的。

 

 說一下 JVM 有哪些垃圾回收算法?

  • 標記-清除算法:標記無用對象,而後進行清除回收。缺點:效率不高,沒法清除垃圾碎片。
  • 標記-整理算法:標記無用對象,讓全部存活的對象都向一端移動,而後直接清除掉端邊界之外的內存。
  • 複製算法:按照容量劃分二個大小相等的內存區域,當一塊用完的時候將活着的對象複製到另外一塊上,而後再把已使用的內存空間一次清理掉。缺點:內存使用率不高,只有原來的一半。
  • 分代算法:根據對象存活週期的不一樣將內存劃分爲幾塊,通常是新生代和老年代,新生代基本採用複製算法,老年代採用標記整理算法。

 

說一下 JVM 有哪些垃圾回收器?

  • Serial:最先的單線程串行垃圾回收器。
  • Serial OldSerial 垃圾回收器的老年版本,一樣也是單線程的,能夠做爲 CMS 垃圾回收器的備選預案。
  • ParNew:是 Serial 的多線程版本。
  • Parallel ParNew 收集器相似是多線程的,但 Parallel 是吞吐量優先的收集器,能夠犧牲等待時間換取系統的吞吐量。
  • Parallel Old Parallel 老生代版本,Parallel 使用的是複製的內存回收算法,Parallel Old 使用的是標記-整理的內存回收算法。
  • CMS:一種以得到最短停頓時間爲目標的收集器,很是適用 B/S 系統。
  • G1:一種兼顧吞吐量和停頓時間的 GC 實現,是 JDK 9 之後的默認 GC 選項。

 

新生代垃圾回收器和老生代垃圾回收器都有哪些?有什麼區別?

  • 新生代回收器:SerialParNewParallel Scavenge
  • 老年代回收器:Serial OldParallel OldCMS
  • 整堆回收器:G1

新生代垃圾回收器通常採用的是複製算法,複製算法的優勢是效率高,缺點是內存利用率低;老年代回收器通常採用的是標記-整理的算法進行垃圾回收。

 

簡述分代垃圾回收器是怎麼工做的?

分代回收器有兩個分區:老生代和新生代,新生代默認的空間佔比總空間的 1/3,老生代的默認佔比是 2/3

新生代使用的是複製算法,新生代裏有 3 個分區:EdenTo SurvivorFrom Survivor,它們的默認佔比是 8:1:1,它的執行流程以下:

  • Eden + From Survivor 存活的對象放入 To Survivor 區;
  • 清空 Eden From Survivor 分區;
  • From Survivor To Survivor 分區交換,From Survivor To SurvivorTo Survivor From Survivor

每次在 From Survivor To Survivor 移動時都存活的對象,年齡就 +1,當年齡到達 15(默認配置是 15)時,升級爲老生代。大對象也會直接進入老生代。

老生代當空間佔用到達某個值以後就會觸發全局垃圾收回,通常使用標記整理的執行算法。以上這些循環往復就構成了整個分代垃圾回收的總體執行流程。

 

經常使用的 JVM 調優的參數都有哪些?

  • -Xms2g:初始化推大小爲 2g
  • -Xmx2g:堆最大內存爲 2g
  • -XX:NewRatio=4:設置年輕的和老年代的內存比例爲 1:4
  • -XX:SurvivorRatio=8:設置新生代 Eden Survivor 比例爲 8:2
  • –XX:+UseParNewGC:指定使用 ParNew + Serial Old 垃圾回收器組合;
  • -XX:+UseParallelOldGC:指定使用 ParNew + ParNew Old 垃圾回收器組合;
  • -XX:+UseConcMarkSweepGC:指定使用 CMS + Serial Old 垃圾回收器組合;
  • -XX:+PrintGC:開啓打印 gc 信息;
  • -XX:+PrintGCDetails:打印 gc 詳細信息。
相關文章
相關標籤/搜索