Interview

CopyOnWriteArrayListjava

 

瞭解寫時複製機制、瞭解其適用場景、思考爲何沒有ConcurrentArrayListredis

      內部持有一個ReentrantLock的可衝入鎖,在增長、刪除是加鎖,使用try finally來在finally的最後語句塊當中解鎖,在增長、刪除時候複製出來一個新的數組,來完成增長、刪除的操做,提升查詢的效率,查詢的時候查詢原來的數組,操做完成後將新數組的引用,賦值給原來的引用。底層數組使用volatile transient修飾的數組,採用volatile transient修飾的緣由,用transient修飾的數據不會被序列化,對於volatile,從java內存模型的角度,每一個線程都有本身的工做內存,處理數據時候獲取中內存數據的拷貝,volatile修飾以後,就禁止了這種拷貝,直接獲取主內存,保證的指令可見性,而不是數據的可見性,還會禁止jvm底層對數據的重排序,使用場景,好比說CopyOnArrayList的成員變量,這種狀況有多個線程併發同時訪問的變量,並且既不是常量,也沒有在synchronzed()的同步代碼塊中。CopyOnArrayList的使用場景:適用於讀多寫少的併發場景。爲何沒有ConcurrentArrayList這樣的數據結構?由於保證線程安全會有各類各樣的手段,可是在保證線程安全的前提下,還要保證性能瓶頸,這就很難了,對於List這樣的數據結構是作不到的,好比說在contains()這樣的方法中,遍歷的時候必定要鎖住整個list的,採用分段鎖也不合適,總不能數組有多少長度就用多少個分段鎖吧,concurrentHahsMap的分段鎖一旦肯定後,即時數組擴容,也不會變了。即時線程安全的CopyOnArrayList也只規避了讀操做的併發瓶頸。算法

ConcurrentHashMapspring

瞭解實現原理、擴容時作的優化、與HashTable對比。數據庫

  concurrentHashMap是基於分段鎖來實現的,默認是16,有一個參數叫作concurrentLevel,該值說明有多少個分段鎖,segment繼承自ReentrantLock,1.8採用cas來實現避免加鎖提升性能,只有內存值與當前值一致,纔會修改爲功。Cas是樂觀鎖,synchronized等等都是悲觀鎖。Cas有一個問題,會產生ABA的問題,好比線程A B都從內存當中取了值,這是線程2修改了值,作了一些操做有把值修改回去了,這時候線程1cas仍是成功的,可是線程2的操做就被忽略了,因此能夠考慮加版本號,修改時除了比較當前值還要校驗版本號。HashTable是直接在方法上的synchronized來保證安全的,併發是會有性能瓶頸的。擴容時候的優化能夠考慮從避免rehash來回答。新建數組爲原來長度的一倍,把原來的數據遍歷放進來。數組

常見問題緩存

  • ConcurrentHashMap是如何在保證併發安全的同時提升性能?

使用細粒度的鎖分段鎖來實現線程安全、以及CAS來保證線程安全,不會有性能併發瓶頸。安全

  • ConcurrentHashMap是如何讓多線程同時參與擴容?

數組鏈表加紅黑樹,以前是頭插,如今是尾插,鏈表的最後一個數據的next爲null,併發擴容不會next不會產生死循環。優化角度避免重複hash。服務器

  • LinkedBlockingQueue、DelayQueue是如何實現的?

前者基於鏈表、後者基於優先級隊列。數據結構

  • CopyOnWriteArrayList是如何保證線程安全的?

新增、修改、刪除,複製一個數組來完成操做,完成後指向原來的引用,讀操做不會影響性能瓶頸。ReentrantLock可衝入鎖。

ThreadLocal

瞭解ThreadLocal使用場景和內部實現

  ThreadLocal的內部實現:ThreadLocal底層是有靜態內部類ThreadLocalMap來實現的,ThreadLocal有一個靜態內部類叫作ThreadLocalMap,ThreadLocalMap有一個靜態內部類叫作Entry,entry是弱引用機制的,entry有一個屬性是value,存儲數據,key是當前threadLocal對象,Thread持有ThreadLocalMap引用。每一個線程保存變量的副本。

  使用場景:某次請求,同一個線程下數據的傳遞,不然只能靠方法的返回值,解耦操做。在某些框架上,若是不用threadLocal,會有耦合的問題。還能夠透傳全局上下文,經過設置Thread構造函數的最後一個參數initThreadLocal,設置爲true。

  缺點:線程池服用Thread對象,會有髒數據的問題,static 修飾會有內存溢出的問題,原本entry實現弱引用,想要經過GC來回收,value,static修飾方法區當中會有引用,致使沒法回收。解決辦法:remove()。

  解決線上日誌上那臺服務器上去找?

  ThreadLocal存儲當前請求的traceID,根據id去找對應的日誌文件。Value存IP。

ThreadPoolExecutor

瞭解線程池的工做原理以及幾個重要參數的設置

1:核心線程數:若是爲0,線程結束後全部線程都會被銷燬。若是不爲0,假設是n,會保留n個線程做爲核心線程。

2:最大線程數:線程池中最多有當前數量的併發線程。

3:阻塞隊列:LinkedBlockQueue,存儲待執行的任務,使用鎖來保證入隊出隊的原子性。

4:超時時間:多長時間回收空閒線程。核心線程默認是不會被回收的,有一個參數叫作容許核心線程超時設置爲true,就能夠回收了。

5:時間單位:時間單位

6:線程工廠:

7:拒絕策略:

l  丟棄任務,拋出異常(默認)

l  丟棄任務

l  丟棄最近最少使用的任務最久的

l  調用任務的run方法繞過線程池執行

 

線程池有幾種類型:

new FixedThreadPool()建立固定大小的線程池

new singleThreadExecutor()建立單個線程池

new ScheduledThreadPool()建立可調度的線程池

new CheThreadPool()可伸縮的線程池

new WorkStealingPool() jdk8新出的

原理:主要是execute()、addWork()這兩個方法:

Execute執行任務,addWork()是用來建立線程,內部由32位的二進制數來表示,高三位表示線程池的狀態,一共有五種狀態,runnable:能夠接受任務,shutdown:不能接受任務,能夠執行正在處理任務stop:不能接受任務,中止正在執行的任務。Tyding:全部任務都已被終止Terminated:已經清理完現場。首先會判斷線程數是否小於核心線程數,若是是,建立線程。不然判斷線程池是不是runnable狀態,若是是置於隊列,不是從隊列移除。

  • 說一說往線程池裏提交一個任務會發生什麼?

Execute方法的執行流程,先判斷工做線程數是否大於核心線程數,若是沒有,那麼就建立線程,不然判斷線程是不是可運行狀態,放到阻塞隊列中。若是不是從阻塞隊列中刪除。在不知足可運行狀態、或者緩存滿了,達到了最大線程數,執行拒絕策略。

  • 線程池的幾個參數如何設置?
  • 線程池的非核心線程何時會被釋放?

達到空閒時間以後會被回收

任務執行完成以後,會設置空閒時間,到時間以後回收。

  • 如何排查死鎖?

引用

瞭解Java中的軟引用、弱引用、虛引用的適用場景以及釋放機制

強引用:不會被在可以被根節點可達的狀況下,不會被回收。Object object = new Object();即時系統立刻OOM了,也不會被回收。

軟引用:有這樣一個類,softRefferrence來定義,在系統OOM以前會被回收。適用於緩存,或者服務器計算的中間結果。

弱引用:YGC年輕代GC時會被回收,有WeakReferrence來調用,在引用的對象置爲null時,能夠主動斷開鏈接,這是弱引用的使命。

虛引用:每一種引用都有一個對應的類來描述,定義以後就沒法指向獲取引用的對象。設置虛引用的目的是爲了回收是獲取一個系統通知。

常見問題

  • 軟引用何時會被釋放

OOM

  • 弱引用何時會被釋放

YGC,當引用的對象設置爲null,會自動斷開引用

類加載

瞭解雙親委派機制

加載一個類時候,判斷父類有沒有加載,若是父類加載過了,就無需加載。若是沒有加載,而且加載不了,就委託子類加載。

常見問題

  • 雙親委派機制的做用?

避免重複加載類,在內存中有不少重複類的字節碼,因此有父類加載優先加載,若是已經加載過了,子類就不能再加載了。防止內存中字節碼爆炸。自定義的類加載器加載的特定位置的類,自定義類加載器加載特殊位置的類。

  • Tomcat的classloader結構
  • 如何本身實現一個classloader打破雙親委派

  繼承classloader,重寫findclass方法,找到自定義目錄下的文件,生成二進制流,調用defineClass()生成Class。何時須要自定義加載器?好比擴展加載源,好比數據庫的驅動,系統自帶的類加載確定沒法加載。

jvm

 

GC

 

垃圾回收基本原理、幾種常見的垃圾回收器的特性、重點了解CMS(或G1)以及一些重要的參數

 

內存區域

 

能說清jvm的內存劃分

 

Jvm的體系劃分:

 

本地方法棧:

 

封裝的須要調用的本地方法,好比System.currentMillions()

 

虛擬棧:

 

方法的執行就是棧幀入棧出棧的過程,正在執行的方法就是棧頂的棧幀。

 

操做變量表:相似於槽,存儲標識地幾個變量的值。存儲方法的局部變量,參數,沒有準備階段,因此必需要立刻初始化。

 

操做數棧:壓棧入棧去作計算

 

動態連接:棧幀當中包含對常量池的引用。

 

方法出口:方法的返回值,包括正常返回,異常返回

 

堆:年輕代老年代。Eden survior1 surviior2 8:1:1。新建立的對象分配在Eden中,若是滿了會觸發YGC,把活着的對象放到未使用的輸入survior中,每一個對象都有一個計數器,每經歷一次YGC,就加1,默認達到15次,就放到老年代。MaxTuringThreshold默認15次。若是一個對象elden區放不下,就會YGC,還放不下,就會放到老年代,還放不下,就會FULL GC,還放不下,就會報錯。OOM。String字符串常量是在堆中。

 

程序計數器:CPU時間片切換到執行的不一樣線程,等在回到記錄上一個線程執行的位置。

 

元數據區:方法信息、靜態屬性,常量,類信息、常量池

 

常見問題

 

  • CMS GC回收分爲哪幾個階段?分別作了什麼事情?

 

Cms利用三種顏色來完成標記。黑:可以被GCroot直接找到的沒有引用白色節點的。白色:須要回收的對象。灰色:可以被GCroot可達,可是沒有掃描完成的。

 

Cms有四個階段:

 

a)          初始標記:從GCroot出發,找到全部直接引用的節點。Stw

 

b)          併發標記:以上一階段的節點爲根節點,併發遍歷標記。Stw

 

c)           從新標記:併發標記GCroot可能有引用關係的變化,因此須要從新標記。從根節點,GCroot遍歷,從新標記。

 

d)          併發清理:併發清理全部對象。標記清理:會有空間碎片的問題。

 

回收的原則:浮動垃圾,以前有引用,如今沒有引用了,發現不了,回收原則:可達的對象絕對不能回收,能夠有垃圾沒有回收。

 

  • CMS有哪些重要參數?

 

1:老年代使用率達到某個閾值,開啓fullGC。

 

2:執行了多少次的不壓縮的full gc 來一次壓縮的full gc。

 

  • Concurrent Model Failure和ParNew promotion failed什麼狀況下會發生?

 

  ConcurrentModelFilure:有大量對象從elden升級到老年代,老年代放不下,報的錯誤。解決辦法:開啓串行老年代收集器,回收整個老年代。

 

  ParNew promotion failed:晉升擔保失敗:空間碎片的問題,來一次標記整理算法回收。

 

  • CMS的優缺點?

 

缺點:有空間碎片化的問題,這是須要內存整理

 

優勢:減小stw的次數。配置執行了多少次的full gc,採起作內存整理。

 

 

 

  • 有作過哪些GC調優?

 

好比說:設置jvm的啓動參數:XMS XMX最小堆內存與最大堆內存,設置成同樣的大小,不然服務器會不斷地收縮與擴容,增長系統的壓力。調節elden區域surior區的交換次數參數,maxTurningThreshold,將年輕代的轉爲老年代。或者配置參數UseG1Gc啓動新的G1垃圾回收器。

 

  • 爲何要劃分紅年輕代和老年代?

 

對象的聲明週期不一樣。

 

  • 年輕代爲何被劃分紅eden、survivor區域?

 

採用複製算法回收,須要額外得存儲區域作擔保。

 

  • 年輕代爲何採用的是複製算法?

 

須要頻繁的作對象的建立於回收,對象聲明週期較短。

 

  • 老年代爲何採用的是標記清除、標記整理算法

 

老年代聲明週期比較長,若是採用複製算法須要其餘內存做擔保,保留存活的對象。年輕代老年代分配比例是3:8。

 

  • 什麼狀況下使用堆外內存?要注意些什麼?

 

對外內存:java.nio.DirectorByteBuffer分配的內存是堆外內存,優勢:提升io效率。缺點:堆外內存回收相對堆外內存來講耗時間。底層:unsafe.allocateMemory()來分配。每個DirctorByteBuffer初始化都會有一個Cleaner對象調用cleaner()來回收。

 

  • 堆外內存如何被回收?
  • jvm內存區域劃分是怎樣的?

spring

 

  bean的生命週期、循環依賴問題、spring cloud(如項目中有用過)、AOP的實現、spring事務傳播

 

循環依賴問題:

 

  好比說spring當中的自動裝配,A依賴了B,B依賴了A,這個時候在實例化A類的這個對象時候,須要依賴B,A沒法實例化,在實例化B的對象時候,依賴了A對象,B對象也沒法完成實例化,須要在AutowiredBeanPostProcessor後置處理器中完成屬性的注入。

 

  Spring是這樣處理的,他設計了一級緩存,已經實例化單例對象的緩存、二級緩存,正在建立中的對象的緩存、三級緩存,單例對象工廠的緩存,這樣的map,在refresh()方法當中,倒數第二個方法實例化bean,首先實例化時候從一級緩存中獲取,以及緩存存儲已經實例化完成的單例對象,若是沒有,從二級緩存中獲取,二級緩存存儲的是正在建立中的對象,二級緩存若是沒有,有一個暴露對象的參數,true,能夠從三級緩存中獲取,這個時候是有的。就能夠經過AutowiredBeanPostProcessor自動裝配的後置處理器干擾bean的實例化過程。

  • spring事務傳播

當前沒有事務,建立事務,有事務,就加入到這個事務中來等等。

或者就直接新建事務。

  • spring中bean的生命週期是怎樣的?

Spring當中完整的bean的聲明週期,從構造函數初始化開始,實例化一個AnnotationConfigApplicationContext開始,接下來就能夠從容器中獲取bean,說明,在構造函數當中就已經完成了spring當中的bean的初始化,以及準備spring的環境。首先會調用this()函數,初始化defaultListableBeanFactory,在實例化一個reader以及scanner,實例化reader會添加5個beanpostProcessor以及一個beanFactoryPostProcessor。接下來會註冊beanDefinition到beanFactory當中。Refresh()方法完成spring容器的準備,bean的實例化。初始化一個applicationcontextAware後置處理器,調用後置處理器,以及實例化bean。

  • 屬性注入和構造器注入哪一種會有循環依賴的問題?

構造器注入會有循環依賴的問題。屬性注入就是setter注入,由於構造函數立刻就會建立對象,沒法完成依賴注入。屬性注入,能夠利用到緩存。一級緩存、二級緩存、三級緩存。

Spring如何實例化對象的?

經過反射,首先經過工廠方法來實例化對象,在經過構造函數,依據參數的類型去實例化,最後經過默認的構造函數,spring底層作了一個這樣的判斷。

redis

redis工做模型、redis持久化、redis過時淘汰機制、redis分佈式集羣的常見形式、分佈式鎖、緩存擊穿、緩存雪崩、緩存一致性問題

@PostConstruct:緩存預熱,在構造函數初始化以後執行

@PreDestroy:在bean銷燬以後執行

常見問題

  • redis性能爲何高?

基於內存數據庫,數據結構簡單,沒有磁盤io,主要是io模型牛逼。

  • 單線程的redis如何利用多核cpu機器?
  • redis的緩存淘汰策略?

Redis的config配置文件中配置最大內存,超過以後,會有6種拒絕策略。

1:noeviction: 不刪除策略, 達到最大內存限制時, 若是須要更多內存, 直接返回錯誤信息。 大多數寫命令都會致使佔用更多的內存(有極少數會例外, 如 DEL )。

2:allkeys-lru: 全部key通用; 優先刪除最近最少使用(less recently used ,LRU) 的 key。

3:volatile-lru: 只限於設置了 expire 的部分; 優先刪除最近最少使用(less recently used ,LRU) 的 key。

4:allkeys-random: 全部key通用; 隨機刪除一部分 key。

5:volatile-random: 只限於設置了 expire 的部分; 隨機刪除一部分 key。

6:volatile-ttl: 只限於設置了 expire 的部分; 優先刪除剩餘時間(time to live,TTL) 短的key。

  • redis如何持久化數據?

RDB:將持久化的數據寫到文件中。

AOF:記錄執行的指令。

  • redis有哪幾種數據結構?

List 、set、 string、 hash、 sortedSet

  • redis集羣有哪幾種形式?

哨兵模式:sentinel,監控master slave,若是master掛了,把slave升級爲slave。

  • 有海量key和value都比較小的數據,在redis中如何存儲才更省內存?
  • 如何保證redis和DB中的數據一致性?

查詢若是緩存沒有就查庫,更新數據庫,是緩存失效。

  • 如何解決緩存穿透和緩存雪崩?
  • 如何用redis實現分佈式鎖?

加鎖:

解鎖:

相關文章
相關標籤/搜索