1. 程式人生 > 其它 >面試題的一些補充

面試題的一些補充

1. ArrayList和LinkedList的區別

  1. 首先底層資料結構不同,ArrayList底層是基於陣列實現的,LinkedList是基於連結串列實現的

  2. 由於底層結構不同,適應的場景也不同,ArrayList適合隨機查詢,LinkedList適合新增和刪除,刪除.新增.查詢的時間複雜度不同

  3. 兩者都實現了list介面,但是LinkedList額外實現了Deque(雙端佇列)介面,因此LinkedList可作為佇列來使用

2.說一下Hashmap的Put方法

1.根據key通過雜湊演算法與與操作運算得到陣列下標

2.如果陣列下標位置為空,則將key和value封裝成Node物件(JDK 1.7是Entry物件;JDK 1.8是Node物件)並放入該位置

3.如果陣列下標位置元素不為空,則分情況討論

a.如果是JDK 1.7,先判斷是否需要擴容,如果需要就進行擴容,如果不用擴容就生成Entry物件,並使用**頭插法**新增到當前位置的連結串列中
b.如果是JDK 1.8,則會先判斷當前位置的Node型別,看是紅黑樹Node還是連結串列Node
  i.如果是紅黑樹Node,則將key和value封裝成紅黑樹節點並新增到紅黑樹中去,在這個過程中會判斷紅黑樹是否存在當前key,如果存在則更新value
  ii.如果此位置Node物件是連結串列節點,則將key和value封裝成連結串列Node並通過**尾插法**插入到連結串列的最後位置去,因為是尾插法,所以需要遍歷整個連結串列,在遍歷連結串列的過程中會判斷是否存在當前key,如果存在則更新value,當遍歷完連結串列後,將新連結串列Node插入到連結串列中,插入到連結串列後,會看到當前連結串列的節點個數,如果超過了8,則會將連結串列轉化為紅黑樹
  iii.將key和value封裝成Node插入到連結串列或者紅黑樹中後,才回去判斷是否需要擴容,需要就擴容,不需要就結束Put方法

3.說一下ThreadLocal

1.是Java中所提供的的執行緒本地儲存機制,可以利用該機制將資料快取在某個執行緒內部,該執行緒可以在任意時刻,任意方法中獲取快取的資料
2.ThreadLocal底層是通過ThreadLocalMap來實現的,每個Thread物件(注意:不是ThreadLocal物件)中都存在一個ThreadLocalMap,Map的key為ThreadLocal物件,Map的value為需要快取的值
3.如果線上程池中使用ThreadLocal會造成記憶體洩露,因為當ThreadLocal物件使用完之後,應該要把設定的key,value,也就是Entry物件進行回收,但執行緒池的執行緒不會回收,而執行緒物件是通過強引用指向ThreadLocalMap,ThreadLocalMap也是強引用指向Entry物件,執行緒不被回收,Entry也就不會被回收,從而出現記憶體洩漏,解決方法是:在使用了ThreadLocal物件之後,手動呼叫ThreadLocal的remove方法,手動清除Entry物件
4.ThreadLocal經典的應用場景就是連線管理(一個執行緒持有一個連線,連線物件可以在不同的方法之間進行傳遞 ,執行緒之間不共享同一個連線)

4.說一下JVM中,哪些是共享區,哪些可以作為GC ROOT?

1.方法區和堆都是所有執行緒共享的,虛擬機器棧,本地方法棧,程式計數器都是每個執行緒獨有的
2.什麼是GC ROOT,jvm在進行垃圾回收時,需要找到"垃圾"物件,也就是沒有引用的物件,但是直接找"垃圾"物件是比較耗時的,所以反過來,先找"非垃圾"物件,也就是正常物件 ,name就需要從某些"根"的引用路徑查詢到正常物件,而這些"根"有個特徵,就是它會引用其他物件,而不會被其他物件引用.
例如:棧中的本地變數,方法區的靜態變數,本地方法棧的變數,正在執行的執行緒等都可以作為GC ROOT

5.如果檢視執行緒死鎖?

1.可以通過jstack命令來檢視,jstack命令中會顯示發生了死鎖的執行緒
2.或者兩個執行緒去操作資料庫時,資料庫發生了死鎖,這時可以查詢資料庫的死鎖情況

6.執行緒之間如何進行通訊的?

1.執行緒之間基於共享記憶體或者基於網路來進行通訊
2.如果是共享記憶體來進行通訊 ,則需要考慮併發問題,什麼時候阻塞,什麼時候喚醒
3.java中wait()是阻塞,notify()是喚醒
4.通過網路就比較簡單了,通過網路連線將通訊資料傳送給對方,當然也要考慮到併發的問題,處理方式就是加鎖等方式

7.介紹一下Spring,通過原始碼介紹下大致流程?

1.Spring是一個快速開發框架,Spring幫助程式設計師來管理物件
2.Spring的原始碼實現是非常優秀的,包括併發安全的實現,面向介面的設計,設計模式的應用等
3.在建立Spring容器,也就是啟動Spring時:
a.首先會進行掃描,掃描得到所有的BeanDefinition物件並存在一個Map中
b.然後篩選出非懶載入的單例BeanDefinition進行建立Bean,對於多例Bean則不需要在啟動的過程中去建立,對於多例 Bean會在每次獲取Bean時利用BeanDefinition去建立
c.利用BeanDefinition建立Bean就是Bean的建立生命週期,這期間包括了合併BeanDefinition,推斷構造方法,例項化,屬性填充,初始化前,初始化,初始化後等步驟,其中AOP就是發生在初始化後這一步驟的
4.單例Bean建立完之後,Spring會發佈一個容器啟動事件
5.Spring啟動結束
6.在原始碼中會更加複雜,比如原始碼中提供一些模板方法,讓子類來實現,比如BenaFactoryPostProcessor和BeanPostProcessor的註冊,Spring的掃描就是通過BenaFactoryPostProcessor來實現的,依賴注入就是通過BeanPostProcessor
7.在Spring啟動過程中還會去處理@import註解

8.說一下Spring的事務機制

1.Spring事務底層是基於資料庫事務和AOP機制的
2.首先對於使用了@Transactional註解的Bean,Spring會建立一個代理物件作為Bean
3.當呼叫代理物件的方法時,會判斷該方法是否加了Transactional註解
4.如果加了,則會利用事務管理器建立一個數據庫連線
5.並且修改資料庫連線的autocommit屬性會為false,禁止此連線的自動提交,這是實現Spring的事務非常重要的一步
6.然後執行當前方法,方法中會執行sql
7.執行完當前方法後,如果沒有出現異常就直接提交事務
8.如果出現了異常,並且這個異常是需要回滾的就會回滾事務,否則仍然提交事務
9.Spring的事務的隔離級別對應的就是資料庫的隔離級別
10.Spring事務的傳播機制是Spring事務自己實現的,也是Spring事務中最複雜的
11.Spring事務的傳播機制是基於資料庫連線來做的,一個數據庫連線一個事務,如果傳播機制配置為需要新開一個事務,那麼實際上就是先建立一個數據庫連線,在此新資料庫連線在執行sql

9.什麼時候@Transactional失效?

1.Spring事務是基於代理來實現的,所以某個加了@Transactional的方法只有是被代理物件呼叫時,這個註解才會生效;如果不是被代理物件呼叫這個方法時,那麼@Transactional註解是不會生效的
2.同時如果某個方法是private的 ,那麼@Transactional也會失效,因為底層cglib是基於父子類來實現的,子類是不能過載父類的private方法的,所以無法很好的利用代理,也會導致@Transactional失效
3.方法丟擲的異常並不屬於rollbackFor所指定的異常或者子類的異常的話,@Transactional也會失效

10.Dubbo是如何做系統互動的?

1.Dubbo底層是通過RPC來完成服務和服務之間的呼叫的,Dubbo支援很多協議,比如預設的dubbo協議,比如http協議,比如rest等都是支援的,它們的底層所使用的技術是不太一樣的,比如dubbo協議底層使用的是netty,也可以使用mina,http協議底層使用的是tomcat或者jetty.
(RPC, Remote Procedure Call 即遠端過程呼叫。見名知意:從遠端主機呼叫一個過程/函式。
RPC 的目標是:使得本程式呼叫其它遠端主機上的函式,好像呼叫本程式內的函式一樣簡單,並且遮蔽程式語言的差異性。
要實現上述目標首先需要設計一種通訊協議,這被稱為:RPC協議(RPC Protocol)
2.服務消費者在呼叫某個服務時,會將當前所呼叫的服務介面資訊,當前方法資訊 ,執行方法所傳入的入參資訊等組裝成一個Invocation物件,然後不同的協議通過不同的資料組織方式和傳輸方式將這個物件傳送給服務提供者,提供者接收到這個物件後,找到對應的服務實現,利用反射執行相應的方法 ,得到方法結果在通過網路響應給服務消費者
3.當然,Dubbo在這個呼叫工程中還做很多其他的設計,比如服務容錯,負載均衡,Filter機制,動態路由機制等,讓Dubbo能處理更多企業中的需求.

11.Dubbo的負載均衡策略

Dubbo目前支援:

1.平衡加權輪詢演算法
2.加權隨機演算法
3.一致性雜湊演算法
4.最小活躍數演算法