【春招實習】貝殼金服電話一面:
面試過程及內容:
-
自我介紹
建議這塊在電話面試的時候準備一份自己的簡歷,方便在自我介紹的時候挑出重點,能夠比較快速和流暢的介紹自己。
-
Java有幾種基本類型,int和float類型各佔幾個字節?
Java中總共有八種數據類型:byte(1)、short(2)、int(4)、long(8)、char(2)、float(4)、double(8)和boolean;
PS: 括號內的爲各個類型所佔的字節數。
-
Java集合:HashMap是否會存在線程安全問題,如何解決?
HashMap可能會出現的線程安全問題的地方:
- HashMap中插入數據:假設正好存在兩個 put 的 key 發生了碰撞(根據 hash 值計算的 bucket 一樣)的線程A、B,然後對同一個數組位置調用createEntry方法,兩個線程都會同時得到頭結點,然後A寫入新的頭結點之後,B也寫入新的頭結點,那B的寫入操作就會覆蓋A的寫入操作造成A的寫入操作丟失。
- HashMap擴容的時候:
- 如果多個線程同時檢測到元素個數超過數組大小 ,這樣就會發生多個線程同時對 Node 數組進行擴容,都在重新計算元素位置以及複製數據,但是最終只有一個線程擴容後的數組會賦給 table,也就是說其他線程的都會丟失,並且各自線程 put 的數據也丟失。
- HashMap 在併發執行 put 操作時會引起死循環,導致 CPU 利用率接近100%。因爲多線程會導致 HashMap 的 Node 鏈表形成環形數據結構,一旦形成環形數據結構,Node 的 next 節點永遠不爲空,就會在獲取 Node 時產生死循環。
如何安全的使用HashMap?
- Hashtable
- ConcurrentHashMap
- Collections.synchronizedMap(new HashMap(…));
-
Map,Array,list三者的區別和共同點,以及時間複雜度?(其實我覺得當時的面試官應該是想問我:Map,Set和list三者的區別?)
當時自己就着重回答了Arraylist和linkedlist的區別:
- 實現的不同:ArrayList是實現了基於動態數組的數據結構,而LinkedList是基於鏈表的數據結構;
- 訪問速度的不同:隨機訪問get和set,ArrayList要優於LinkedList,因爲LinkedList要移動指針;
- 插入刪除速度的不同:一般都認爲LinkedList要比ArrayList快,但是這僅適用於從隨機位置插入(因爲數組從中間插入,需要移動元素),當從尾部插入數據時,插入的數據量很小時,兩者區別不太大,當插入的數據量大時,大約在容量的1/10之前,LinkedList會優於ArrayList,在其後就劣與ArrayList,且越靠近後面越差。
Map,Set和list三者的區別:
- list:其中的值允許重複,因爲其爲有序的數據結構 ,允許空值
- 三個實現類:LinkedList、ArrayList、Vector
- set :其中的值不允許重複,無序的數據結構 (Set 集合根據 hashcode 來進行數據的存儲,所以位置是固定的,但是位置不是用戶可以控制的,所以對於用戶來說 set 中的元素還是無序的)
- 兩個實現類:TreeSet 、HashSet
- map:成對的數據結構,健值必須具有唯一性(鍵不能同,否則值替換)
- 四個實現類:HashMap、HashTable、SortMap、 LinkedHashMap
-
Abstract(抽象類)和interface(接口)的區別?
不同點:
- 抽象類中可以有構造方法,接口中不能;
- 抽象類中可以有普通成員變量,接口中不能;
- 抽象類中可以包含普通方法,接口中不能;
- 抽象類中的訪問權限是:public、protect,接口中只能是 public;
- 抽象類中可以包含靜態方法,接口中不能;
- 抽象類中可以包含任意類型的靜態成員變量,接口中只能是public static final;
- 一個類只能繼承一個類,但是可以繼承多個接口;
相同點:
- 不能夠實例化
- 可以將抽象類和接口類型作爲引用類型
- 一個類如果繼承了某個抽象類或者實現了某個接口都需要對其中的抽象方法全部進行實現,否則該類仍然需要被聲明爲抽象類
-
Http、TCP/IP的區別與關係?
TPC/IP協議是傳輸層協議,主要解決數據如何在網絡中傳輸,而HTTP是應用層協議,主要解決如何包裝數據。
自己補充說了一下有關https的東西,https大致的請求過程如圖
-
MySQL多表查詢、索引以及索引的底層實現
這部分大概就舉了一個實際的例子進行分析,然後說了下索引的使用條件,以及底層實現所用的B樹和B+樹
-
Java線程狀態有多少種?以及各個狀態之間如何轉化?
-
新建(new):新創建了一個線程對象。
-
就緒(runnable):線程對象創建後,其他線程(比如main線程)調用了該對象的start()方法。該狀態的線程位於可運行線程池中,等待被線程調度選中,獲取cpu 的使用權 。
-
運行(running):可運行狀態(runnable)的線程獲得了cpu 時間片(timeslice) ,執行程序代碼。
-
阻塞(block):阻塞狀態是指線程因爲某種原因放棄了cpu 使用權,也即讓出了cpu timeslice,暫時停止運行。直到線程進入可運行(runnable)狀態,纔有機會再次獲得cpu timeslice 轉到運行(running)狀態。阻塞的情況分三種:
- 等待阻塞:運行(running)的線程執行o.wait()方法,JVM會把該線程放入等待隊列(waitting queue)中。
- 同步阻塞:運行(running)的線程在獲取對象的同步鎖時,若該同步鎖被別的線程佔用,則JVM會把該線程放入鎖池(lock pool)中。
- 其他阻塞:運行(running)的線程執行Thread.sleep(long ms)或t.join()方法,或者發出了I/O請求時,JVM會把該線程置爲阻塞狀態。當sleep()狀態超時、join()等待線程終止或者超時、或者I/O處理完畢時,線程重新轉入可運行(runnable)狀態。
-
死亡(dead):線程run()、main() 方法執行結束,或者因異常退出了run()方法,則該線程結束生命週期。死亡的線程不可再次復生。
-
用過Redis的原子操作嗎?
其實剛聽到這個問題還是有點蒙的,下來查了之後覺得應該是指Redis中的原子鎖:
- INCR: key不存在,那麼 key 的值會先被初始化爲 0 ,然後再執行 INCR 操作進行加一。 然後其它用戶在執行 INCR 操作進行加一時,如果返回的數大於 1 ,說明這個鎖正在被使用當中。
- SETNX:這種加鎖的思路是,如果 key 不存在,將 key 設置爲 value 如果 key 已存在,則
SETNX
不做任何動作 - getSet:獲取key的舊值,將新value放入
-
Redis 3.0 以後單機和集羣的特性?
聽到這個問題的時候,真的留下了不學無術的淚水,自己就胡扯了一下主從複製、哨兵以及單機瓶頸的原因。
Redis集羣的特點:
- 所有的redis節點彼此互聯(PING-PONG機制),內部使用二進制協議優化傳輸速度和帶寬.
- 節點的fail是通過集羣中超過半數的節點檢測失效時才生效.
- 客戶端與redis節點直連,不需要中間proxy層.客戶端不需要連接集羣所有節點,連接集羣中任何一個可用節點即可
- redis-cluster把所有的物理節點映射到[0-16383]slot(插槽)上,cluster 負責維護node<->slot<->value
總結
這次面試算是自己第一次進行電話技術面試,所以很緊張,很多問題都出現了答非所問的情況。總體感覺這次面試的難度一般,更加側重於基礎知識,只有最後兩個問題可能會稍微困難一點。以及前期可能複習側重點的問題,可能忽略了對於基礎知識的彌補,也算是對於自己的一個提醒吧。