Linux下安裝SOAR及相關環境配置
某Java大佬在地表最強Java企業(阿里)面試總結
一面
1.1、HashMap和Hashtable的區別
繼承:
Hashtable繼承自Dictionary類,而HashMap繼承自AbstractMap類。但二者都實現了Map介面。
鎖:
Hashtable 中的方法是Synchronize的,而HashMap中的方法在預設情況下是非Synchronize的。
方法:
HashMap把Hashtable的contains方法去掉了,改成containsValue和containsKey,因為contains方法容易讓人引起誤解。
是否可以為null:
Hashtable中,key和value都不允許出現null值。
HashMap中,null可以作為鍵,這樣的鍵只有一個。
Hashtable中有類似put(null,null)的操作,編譯同樣可以通過,因為key和value都是Object型別,但執行時會丟擲NullPointerException異常,這是JDK的規範規定的。
Tips:
當get()方法返回null值時,可能是 HashMap中沒有該鍵,也可能使該鍵所對應的值為null。因此,在HashMap中不能由get()方法來判斷HashMap中是否存在某個鍵, 而應該用containsKey()方法來判斷。
遍歷:
Hashtable、HashMap都使用了 Iterator。但是,Hashtable還使用了Enumeration的方式 。
計算Hash值:
HashTable直接使用物件的hashCode。
HashMap的Hash值:(key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
容量:
HashTable在不指定容量的情況下的預設容量為11,而HashMap為16,
Hashtable不要求底層陣列的容量一定要為2的整數次冪,而HashMap則要求一定為2的整數次冪。
Hashtable擴容時,將容量變為原來的2倍加1,而HashMap擴容時,將容量變為原來的2倍。
1.2、實現一個保證迭代順序的HashMap
使用HashMap的一個子類LinkedHashMap(順序遍歷的HashMap)進行研究
放入方法中:
重寫了最關鍵的Node<K, V> newNode(int hash, K key, V value, Node next)方法,該方法首先建立一個HashMap.Node的子類LinkedHashMap.Entry,它比Node多了兩個指標Entry<K, V> before, after;//用於儲存前後兩個節點的資訊。
Tips:
LinkedHashMap擁有兩個瞬時的屬性transient LinkedHashMap.Entry<K,V> tail;//用於儲存上一個元素,即表尾;
transient LinkedHashMap.Entry<K, V> head;//用於儲存第一個元素,即表頭。
遍歷:
使用LinkedEntryIterator
迭代器進行遍歷,繼承於abstract class LinkedHashIterator
抽象類。該迭代器擁有兩個Entry的指標next
和current
,並結合Entry中的before
和after
指標,實現了LinkedHashMap中元素的順序遍歷。
LinkedHashIterator的nextNode
方法使用了LinkedHashMap.Entry<K, V>的after屬性
,使得iterator的遍歷按照放入順序進行的。
取值方法:
LinkedHashMap重寫了Map介面的V get(Object key)方法,該方法分兩個步驟:
- 呼叫父類HashMap的getNode(hash(key), key)方法,獲取value;
- 如果accessOrder(訪問後重排序)為true(預設為false),那麼移動所訪問的元素到表尾,並修改head和tail的值。
1.3、 說一說排序演算法,穩定性,複雜度
這個東西還是面試前把每個排序演算法都看一看比較好
1.4、 說一說GC
堆(新生代和老生代)
是Java虛擬機器進行垃圾回收的主要場所,其次要場所是方法區(永久代)
。
在堆中進行垃圾回收分為新生代和老生代;將新生代分成了三個獨立的區域
(這裡的獨立區域只是一個相對的概念,並不是說分成三個區域以後就不再互相聯合工作了),
分別為:Eden區、From Survivor區以及To Survivor,而Eden區分配的記憶體較大,其他兩個區較小,每次使用Eden和其中一塊Survivor。
在進行垃圾回收時,將Eden和Survivor中還存活著的物件進行一次性地複製到另一塊Survivor空間上,直到其兩個區域中物件被回收完成,
當Survivor空間不夠用時,需要依賴其他老年代的記憶體進行分配擔保。當另外一塊Survivor中沒有足夠的空間存放上一次新生代收集下來的存活物件時,這些物件將直接通過分配擔保機制進入老生代,大物件和長期存活的物件也會直接進入老年代。
如果老生代的空間也被佔滿,當來自新生代的物件再次請求進入老生代時就會報OutOfMemory異常。
新生代中的垃圾回收頻率高, ,儲存在JVM的方法區(永久代)中的物件一般不會被回收。
其永久代進行垃圾回收的頻率就較低,速度也較慢。
永久代的垃圾收集主要回收廢棄常量和無用類。
判斷一個類是否被回收,則需同時滿足的條件:
該類所有的例項和ClassLoader都已經被回收。
該類的物件沒有被引用,無法通過反射訪問,這裡說的是可以回收而不是必然回收。
大多數情況下,物件在新生代Eden區中分配,當Eden區沒有足夠空間進行分配時,虛擬機器將發起一次Minor GC;
同理,當老年代中沒有足夠的記憶體空間來存放物件時,虛擬機器會發起一次Major GC/Full GC。只要老年代的連續空間大於新生代物件總大小或者歷次晉升的平均大小就會進行Minor GC,否則將進行Full CG。
虛擬機器通過物件年齡計數器來判斷存放在哪:
如果物件在Eden出生並經過一次Minor GC後仍然存活,並且能被Survivor容納的話,將被移動到Survivor空間中,並將該物件的年齡設為1。
物件每在Survivor中熬過一次Minor GC,年齡就增加1歲,當他的年齡增加到最大值15(MaxTenuringThreshold)時,就將會被晉升到老年代中。
如果在Survivor空間中所有相同年齡的物件大小的總和大於Survivor空間的一半,年齡大於或等於該年齡的物件就可以直接進入老年代,無需等到MaxTenuringThreshold中要求的年齡。
Jdk8開始廢棄永久代:
This is part of the JRockit and Hotspot convergence effort. JRockit customers do not need to configure the permanent generation (since JRockit does not have a permanent generation) and are accustomed to not configuring the permanent generation.
(移除永久代是為融合HotSpot JVM與 JRockit VM而做出的努力,因為JRockit沒有永久代,不需要配置永久代。)
由於永久代記憶體經常不夠用或發生記憶體洩露,爆出異常java.lang.OutOfMemoryError: PermGen
字串存在永久代中,容易出現效能問題和記憶體溢位。
類及方法的資訊等比較難確定其大小,因此對於永久代的大小指定比較困難,太小容易出現永久代溢位,太大則容易導致老年代溢位。
永久代會為GC帶來不必要的複雜度,而且回收效率偏低。
1.5、 可以保證的實習時長
一般都是半年到一年,(太少的話,剛教會了你,你就可能走了,太多的話也不現實)
還有可能問到什麼時候去上班,建議的話,就是下個月,或者兩週後,今天面試明天上班,肯定準備的不充分。(問這個的話,大多都是有個專案什麼的著急要人,然後面試官用你應付,)
1.6、 職業規劃
其實這個問題不只是回答面試官,更是回答自己,為什麼做,想怎麼做……
說明自己對崗位的理解和從事這份工作的原因。
說明自己願意為這份工作付出努力。
說明自己長遠的目標和規劃。
下面以產品經理為例子回答:
網際網路行業是一個高速發展的行業,同時也有大量創新和嘗試的機會(闡述自己看好行業)。
而產品經理則是網際網路企業的核心崗位之一,產品經理負責使用者需求分析、競品分析、產品設計和上下層需求的溝通,需要超強的邏輯思考和分析能力、使用者洞察能力和溝通協作能力。(闡述自己對崗位的理解)。
而我畢業於XXX大學,在大學裡曾參加XXX產品設計比賽,拿下了XXX的成績,個人非常擅長思考和分析問題,同時能處理好和團隊成員的溝通協作…(闡述自己適合這個工作)。
我認為自己非常適合這個崗位,為此,我也願意付出努力。
在過去,我曾閱讀過XXX本產品書籍,自己設計過3款產品的原型,有一款在自己的努力下成功上線,並通過持續獲取使用者反饋,收穫了XXX萬的使用者。(表達自己過去的努力)
入職以後,我希望能從助理開始,系統學習產品的基本功,在一年的時間裡面,成功掌握主流的產品設計方法論(表達自己願意付出的努力)。
我知道,優秀的產品經理不僅僅需要掌握產品設計的方法,還需要XXXX。
我會努力培養自己的業務思維,站在全域性業務的角度去思考和解決問題,為團隊做好表率…(表達自己大致的努力方向)。
每個產品經理都有自己的目標,我也一樣。
我希望在我的努力之下,在兩年以後,能夠獨擋一面,負責好一個版塊的功能;
在三到五年左右,可以負責好一個產品的規劃、設計和優化;
在未來的五到八年,可以做好一個產品的全域性規劃、團隊管理等等…
二面
2.1、 自我介紹。
自我介紹在三到五分鐘最好
一兩句話概括自己名字學校什麼的,主學的什麼,對什麼有研究,瞭解什麼(切忌:儘量別說“精通”),然後說一下以前做過的專案(具體說一些自己做的有技術的),或者什麼別的獎項,然後談一下自己對公司的瞭解以及對未來的規劃,等等。(百度有很多,隨便搜搜)
2.2、 JVM如何載入一個類的過程,雙親委派模型中有哪些方法?
類載入過程:
載入
(通過一個類的全限定名獲取定義此類的二進位制位元組流,將這個位元組流所代表的靜態儲存結構轉化為方法區域的執行時資料結構,在Java堆中生成一個代表這個類的java.lang.Class物件,作為方法區域資料的訪問入口)、
驗證
(驗證階段作用是保證Class檔案的位元組流包含的資訊符合JVM規範,不會給JVM造成危害,如果驗證失敗,就會丟擲一個java.lang.VerifyError異常或其子類異常。
1.檔案格式驗證:
驗證位元組流檔案是否符合Class檔案格式的規範,並且能被當前虛擬機器正確的處理。
2.元資料驗證:
是對位元組碼描述的資訊進行語義分析,以保證其描述的資訊符合Java語言的規範。
3.位元組碼驗證:
主要是進行資料流和控制流的分析,保證被校驗類的方法在執行時不會危害虛擬機器。
4.符號引用驗證:
符號引用驗證發生在虛擬機器將符號引用轉化為直接引用的時候,這個轉化動作將在解析階段中發生。)、
準備
(準備階段為(static)變數(不包括類的例項)分配記憶體並設定類變數的初始化,此初始化並不是賦值static int num =1,這時得num為0,並不是1)、
解析
(解析過程是將常量池內的符號引用替換成直接引用(類或介面的解析、欄位解析、方法解析、介面方法解析。))、
初始化
(這裡才是賦值階段)
使用過程:新執行緒—程式計數器----jvm棧執行(物件引用)-----堆記憶體(直接引用)----方法區。
解除安裝靠GC
雙親委派模型中方法:
雙親委派是指如果一個類收到了類載入的請求,不會自己先嚐試載入,先找父類載入器去完成。當頂層啟動類載入器表示無法載入這個類的時候,子類才會嘗試自己去載入。當回到最開的發起者載入器還無法載入時,並不會向下找,而是丟擲ClassNotFound異常。
方法:啟動(Bootstrap)類載入器,標準擴充套件(Extension)類載入器,應用程式類載入器(Application ),上下文(Custom)類載入器。意義是防止記憶體中出現多份同樣的位元組碼 。
1)啟動類載入器(Bootstrap ClassLoader):
負責載入JAVA_HOME\lib目錄中並且能被虛擬機器識別的類庫到JVM記憶體中,如果名稱不符合的類庫即使放在lib目錄中也不會被載入。該類載入器無法被Java程式直接引用。
2)擴充套件類載入器(Extension ClassLoader):
按《深入理解java虛擬機器》這本書上所說,該載入器主要是負責載入JAVA_HOME\lib\ext目錄中的類庫,但是貌似在JDK的安裝目錄下,沒看到該指定的目錄。該載入器可以被開發者直接使用。
3)應用程式類載入器(Application ClassLoader):
該類載入器也稱為系統類載入器,它負責載入使用者類路徑(Classpath)上所指定的類庫,開發者可以直接使用該類載入器,如果應用程式中沒有自定義過自己的類載入器,一般情況下這個就是程式中預設的類載入器。
2.3、 HashMap如何實現的?
HashMap的底層是陣列+連結串列,(很多人應該都知道了)
JDK1.7的是陣列+連結串列
首先是一個數組,然後陣列的型別是連結串列
元素是頭插法
JDK1.8的是陣列+連結串列 或者 陣列+紅黑樹
首先是一個數組,然後陣列的型別是連結串列
在連結串列的元素大於8的時候,會變成紅黑樹
(當連結串列長度大於8並且陣列長度大於64時,才會轉換為紅黑樹。
如果連結串列長度大於8,但是陣列長度小於64時,還是會進行擴容操作,不會轉換為紅黑樹。因為陣列的長度較小,應該儘量避開紅黑樹。因為紅黑樹需要進行左旋,右旋,變色操作來保持平衡,
所以當陣列長度小於64,使用陣列加連結串列比使用紅黑樹查詢速度要更快、效率要更高。 )
在紅黑樹的元素小於6的時候會變成連結串列
(這裡需要注意,不是元素小於6的時候一定會變成連結串列,只有resize的時候才會根據UNTREEIFY_THRESHOLD 進行轉換,同樣也不是到8的時候就變成紅黑樹(不是等到擴容的時候) 連結串列與紅黑樹的轉換詳情)
元素進行尾
插
2.4、 HashMap和Concurrent HashMap區別, Concurrent HashMap 執行緒安全嗎, Concurrent HashMap如何保證 執行緒安全?
使用ConcurrentHashMap(執行緒安全),
JDK1.7的是分段陣列,有Segment鎖(繼承於ReentrantLock)
加速一小段保證併發
JDK1.8 是和HashMap一樣了,陣列+連結串列(或者紅黑樹)
Synchronized(鎖)and CAS(compare and swap)
(JVM在1.6對Synchronize的優化很好)
CAS通俗易懂,比較並替換
(CAS是一種無鎖演算法,CAS有3個運算元,記憶體值V,舊的預期值A,要修改的新值B。當且僅當預期值A和記憶體值V相同時,將記憶體值V修改為B,否則什麼都不做)
(無鎖化的修改值的操作,他可以大大降低鎖代理的效能消耗。這個演算法的基本思想就是不斷地去比較當前記憶體中的變數值與你指定的 一個變數值是否相等,如果相等,則接受你指定的修改的值,否則拒絕你的操作。因為當前執行緒中的值已經不是最新的值,你的修改很可能會覆蓋掉其他執行緒修改的結果。這一點與樂觀鎖,SVN的思想是比較類似的)
2.5、 HashMap和HashTable 區別,HashTable執行緒安全嗎?
1.1、HashMap和Hashtable的區別
HashTable(執行緒安全)就是把HashMap套上了一個Synchronized
2.6、 程序間通訊有哪幾種方式?
管道、訊息佇列、訊號量、共享記憶體、套接字
無名管道( pipe ):
管道是一種半雙工的通訊方式,資料只能單向流動,而且只能在具有親緣關係的程序間使用。程序的親緣關係通常是指父子程序關係。
高階管道(popen):
將另一個程式當做一個新的程序在當前程式程序中啟動,則它算是當前程式的子程序,這種方式我們成為高階管道方式。
有名管道 (named pipe) :
有名管道也是半雙工的通訊方式,但是它允許無親緣關係程序間的通訊。
訊息佇列( message queue ) :
訊息佇列是由訊息的連結串列,存放在核心中並由訊息佇列識別符號標識。訊息佇列克服了訊號傳遞資訊少、管道只能承載無格式位元組流以及緩衝區大小受限等缺點。
訊號量( semophore ) :
訊號量是一個計數器,可以用來控制多個程序對共享資源的訪問。它常作為一種鎖機制,防止某程序正在訪問共享資源時,其他程序也訪問該資源。因此,主要作為程序間以及同一程序內不同執行緒之間的同步手段。
訊號 ( sinal ) :
訊號是一種比較複雜的通訊方式,用於通知接收程序某個事件已經發生。
共享記憶體( shared memory ) :
共享記憶體就是對映一段能被其他程序所訪問的記憶體,這段共享記憶體由一個程序建立,但多個程序都可以訪問。共享記憶體是最快的 IPC 方式,它是針對其他程序間通訊方式執行效率低而專門設計的。它往往與其他通訊機制,如訊號兩,配合使用,來實現程序間的同步和通訊。
套接字( socket ) :
套解口也是一種程序間通訊機制,與其他通訊機制不同的是,它可用於不同機器間的程序通訊。
2.7、 JVM分為哪些區,每一個區幹嗎的?
執行緒獨佔 : 棧 , 本地方法棧 ,程式計數器
執行緒共享 : 堆 , 方法區
程式計數器PC
執行緒私有的
它可以看做是當前執行緒所執行的位元組碼的行號指示器
記憶體區域中唯一一個沒有規定任何OutOfMemoryError的區域
Java虛擬機器棧
執行緒私有的
每個方法在執行的同時都會建立一個棧幀,用於儲存區域性變量表、運算元棧、動態連結、方法出口等資訊
如果執行緒請求的棧深度大於虛擬機器所允許的深度,將拋StackOverFlowError異常;
如虛擬機器擴充套件時仍無法申請到足夠的記憶體,就會丟擲OutOfMemoryError異常
本地方法棧
與虛擬機器棧非常相似,區別是虛擬機器棧為虛擬機器執行Java方法服務,而本地方法棧則為虛擬機器使用Native方法服務
也會丟擲StackOverFlowError和OutOfMemoryError異常
Java堆
執行緒共享的
Java堆是GC管理的主要區域
在虛擬機器啟動時建立
存放物件例項,幾乎所有的物件例項和陣列都在這裡分配記憶體。
如果在堆中沒有記憶體完成例項分配,並且堆也無法再擴充套件時,將會丟擲OutOfMemoryError異常
方法區
執行緒共享的
用於儲存已被虛擬機器載入的類資訊、常量、靜態變數、即使編譯器編譯後的程式碼等資料
當方法區無法滿足記憶體分配需求時,將丟擲OutOfMemoryError異常
執行時常量池
是方法區的一部分
用於存放編譯器生成的各種字面量和符號引用
相對於Class檔案常量池的一個重要特徵是,具備動態性
執行時常量池是方法區的一部分,自然受到方法區記憶體的限制。當常量池無法再申請到記憶體時會丟擲OutOfMemoryError異常
2.8、 JVM如何GC,新生代,老年代,持久代,都儲存哪些東西?
2.9、 GC用的引用可達性分析演算法中,哪些物件可作為GC Roots物件?
可達性分析演算法的思想:
從一個被稱為GC Roots的物件開始向下搜尋,如果一個物件到GC Roots沒有任何引用鏈相連時,則說明此物件不可用。
在java中可以作為GC Roots的物件有以下幾種:虛擬機器棧中引用的物件、方法區類靜態屬性引用的物件、方法區常量池引用的物件、本地方法棧JNI引用的物件
雖然這些演算法可以判定一個物件是否能被回收,但是當滿足上述條件時,一個物件 不一定會被回收。當一個物件不可達GC Roots時,這個物件並不會馬上被回收,而是處於一個死緩的階段,若要被真正的回收需要經歷兩次標記。如果物件在可達性分析中沒有與GC Roots的引用鏈,那麼此時就會被第一次標記並且進行一次篩選,篩選的條件是是否有必要執行finalize()方法。當物件沒有覆蓋finalize()方法或者已經被虛擬機器呼叫過,那麼就認為是沒必要的。
如果該物件有必要執行finalize()方法,那麼這個物件將會放在一個稱為F-Queue的佇列中,虛擬機器會觸發一個finalize()執行緒去執行,此執行緒是低優先順序的,並且虛擬機器不會承諾一直等待它執行完,這還是因為如果finalize()執行緩慢或者發生了死鎖,那麼就會造成F-Queue佇列一直等待,造成了記憶體回收系統的崩潰。GC對處於F-Queue中的物件進行第二次被標記,這時,該物件將被移除“即將回收”集合,等待回收。
2.10、 快速排序,過程,複雜度?
//快速排序
void quick_sort(int s[], int l, int r)
{
if (l < r)
{
//Swap(s[l], s[(l + r) / 2]); //將中間的這個數和第一個數交換 參見注1
int i = l, j = r, x = s[l];
while (i < j)
{
while(i < j && s[j] >= x) // 從右向左找第一個小於x的數
j--;
if(i < j)
s[i++] = s[j];
while(i < j && s[i] < x) // 從左向右找第一個大於等於x的數
i++;
if(i < j)
s[j--] = s[i];
}
s[i] = x;
quick_sort(s, l, i - 1); // 遞迴呼叫
quick_sort(s, i + 1, r);
}
}
快速排序,分治遞迴,對於每一段做如下處理:
從右向左第一個小於x的數放在原來左位置+1得那個地方,相反,從左向右第一個大於x的數放到原來右位置-1,一直到坐位置》=右位置,然後中間位置=原來左面的那個位置的數,在遞迴呼叫(l,i-1)和(i+1,r)
2.11、 什麼是二叉平衡樹,如何插入節點,刪除節點,說出關鍵步驟。
對於每一個結點來說,子樹和右子樹都是二叉平衡樹,左右子樹的高度差不能大於1,如果插入刪除使得高度差大於1了,就要進行旋轉操作
插入:
如果有當前結點就返回false,就插入,如果還是二叉平衡樹就返回true,插入的過程中如果不符合條件,就左旋右旋處理
刪除:
(1)刪除節點沒有左子樹,這種情況直接將刪除節點的父節點指向刪除節點的右子樹。
(2)刪除節點沒有右子樹,這種情況直接將刪除節點的父節點指向刪除節點的左子樹。
(3)刪除節點左右子樹都存在,可以採用兩種方式,
1:讓刪除節點左子樹的最右側節點代替當前節點
2:讓刪除節點右子樹的最左側節點代替當前節點
2.12、 TCP如何保證可靠傳輸?三次握手過程?
TCP為了提供可靠傳輸:
(1)首先,採用三次握手來建立TCP連線,四次握手來釋放TCP連線,從而保證建立的傳輸通道是可靠的。
(2)其次,TCP採用了連續ARQ協議(回退N,Go-back-N;超時自動重傳)(自動重傳請求(Automatic Repeat-reQuest,ARQ))來保證資料傳輸的正確性,使用滑動視窗協議來保證接方能夠及時處理所接收到的資料,進行流量控制。
(3)最後,TCP使用慢開始、擁塞避免、快重傳和快恢復來進行擁塞控制,避免網路擁塞。
在TCP/IP協議中,TCP協議提供可靠的連線服務,採用三次握手建立一個連線。
第一次握手:建立連線時,客戶端傳送syn包(syn=j)到伺服器,並進入SYN_SEND狀態,等待伺服器確認;
第二次握手:伺服器收到syn包,必須確認客戶的SYN(ack=j+1),同時自己也傳送一個SYN包(syn=k),即SYN+ACK包,此時伺服器進入SYN_RECV狀態;
第三次握手:客戶端收到伺服器的SYN+ACK包,向伺服器傳送確認包ACK(ack=k+1),此包傳送完畢,客戶端和伺服器進入ESTABLISHED狀態,完成三次握手。 完成三次握手,客戶端與伺服器開始傳送資料.
2.13、 TCP和UDP區別?
TCP與UDP區別總結
1、TCP面向連線(如打電話要先撥號建立連線);UDP是無連線的,即傳送資料之前不需要建立連線
2、TCP提供可靠的服務。也就是說,通過TCP連線傳送的資料,無差錯,不丟失,不重複,且按序到達;UDP盡最大努力交付,即不保證可靠交付。TCP通過校驗和,重傳控制,序號標識,滑動視窗、確認應答實現可靠傳輸。如丟包時的重發控制,還可以對次序亂掉的分包進行順序控制。
3、UDP具有較好的實時性,工作效率比TCP高,適用於對高速傳輸和實時性有較高的通訊或廣播通訊。
4.每一條TCP連線只能是點到點的;UDP支援一對一、一對多、多對一和多對多的互動通訊。
5、TCP對系統資源要求較多,UDP對系統資源要求較少。
為什麼UDP有時比TCP更有優勢?
UDP以其簡單、傳輸快的優勢,在越來越多場景下取代了TCP,如實時遊戲。
(1)網速的提升給UDP的穩定性提供可靠網路保障,丟包率很低,如果使用應用層重傳,能夠確保傳輸的可靠性。
(2)TCP為了實現網路通訊的可靠性,使用了複雜的擁塞控制演算法,建立了繁瑣的握手過程,由於TCP內建的系統協議棧中,極難對其進行改進。
採用TCP,一旦發生丟包,TCP會將後續的包快取起來,等前面的包重傳並接收到後再繼續傳送,延時會越來越大,基於UDP對實時性要求較為嚴格的情況下,採用自定義重傳機制,能夠把丟包產生的延遲降到最低,儘量減少網路問題對遊戲性造成影響。
2.14、 滑動視窗演算法?
大概意思:在一個數組或者其他連結串列中,確認左端點和右端點,這中間用和或者其他的存起來,一個一個的向右移動右端點,這個過程中可能因不符合條件要把左端點也右移,在這個過程中一直記錄最大值或者最小值,(向右移動左端點就是在這個範圍的和或者其他記錄的數值刪去左端點這個值)
2.15、 Linux下如何進行程序排程的?
涼涼…………(這個不會,看也看不懂的那種)
1.先來先服務排程演算法
先來先服務(FCFS)排程演算法是一種最簡單的排程演算法,該演算法既可用於作業排程,也可用於程序排程。當在作業排程中採用該演算法時,
每次排程都是從後備作業佇列中選擇一個或多個最先進入該佇列的作業,將它們調入記憶體,為它們分配資源、建立程序,然後放入就緒
佇列。在程序排程中採用FCFS演算法時,則每次排程是從就緒佇列中選擇一個最先進入該佇列的程序,為之分配處理機,使之投入執行。
該程序一直執行到完成或發生某事件而阻塞後才放棄處理機。
2、基於優先順序排程 (Priority Scheduling)
在優先順序排程演算法中,每個程序都關聯一個優先順序,核心將CPU分配給最高優先順序的程序。具有相同優先順序的程序,按照
先來先服務的原則進行排程。
Aging就是指逐漸提高系統中長時間等待的程序的
優先順序。我們可以每15分鐘將等待程序的優先順序加1。最終
經過一段時間,即便是擁有最低優先順序的程序也會變成系統中最高優先順序的程序,從而被執行。
優先順序排程可以搶佔式或者非搶佔式的。當一個程序在Ready佇列中時,核心將它的優先順序與正在CPU上執行的程序的優先順序
進行比較。當發現這個新程序的優先順序比正在執行的程序高時:對於搶佔式核心,新程序會搶佔CPU,之前正在執行的程序
轉入Ready佇列;對於非搶佔式核心,新程序只會被放置在Ready佇列的頭部,不會搶佔正在執行的程序。
3、短程序優先(SCBF–Shortest CPU Burst First)
最短CPU執行期優先排程演算法(SCBF–Shortest CPU Burst First)
該演算法從就緒佇列中選出下一個“CPU執行期最短”的程序,為之分配處理機。
最短作業優先排程是優先順序排程的特例。在優先順序排程中我們根據程序的優先順序來進行排程,在最短作業優先排程中我們
根據作業的執行時間長短來排程。
4、輪轉法 (Round-Robin Scheduling) (RR)
前幾種演算法主要用於批處理系統中,不能作為分時系統中的主排程演算法,在分時系統中,都採用時間片輪轉法。
簡單輪轉法:系統將所有就緒程序按FIFO規則排隊,按一定的時間間隔把處理機分配給佇列中的程序。這樣,就緒
佇列中所有程序均可獲得一個時間片的處理機而執行。多級佇列方法:將系統中所有程序分成若干類,每類為一級。
RR排程演算法轉為分時系統設計,它與FCFS很像,但是加入了搶佔。具體排程過程是:核心從Ready佇列中選取第一個程序,
將CPU資源分配給它,並且設定一個定時器在一個時間片後中斷該程序,排程Ready佇列中的下一程序。很明顯,RR排程
演算法是搶佔式的,並且在該演算法的排程下,沒有一個程序能夠連續佔用CPU超過一個時間片,從而達到了分時的目的。
5、高響應比優先排程演算法
(1) 如果作業的等待時間相同,則要求服務的時間愈短,其優先權愈高,因而該演算法有利於短作業.
(2) 當要求服務的時間相同時,作業的優先權決定於其等待時間,等待時間愈長,其優先權愈高,因而它實現的是先來先服務.
(3) 對於長作業,作業的優先順序可以隨等待時間的增加而提高,當其等待時間足夠長時,其優先順序便可升到很高, 從而也可獲得處理機.
該演算法照顧了短作業,且不會使長作業長期得不到服務
6、搶佔式排程演算法
- 非搶佔式排程演算法
為每一個被控物件建立一個實時任務並將它們排列成一輪轉佇列,排程程式每次選擇佇列中的第一個任務投入執行.該任務完成後便把它掛在輪轉佇列的隊尾等待下次排程執行. - 非搶佔式優先排程演算法.
實時任務到達時,把他們安排在就緒佇列的對首,等待當前任務自我終止或執行完成後才能被排程執行. - 搶佔式排程演算法
1)基於時鐘中斷的搶佔式優先權排程演算法.
實時任務到達後,如果該任務的優先級別高於當前任務的優先順序並不立即搶佔當前任務的處理機,而是等到時鐘中斷到來時,排程程式才剝奪當前任務的執行,將處理機分配給新到的高優先權任務.
2)立即搶佔的優先權排程演算法.
在這種排程策略中,要求作業系統具有快速響應外部時間中斷的能力.一旦出現外部中斷,只要當前任務未處於臨界區便立即剝奪當前任務的執行,把處理機分配給請求中斷的緊迫任務,實時程序排程,實時程序搶佔當前。
2.16、 Linux下你常用的命令有哪些?
這個最好是多用用比較好,直接跳過看一下個題
1、顯示日期的指令: date
2、顯示日曆的指令:cal
3、簡單好用的計算器:bc
怎麼10/100會變成0呢?這是因為bc預設僅輸出整數,如果要輸出小數點下位數,那麼就必須要執行 scale=number ,那個number就是小數點位數,
4、重要的幾個熱鍵[Tab],[ctrl]-c, [ctrl]-d
[Tab]按鍵—具有『命令補全』不『檔案補齊』的功能
[Ctrl]-c按鍵—讓當前的程式『停掉』
[Ctrl]-d按鍵—通常代表著:『鍵盤輸入結束(End Of File, EOF 戒 End OfInput)』的意思;另外,他也可以用來取代exit
5、man
退出用q,
man -f man
6、資料同步寫入磁碟: sync
輸入sync,那舉在記憶體中尚未被更新的資料,就會被寫入硬碟中;所以,這個挃令在系統關機戒重新啟勱乀前, 徑重要喔!最好多執行幾次!
7、慣用的關機指令:shutdown
此外,需要注意的是,時間引數請務必加入指令中,否則shutdown會自動跳到 run-level 1 (就是單人維護的登入情況),這樣就傷腦筋了!底下提供幾個時間引數的例子吧:
重啟,關機: reboot, halt,poweroff
8、切換執行等級: init
Linux共有七種執行等級:
–run level 0 :關機
–run level 3 :純文字模式
–run level 5 :含有圖形介面模式
–run level 6 :重新啟動
使用init這個指令來切換各模式:
如果你想要關機的話,除了上述的shutdown -h now以及poweroff之外,你也可以使用如下的指令來關機:
9、改變檔案的所屬群組:chgrp
10、改變檔案擁有者:chown
他還可以頇便直接修改群組的名稱
11、改變檔案的許可權:chmod
許可權的設定方法有兩種, 分別可以使用數字或者是符號來進行許可權的變更。
–數字型別改變檔案許可權:
–符號型別改變檔案許可權:
12、檢視版本資訊等
13、變換目錄:cd
14、顯示當前所在目錄:pwd
15、建立新目錄:mkdir
不建議常用-p這個選項,因為擔心如果你打錯字,那麼目錄名稱就回變得亂七八糟的
16、刪除『空』的目錄:rmdir
17、檔案與目錄的顯示:ls
18、複製檔案或目錄:cp
19、移除檔案或目錄:rm
20、移動檔案與目錄,或更名:mv
21、取得路徑的檔名與目錄名:basename,dirname
22、由第一行開始顯示檔案內容:cat
23、從最後一行開始顯示:tac(可以看出 tac 是 cat 的倒著寫)
24、顯示的時候,順道輸出行號:nl
25、一頁一頁的顯示檔案內容:more
26、與 more 類似,但是比 more 更好的是,他可以往前翻頁:less
27、只看頭幾行:head
28、只看尾幾行:tail
29、以二進位制的放置讀取檔案內容:od
30、修改檔案時間或新建檔案:touch
31、檔案預設許可權:umask
32、配置檔案檔案隱藏屬性:chattr
33、顯示檔案隱藏屬性:lsattr
34、觀察檔案型別:file
35、尋找【執行擋】:which
36、尋找特定檔案:whereis
37、尋找特定檔案:locate
38、尋找特定檔案:find
39、壓縮檔案和讀取壓縮檔案:gzip,zcat
40、壓縮檔案和讀取壓縮檔案:bzip2,bzcat
41、壓縮檔案和讀取壓縮檔案:tar
2.17、 作業系統什麼情況下會死鎖?
死鎖的4個必要條件
(1) 互斥條件:一個資源每次只能被一個程序使用。
(2) 請求與保持條件:一個程序因請求資源而阻塞時,對已獲得的資源保持不放。
(3) 不剝奪條件:程序已獲得的資源,在末使用完之前,不能強行被剝奪。
(4) 迴圈等待條件:若干程序之間形成一種頭尾相接的迴圈等待資源關係。
這四個條件是死鎖的必要條件,只要系統發生死鎖,這些條件必然成立,而只要上述條件之一不滿足,就不會發生死鎖。
競爭不可剝奪資源
在系統中所配置的不可剝奪資源,由於它們的數量不能滿足諸程序執行的需要,會使程序在執行過程中,因爭奪這些資源而陷於僵局。
競爭臨時性資源
上面所說的印表機資源屬於可順序重複使用型資源,稱為永久資源。還有一種所謂的臨時資源,這是指由一個程序產生,被另一個程序使用,短時間後便無用的資源,故也稱為消耗性資源,
2.18、 常用的hash演算法有哪些?
加法Hash;位運算Hash;乘法Hash;除法Hash;查表Hash;混合Hash;
2.19、 什麼是一致性雜湊?
一致性Hash演算法將整個雜湊值空間組織成一個虛擬的圓環,整個空間按順時針方向組織
圓環的正上方的點代表0,0點右側的第一個點代表1,以此類推,
0點的左側是2的32次方-1,把這個圓環叫做Hash環
然後把伺服器ip或者主機名字作為關鍵字Hash,每個伺服器都能確定位置,把資料進行相同的Hash算出的位置,順時針訪問的第一個就是對應的伺服器
一致性Hash演算法對於節點的增減都只需重定位環空間中的一小部分資料,具有較好的容錯性和可擴充套件性。
2.20、 如何理解分散式鎖?
分散式鎖:甲乙兩人購買時剩餘量都顯示一個,如果同時下單可能會出現問題,這時就需要用到分散式鎖
分散式鎖是實現有序排程不同的程序,解決不同程序之間相互干擾的問題的技術手段
分散式鎖的應具備的條件
在分散式系統環境下,分散式鎖在同一個時間僅能被同一個程序訪問
高可用的獲取/釋放鎖
高效能的獲取/釋放鎖
具備鎖的重入性
具備鎖的失效機制,防止死鎖
具備非阻塞鎖的特性,即使沒有獲取鎖也能直接返回結果
分散式鎖的實現有哪些
mechache:
利用mechache的add命令,改命令是原子性的操作,只有在key 不存在的情況下,才能add成功,也就意味著執行緒拿到了鎖
Redis:
和Mechache的實現方法相似,利用redis的setnx命令,此命令同樣是原子性的操作,只有在key不存在的情況下,add成功
zookeeper:
利用他的順序臨時節點,來實現分散式鎖和等待佇列,zookeeper的設計初衷就是為了實現分散式微服務的
使用Redis實現分散式鎖的思路
先去redis中使用setnx(商品id,數量) 得到返回結果
這裡的數量無所謂,它的作用就是告訴其他服務,我加上了鎖
發現redis中有數量,說明已經可以加鎖了
發現redis中沒有資料,說明已經獲得到了鎖
解鎖: 使用redis的 del商品id
鎖超時, 設定exprie 生命週期,如30秒, 到了指定時間,自定解鎖
三個致命問題
非原子性操作:setnx,宕機,expire
因為 setnx和expire不是原子性的,要麼都成功要麼都失敗, 一旦出現了上面的情況,就會導致死鎖出現
redis提供了原子性的操作 set ( key , value , expire)
誤刪鎖
假如我們的鎖的生命事件是30秒,結果我在30s內沒操作完,但是鎖被釋放了
jvm2拿到了鎖進行操作
jvm1 操作完成使用del,結果把jvm2 的鎖刪除了
解決方法, 在刪除之前,判斷是不是自己的鎖
redis提供了原子性的操作 set ( key ,threadId, expire)
超時為完成任務
增加一個守護執行緒,當快要超時,但是任務還沒執行完成,就增加鎖的時間
2.21、 資料庫中的正規化有哪些?
第一正規化----資料庫中的表(所有欄位值)都是不可分割的原子資料項。
第二正規化----資料庫表中的每一列都和主鍵相關,而不能只和主鍵的某一部分相關。也就是說 一個表中只能只能包含一個,不能把多種資料儲存在同一個表中。
第三正規化----資料庫表中每一列資料都和主鍵直接相關,不能間接相關。
2.22、 資料庫中的索引的結構?什麼情況下適合建索引?
資料庫中索引的結構是一種排序的資料結構。是通過B樹和變形的B+樹
實現的。
適合建索引:經常查詢,使用,用在表連線的欄位(經常更改的欄位不適合建索引)
2.23、 Java中的NIO,BIO,AIO分別是什麼?
BIO:同步並阻塞
,伺服器實現模式為一個連線一個執行緒
,即客戶端有連線請求時伺服器端就需要啟動一個執行緒進行處理,如果這個連線不做任何事情會造成不必要的執行緒開銷,當然可以通過執行緒池機制改善。BIO方式適用於連線數目比較小且固定的架構,這種方式對伺服器資源要求比較高,併發侷限於應用中,JDK1.4以前的唯一選擇,但程式直觀簡單易理解。
NIO:同步非阻塞
,伺服器實現模式為一個請求一個執行緒
,即客戶端傳送的連線請求都會註冊到多路複用器上,多路複用器輪詢到連線有I/O請求時才啟動一個執行緒進行處理。NIO方式適用於連線數目多且連線比較短(輕操作)的架構,比如聊天伺服器,併發侷限於應用中,程式設計比較複雜,JDK1.4開始支援。
AIO:非同步非阻塞
,伺服器實現模式為一個有效請求一個執行緒
,客戶端的I/O請求都是由OS先完成了再通知伺服器應用去啟動執行緒進行處理.AIO方式使用於連線數目多且連線比較長(重操作)的架構,比如相簿伺服器,充分呼叫OS參與併發操作,程式設計比較複雜,JDK7開始支援。
2.24、 用什麼工具除錯程式?JConsole,用過嗎?
JConsole在JDK/bin目錄下面,對資源消耗和效能進行監控,提供圖表和視覺化介面,佔記憶體小(具體的一些還是自己多開啟看一看就差不多了)
2.25、 現在JVM中有一個執行緒掛起了,如何用工具查出原因?
通過Javacore
瞭解執行緒執行情況:
Javacore,也可以稱為“threaddump”或是“javadump”,它是 Java 提供的一種診斷特性,能夠提供一份可讀的當前執行的 JVM 中執行緒使用情況的快照。即在某個特定時刻,JVM 中有哪些執行緒在執行,每個執行緒執行到哪一個類,哪一個方法。
應用程式如果出現不可恢復的錯誤或是記憶體洩露,就會自動觸發 Javacore 的生成。而為了效能問題診斷的需要,我們也會主動觸發生成 Javacore。
在 AIX、Linux、Solaris 環境中,我們通常使用 kill -3 產生該程序的 Javacore。
2.26、 執行緒同步與阻塞的關係?同步一定阻塞嗎?阻塞一定同步嗎?
同步是個過程,阻塞是執行緒的一種狀態。多個執行緒操作共享變數時可能會出現競爭。這時需要同步來防止兩個以上的執行緒同時進入臨界區,在這個過程中,後進入臨界區的執行緒將阻塞,等待先進入的執行緒走出臨界區。
執行緒同步不一定發生阻塞!!!執行緒同步的時候,需要協調推進速度,互相等待和互相喚醒會發生阻塞。
同樣,阻塞也不一定同步。
2.27、 同步和非同步有什麼區別?
同步互動:指傳送一個請 求,需要等待返回,然後 才能夠傳送下一個請求,有個等待過程;
非同步互動:指傳送一個請求,不需要等待返回,隨時可以再發送下一個請求,即不需要等待。
區別:一個需要等待,一個不需要等待,在部分情況下,我們的專案開發中都會優先選擇不需要等待的非同步互動方式。
2.28、 執行緒池用過嗎?
執行緒池做的工作
主要是控制執行的執行緒的數量,處理過程中將任務放入佇列,然後線上程建立後啟動這些任務,如果執行緒數量超過了最大數量超出數量的執行緒排隊等候,等其他執行緒執行完畢,再從佇列中取出任務來執行。
執行緒池的優勢
執行緒複用、控制最大併發數、執行緒管理
(1)降低系統資源消耗,通過重用已存在的執行緒,降低執行緒建立和銷燬造成的消耗;
(2)提高系統響應速度,當有任務到達時,通過複用已存在的執行緒,無需等待新執行緒的建立便能立即執行;
(3)方便執行緒併發數的管控。因為執行緒若是無限制的建立,可能會導致記憶體佔用過多而產生OOM,並且會造成cpu過度切換(cpu切換執行緒是有時間成本的(需要保持當前執行執行緒的現場,並恢復要執行執行緒的現場))。
(4)提供更強大的功能,延時定時執行緒池。
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
1、corePoolSize(執行緒池基本大小):當向執行緒池提交一個任務時,若執行緒池已建立的執行緒數小於corePoolSize,即便此時存在空閒執行緒,也會通過建立一個新執行緒來執行該任務,直到已建立的執行緒數大於或等於corePoolSize時,(除了利用提交新任務來建立和啟動執行緒(按需構造),也可以通過 prestartCoreThread() 或 prestartAllCoreThreads() 方法來提前啟動執行緒池中的基本執行緒。)
2、maximumPoolSize(執行緒池最大大小):執行緒池所允許的最大執行緒個數。當佇列滿了,且已建立的執行緒數小於maximumPoolSize,則執行緒池會建立新的執行緒來執行任務。另外,對於無界佇列,可忽略該引數。
3、keepAliveTime(執行緒存活保持時間):當執行緒池中執行緒數大於核心執行緒數時,執行緒的空閒時間如果超過執行緒存活時間,那麼這個執行緒就會被銷燬,直到執行緒池中的執行緒數小於等於核心執行緒數。
4、workQueue(任務佇列):用於傳輸和儲存等待執行任務的阻塞佇列。
5、threadFactory(執行緒工廠):用於建立新執行緒。threadFactory建立的執行緒也是採用new Thread()方式,threadFactory建立的執行緒名都具有統一的風格:pool-m-thread-n(m為執行緒池的編號,n為執行緒池內的執行緒編號)。
6、handler(執行緒飽和策略):當執行緒池和佇列都滿了,再加入執行緒會執行此策略。
執行緒池為什麼需要使用(阻塞)佇列?
1、因為執行緒若是無限制的建立,可能會導致記憶體佔用過多而產生OOM,並且會造成cpu過度切換。
2、建立執行緒池的消耗較高。 (執行緒池建立執行緒需要獲取mainlock這個全域性鎖,影響併發效率,阻塞佇列可以很好的緩衝。)
執行緒池為什麼要使用阻塞佇列而不使用非阻塞佇列?
阻塞佇列可以保證任務佇列中沒有任務時阻塞獲取任務的執行緒,使得執行緒進入wait狀態,釋放cpu資源。
當佇列中有任務時才喚醒對應執行緒從佇列中取出訊息進行執行。
使得線上程不至於一直佔用cpu資源。
不用阻塞佇列也是可以的,不過實現起來比較麻煩而已,有好用的為啥不用呢?
如何配置執行緒池
CPU密集型任務:儘量使用較小的執行緒池,一般為CPU核心數+1。
IO密集型任務:可以使用稍大的執行緒池,一般為2*CPU核心數。
混合型任務:可以將任務分成IO密集型和CPU密集型任務,
2.29、 如何建立單例模式?說了雙重檢查,他說不是執行緒安全的。如何高效的建立一個執行緒安全的單例?
餓漢模式
通過定義final型的物件,來讓載入類的時候,直接建立物件,只加載一次,實現單例。
懶漢式
通過定義靜態物件,加鎖去例項化物件。
列舉
通過定義列舉類,來實現單例。
Double-Check
若有兩個執行緒通過了第一個Check迴圈,進入第二個Check迴圈是序列化的,只能有一個執行緒進入,這樣當這個執行緒建立完成後,另外的執行緒就無法通過第二個迴圈了,保證了例項的唯一性
,隨後的執行緒也不會通過第一個Check迴圈,也就不會有同步控制的環節了。但是,這種方法也伴隨著一個缺點,它可能會引起空指標的異常。
高效建立執行緒安全的單例
Volatile+Double-Check
volatile關鍵字可以防止重排序的發生,在此不對volatile作詳細介紹,通過volatile關鍵字,這種模式可以說是滿足懶載入、多執行緒下單例的唯一性、安全性的。
public final class SingletonObject5 {
private volatile static SingletonObject5 instance ;
private SingletonObject5() {
}
public static SingletonObject5 getInstance() {
if (null == instance) {
synchronized (SingletonObject5.class) {
if (null == instance)
instance = new SingletonObject5();
}
}
return SingletonObject5.instance;
}
}
2.30、 concurrent包下面,都用過什麼?
(涼涼夜色為我思念成河……)
1.executor介面,使用executor介面的子介面ExecutorService用來建立執行緒池
2.Lock介面下的ReentrantLock類,實現同步,比如三個執行緒迴圈列印ABCABCABC…
3.atomic包,使用AtomicInteger類的incrementAndGet()方法來實現原子操作,比如a++
4.Callable介面,重寫call方法,實現多執行緒
5.concarrenHashMap,執行緒安全的HashMap
2.31、 常用的資料庫有哪些?redis用過嗎?
mysql 、SQL Server、Oracle、Sybase、DB2等
Redis:
1、純記憶體操作
2、核心是基於非阻塞的IO多路複用機制
3、單執行緒反而避免了多執行緒的頻繁上下文切換問題
2.32、 瞭解hadoop嗎?說說hadoop的元件有哪些?說下mapreduce程式設計模型。
common、Hadoop Distributed File System(HDFS)、MapReduce、YARN
程式設計模型:
Mapper把複雜的任務分解為若干個小任務,分到存在所需資料結點上進行計算,這些任務可以一起,彼此沒有依賴關係
Reducer把Mapper的結果彙總
eg:
一共有100個漢堡,甲吃十個,乙吃是個,丙吃十個,,,這就是Mapper
甲乙丙……放到一起就是Reducer
2.33、 你知道的開源協議有哪些?
• Mozilla Public License:
MPL License,允許免費重發布、免費修改,但要求修改後的程式碼版權歸軟體的發起
者。這種授權維護了商業軟體的利益,它要求基於這種軟體得修改無償貢獻版權給該軟體。這樣,圍繞該軟體得
所有程式碼得版權都集中在發起開發人得手中。但MPL是允許修改,無償使用得。MPL軟體對連結沒有要求。
• BSD開源協議:
給於使用者很大自由的協議。可以自由的使用,修改原始碼,也可以將修改後的程式碼作為開源或
者專有軟體再發布。
• Apache Licence 2.0 :
Apache Licence是著名的非盈利開源組織Apache採用的協議。該協議和BSD類似,同樣
鼓勵程式碼共享和尊重原作者的著作權,同樣允許程式碼修改,再發布(作為開源或商業軟體)。
• GPL:
GPL許可證是自由軟體的應用最廣泛的軟體許可證,人們可以修改程式的一個或幾個副本或程式的任何部
分,以此形成基於這些程式的衍生作品。必須在修改過的檔案中附有明顯的說明:您修改了此一檔案及任何修改
的日期。 您必須讓您釋出或出版的作品,包括本程式的全部或一部分,或內含本程式的全部或部分所衍生的作
品,允許第三方在此許可證條款下使用,並且不得因為此項授權行為而收費。
• LGPL:
LGPL是GPL的一個為主要為類庫使用設計的開源協議。和GPL要求任何使用/修改/衍生之GPL類庫的的軟
件必須採用GPL協議不同。LGPL允許商業軟體通過類庫引用(link)方式使用LGPL類庫而不需要開源商業軟體的代
碼。這使得采用LGPL協議的開原始碼可以被商業軟體作為類庫引用併發布和銷售。
• Public Domain:
公共域授權。將軟體授權為公共域,這些軟體包沒有授權協議,任何人都可以隨意使用它
2.34、 你知道的開源軟體有哪些?
• JDK
• eclipse
• Tomcat
• Spring
• Hibernate
• MySQL
• MyBatis
• struts
2.35、 你最近在看的書有哪些?
這個儘量說真話,最好不要搜一點簡介就說看過什麼書,否則被戳穿
很難受,
如果實在沒看過可以這麼說:
最近沒怎麼看書,但是相對於書本,我更喜歡在B站學習,比如大學公開課和攝影欄目我就經常逛;知乎我也挺活躍的,關注……等話題,每天保持相當的閱讀量,回答受贊也有幾百了;我也參加了很多經驗分享活動,我覺得從面對面的交流獲得的知識,是閱讀無法替代的。
2.36、 你有什麼問題要問我嗎?
嚴禁:沒問題,提薪資,五年計劃,某某產品被賣了等無關緊要的問題
準備3-5個問題就行,太多或者太少都不好
問題
1、問工作內容
這份工作比較大的挑戰是?
您希望我在短期內解決哪些問題?
對於未來加入這個團隊,您對我的期望是什麼?
我對這個職位工作的理解是XXX,不知道除了我的理解外,是否還有其他的工作職責?
2、問職位差距
對我此次應聘的表現有什麼評價和建議?
如果可以錄用,我需要學習哪方面的知識?
接下來的這段空檔期,有什麼值得注意或者建議學習的嗎?
3、問工作潛力
請問該崗位都要經歷哪些培訓?
這個崗位的晉升路徑是什麼樣子的?
咱們部門近期/未來有什麼新動向/新舉措?
您對這個崗位三到五年職業規劃的建議是什麼呢
4、問團隊氛圍
能帶我看一下辦公區嗎?
您在公司的一天是如何度過的?
可以介紹下一起工作的團隊是什麼樣的嗎?
提問的原則
1、探討式發問
提問不是隻問不答,提問後,先丟擲一點自己的理解,讓面試官看出你對應聘的職位是做過功課的。透過發問,更瞭解公司的組織文化和工作上實際會遇到的問題。
2、在其位謀其職
提問要展現專業度,切忌太跳脫或者故意裝高深,引發尷尬,又給人好高騖遠的感覺。記住一點:不提和所聘崗位無關的問題。
3、真誠
提問環節也是考驗情商的時候!關注他人感受,掌握好分寸感。要明白提問不是辯論,你不是為了和麵試官互相切磋知識、技能,而是真誠、虛心請教。
2.37、 瞭解哪些設計模式?說說都用過哪些設計模式
設計模式的分類
總體來說是三大類
:
建立型模式,五種:工廠方法模式、 抽象工廠模式、單例模式、建造者模式、原型模式
結構性模式,共七種: 介面卡模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。
行為型模式,共十一種:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介模式、直譯器模式。
其實還有兩類:併發型模式和執行緒池模式
2.38、 如何判斷一個單鏈表是否有環?
快慢指標查詢,快指標每次跳兩個,慢指標每次跳一個,如果兩指標相等時,就證明有環
環的入口:
用兩個指標,一個指向快慢指標相交點(這裡就是慢指標走,慢指標在走快指標的一半就相當於快指標走的路了,還會到這個點),一個指向單鏈表的頭結點(模擬慢指標從頭走,也是走快指標的一半),一起走,當兩個指標相等時,就是環的入口。
數學思維:
設從單鏈表頭節點到環入口節點的距離是D,環入口到相交點的距離是X,設slow和fast第一次相遇時fast走了n圈環,slow走的距離為len,那麼fast走的距離是2*len,可以得出下面的兩個等式:
len = D + X
2 * len = D + X + n * R
兩個等式相減可以的到:len = n * R - X
如果還不行的話,自己畫個帶環的單鏈表就明白了
2.39、 作業系統如何進行分頁排程?
筆者不懂,涼涼……
1.分頁的作用:高效率地利用記憶體,可以執行比實體記憶體空間更大的程式;
2.分頁機制的原理:利用兩級頁表將記憶體分割成4KB/頁的大小,強制記憶體對齊提高效率;
3.頁表結構:PDE與PTE在記憶體中各個位的主要作用,表項與頁之間的對應關係。
2.40、 匿名內部類是什麼?如何訪問在其外面定義的變數?
匿名內部類:
沒有名字,通常用來簡化程式碼,只能用一次(使用的話必須要繼承父類或者實現介面)
訪問在其外面定義的變數:
必須要final型別的變數(也可以不用final型別,但只能使用不能修改)
三面
3.1、 自我介紹,做過什麼專案。
這。就不說了,某度一搜一堆,專案要挑自己做的最有水平的拿出來
3.2、java虛擬機器的區域如何劃分
程式計數器(獨立記憶體)
當前執行緒所執行的位元組碼的行號指示器。
Java虛擬機器棧(獨立記憶體)
每個方法從呼叫直至執行完成的過程,就對應著一個棧幀在虛擬機器棧中入棧到出棧的過程。
本地方法棧(獨立記憶體)
本地方法棧則為虛擬機器使用到的Native方法(百度說是Java中宣告的可呼叫的C/C++實現的方法)服務。
Java堆(共享記憶體):存放物件例項
方法區(共享記憶體):儲存已被虛擬區載入的類資訊、常量、靜態變數、即時編譯器編譯後的程式碼等資料。
執行時常量池:存放編譯期生成的各種字面量和符號引用,這部分內容將在類載入後進入方法區的執行時常量池中存放。
3.3、 雙親委派模型中,從頂層到底層,都是哪些類載入器,分別載入哪些類?
(1)啟動類載入器(Bootstrap ClassLoader)
這個類載入器負責將存放在JAVA_HOME/lib下的,或者被-Xbootclasspath引數所指定的路徑中的,並且是虛擬機器識別的類庫載入到虛擬機器記憶體中。啟動類載入器無法被Java程式直接引用。
(2)擴充套件類載入器(Extension ClassLoader)
這個載入器負責載入JAVA_HOME/lib/ext目錄中的,或者被java.ext.dirs系統變數所指定的路徑中的所有類庫,開發者可以直接使用擴充套件類載入器
(3)應用程式類載入器(Application ClassLoader)
這個載入器是ClassLoader中getSystemClassLoader()方法的返回值,所以一般也稱它為系統類載入器。它負責載入使用者類路徑(Classpath)上所指定的類庫,可直接使用這個載入器,如果應用程式沒有自定義自己的類載入器,一般情況下這個就是程式中預設的類載入器
3.4、 有沒有可能父類載入器和子類載入器,載入同一個類?如果載入同一個類,該使用哪一個類?
雙親委派,先在父類看能不能載入,如果能則由父載入,否則給子類載入
3.5、 HashMap的結構,get(),put()是如何實現的?
Put:
1、先將key和value封裝到Node節點中
2、底層會呼叫key的hashcode()方法,通過hash函式將hash值轉換為陣列下標,下標位置上如果沒有任何元素,就把該Node新增到該位置上(該下標處)
如果該下標處對應的位置上已經存在元素或連結串列(多於一個元素變成連結串列),那麼就會拿著新節點的key與連結串列上的每一個人節點中的key進行equals。
1、 如果所有對比(equals)都返回false,那麼這個新節點將會被新增到連結串列的尾部。(大於8個就會轉換成紅黑樹)
2、 如果其中有一個對比(equals)返回true,那麼這個節點上的value將會被新節點的value覆蓋。
Get:
1、底層會呼叫key的hashcode()方法,通過hash函式將hash值轉換為陣列下標,通過陣列下標快速定位到陣列的指定位置上,如果這個位置上沒有任何元素,那麼返回null。
2、如果這個位置上有單向連結串列(該位置上有元素,或者有紅黑樹),那麼會拿著我們get(key)中的key和單向連結串列中的每個節點的key進行equals,如果說所有的equals都返回false,那麼這個get方法返回false。
3、只要其中有一個節點的key和引數key的equals對比的結果返回true,那麼這個節點的value就是我們想要找的value,get方法返回這個value.
3.6、 ConcurrentHashMap的get(),put(),又是如何實現的?ConcurrentHashMap有哪些問題? ConcurrentHashMap的鎖是讀鎖還是寫鎖?
put 操作一上來就鎖定了整個segment
,這當然是為了併發的安全
,修改資料是不能併發進行的,必須得有個判斷是否超限的語句以確保容量不足時能夠 rehash,
而比較難懂的是這句int index = hash & (tab.length - 1),原來segment裡面才是真正的hashtable,即每個segment是一個傳統意義上的hashtable, 從兩者的結構就可以看出區別,這裡就是找出需要的entry在table的哪一個位置,之後得到的entry就是這個鏈的第一個節點,如果e!=null,說明找到了,這是就要替換節點的值(onlyIfAbsent == false),否則,我們需要new一個entry,它的後繼是first,而讓tab[index]指向它,什麼意思呢?實際上就是將這個新entry 插入到鏈頭,剩下的就非常容易理解了。
get 方法(請注意,這裡分析的方法都是針對桶的,因為ConcurrentHashMap的最大改進就是將粒度細化到了桶上
),首先判斷了當前桶的資料個數是 否為0,為0自然不可能get到什麼,只有返回null,這樣做避免了不必要的搜尋,也用最小的代價避免出錯。然後得到頭節點(方法將在下面涉及)之後就 是根據hash和key逐個判斷是否是指定的值,如果是並且值非空就說明找到了,直接返回;
程式非常簡單,但有一個令人困惑的地方,這句return readValueUnderLock(e)到底是用來幹什麼的呢?研究它的程式碼,在鎖定之後返回一個值。但這裡已經有一句V v = e.value得到了節點的值,這句return readValueUnderLock(e)是否多此一舉?
事實上,這裡完全是為了併發考慮的,這裡當v為空時,可能是一個執行緒正在改變節點,而之前的 get操作都未進行鎖定,根據bernstein條件,讀後寫或寫後讀都會引起資料的不一致,所以這裡要對這個e重新上鎖再讀一遍,以保證得到的是正確值,
這裡不得不佩服Doug Lea思維的嚴密性。整個get操作只有很少的情況會鎖定,相對於之前的Hashtable,併發是不可避免的啊!
ConcurrentHashmap只能保證自身資料在多執行緒的環境下不被破壞,而並不能保證業務邏輯的正確性。
ConcurrentHashMap的鎖是讀鎖
3.7、 sleep()和wait()分別是哪個類的方法,有什麼區別?synchronized底層如何實現的?用在程式碼塊和方法上有什麼區別?
sleep方法是Thread
類的靜態方法,呼叫此方法會讓當前執行緒暫停指定的時間,將執行機會(CPU)讓給其他執行緒,但是不會釋放鎖,因此休眠時間結束後自動恢復(程式回到就緒狀態)。
wait是Object
類的方法,呼叫物件的wait方法導致執行緒放棄CPU的執行權,同時也放棄物件的鎖(執行緒暫停執行),進入物件的等待池(wait pool),只有呼叫物件的notify或notifyAll方法才能喚醒等待池中的執行緒進入等鎖池(lock pool),如果執行緒重新獲得物件的鎖就可以進入就緒狀態。
wait只能在同步控制方法中或者同步控制塊中使用,而sleep可以在任何地方使用。
wait 可以指定時間也可以不指定,指定時間 wait(time) 在 time時間內 有別的執行緒 notifyAll() 是不會喚醒到它 。sleep 必須指定時間
synchronized程式碼塊是由一對monitorenter/monitorexit
指令實現的, Monitor物件是同步的基本實現單元。
現代的(Oracle) JDK6中, JVM對此進行了大刀闊斧地改進,提供了三種不同的Monitor實現,也就是常說的三種不同的鎖:
偏斜鎖(Biased Locking)、輕量級鎖和重量級鎖,大大改進了其效能。
同步方法直接在方法上加synchronized實現加鎖,同步程式碼塊則在方法內部加鎖,很明顯,同步方法鎖的範圍比較大,而同步程式碼塊範圍要小點
,
一般同步的範圍越大,效能就越差,一般需要加鎖進行同步的時候,肯定是範圍越小越好,這樣效能更好。
3.8、 什麼是執行緒池?如果讓你設計一個動態大小的執行緒池,如何設計,應該有哪些方法?
執行緒池就是建立若干個可執行的執行緒放入一個池(容器)中,有任務需要處理時,會提交到執行緒池中的任務佇列,處理完之後執行緒並不會被銷燬,而是仍然線上程池中等待下一個任務。
一個執行緒池包括以下四個基本組成部分:
執行緒管理器 (ThreadPool):用於建立並管理執行緒池,包括建立執行緒,銷燬執行緒池,新增新任務;
工作執行緒 (PoolWorker):執行緒池中執行緒,在沒有任務時處於等待狀態,可以迴圈的執行任務;
任務介面 (Task):每個任務必須實現的介面,以供工作執行緒排程任務的執行,它主要規定了任務的入口,任務執行完後的收尾工作,任務的執行狀態等;
任務佇列 (TaskQueue):用於存放沒有處理的任務。提供一種緩衝機制;
所包含的方法
//建立執行緒池
private ThreadPool()
//獲得一個預設執行緒個數的執行緒池
public static ThreadPool getThreadPool()
//執行任務,其實只是把任務加入任務佇列,什麼時候執行有執行緒池管理器決定
public void execute(Runnable task)
//批量執行任務,其實只是把任務加入任務佇列,什麼時候執行有執行緒池管理器決定
public void execute(Runnable[] task)
//銷燬執行緒池,該方法保證在所有任務都完成的情況下才銷燬所有執行緒,否則等待任務完成才銷燬
public void destroy()
//返回工作執行緒的個數
public int getWorkThreadNumber()
//返回已完成任務的個數,這裡的已完成是隻出了任務佇列的任務個數,可能該任務並沒有實際執行完成
public int getFinishedTasknumber()
//在保證執行緒池中所有執行緒正在執行,並且要執行執行緒的個數大於某一值時。增加執行緒池中執行緒的個數
public void addThread()
//在保證執行緒池中有很大一部分執行緒處於空閒狀態,並且空閒狀態的執行緒在小於某一值時,減少執行緒池中執行緒的個數
public void reduceThread()
3.9、 什麼是死鎖?JVM執行緒死鎖,你該如何判斷是因為什麼?如果用VisualVM,dump執行緒資訊出來,會有哪些資訊?
(不懂還是不懂, )
執行緒死鎖是指由於兩個或者多個執行緒互相持有對方所需要的資源
,導致這些執行緒處於等待狀態,無法前往執行。
常常需要在隔兩分鐘後再次收集一次thread dump,如果得到的輸出相同,仍然是大量thread都在等待給同一個 地址上鎖,那麼肯定是死鎖了。
3.10、 檢視jvm虛擬機器裡面堆、執行緒的資訊,你用過什麼命令?
-heap :列印jvm heap的情況,會列出堆的總體使用情況,還有新生代老生代的記憶體佔用情況。
-histo:列印jvm heap的直方圖。其輸出資訊包括類名,物件數量,物件佔用大小。
-histo:live: 同上,但是隻答應存活物件的情況
-permstat:列印permanent generation heap情況
等等
3.11、 垃圾回收演算法有哪些?CMS知道嗎?如何工作的?
標記-清除演算法
從演算法的名稱上可以看出,這個演算法分為兩部分,標記和清除。首先標記出所有需要被回收的物件,然後在標記完成後統一回收掉所有被標記的物件。
這個演算法簡單,但是有兩個缺點:一是標記和清除的效率不是很高;二是標記和清除後會產生很多的記憶體碎片,導致可用的記憶體空間不連續,當分配大物件的時候,沒有足夠的空間時不得不提前觸發一次垃圾回收。
複製演算法
這個演算法將可用的記憶體空間分為大小相等的兩塊,每次只是用其中的一塊,當這一塊被用完的時候,就將還存活的物件複製到另一塊中,然後把原已使用過的那一塊記憶體空間一次回收掉。這個演算法常用於新生代的垃圾回收。
複製演算法解決了標記-清除演算法的效率問題,以空間換時間,但是當存活物件非常多的時候,複製操作效率將會變低,而且每次只能使用一半的記憶體空間,利用率不高。
標記-整理演算法
這個演算法分為三部分:
一是標記出所有需要被回收的物件;
二是把所有存活的物件都向一端移動;三是把所有存活物件邊界以外的記憶體空間都回收掉。
標記-整理演算法解決了複製演算法多複製效率低、空間利用率低的問題,同時也解決了記憶體碎片的問題。
分代收集演算法
根據物件生存週期的不同將記憶體空間劃分為不同的塊,然後對不同的塊使用不同的回收演算法。一般把Java堆分為新生代和老年代,新生代中物件的存活週期短,只有少量存活的物件,所以可以使用複製演算法,而老年代中物件存活時間長,而且物件比較多,所以可以採用標記-清除和標記-整理演算法。
CMS工作過程
初始標記 :在這個階段,需要虛擬機器停頓正在執行的任務,官方的叫法STW(Stop The Word)。這個過程從垃圾回收的"根物件"開始,只掃描到能夠和"根物件"直接關聯的物件,並作標記。所以這個過程雖然暫停了整個JVM,但是很快就完成了。
併發標記 :這個階段緊隨初始標記階段,在初始標記的基礎上繼續向下追溯標記。併發標記階段,應用程式的執行緒和併發標記的執行緒併發執行,所以使用者不會感受到停頓。
併發預清理 :
併發預清理階段仍然是併發的。在這個階段,虛擬機器查詢在執行併發標記階段新進入老年代的物件(可能會有一些物件從新生代晉升到老年代, 或者有一些物件被分配到老年代)。通過重新掃描,減少下一個階段"重新標記"的工作,因為下一個階段會Stop The World。
重新標記 :這個階段會暫停虛擬機器,收集器執行緒掃描在CMS堆中剩餘的物件。掃描從"跟物件"開始向下追溯,並處理物件關聯。
併發清理 :清理垃圾物件,這個階段收集器執行緒和應用程式執行緒併發執行。
併發重置 :這個階段,重置CMS收集器的資料結構,等待下一次垃圾回收。
3.12、 資料庫中什麼是事務?事務的隔離級別?事務的四個特性?什麼是髒讀,幻讀,不可重複讀?
事務(transaction)是作為一個單元的一組有序的資料庫操作。
如果組中的所有操作都成功,則認為事務成功,即使只有一個操作失敗,事務也不成功。如果所有操作完成,事務則提交
資料庫事務的隔離級別由低到高分別為Read uncommitted 、Read committed(大多數資料庫) 、Repeatable read(Sql Server , Oracle。Mysql) 、Serializable
事務的四個特性:
1 、原子性
事務是資料庫的邏輯工作單位,事務中包含的各操作要麼都做,要麼都不做
2 、一致性
(只有一種結果,不是全寫入資料庫,就是全都沒寫入資料庫)
事 務執行的結果必須是使資料庫從一個一致性狀態變到另一個一致性狀態。因此當資料庫只包含成功事務提交的結果時,就說資料庫處於一致性狀態。如果資料庫系統 執行中發生故障,有些事務尚未完成就被迫中斷,這些未完成事務對資料庫所做的修改有一部分已寫入物理資料庫,這時資料庫就處於一種不正確的狀態,或者說是 不一致的狀態。
3 、隔離性
一個事務的執行不能其它事務干擾。即一個事務內部的操作及使用的資料對其它併發事務是隔離的,併發執行的各個事務之間不能互相干擾。
4 、持續性
也稱永久性,指一個事務一旦提交,它對資料庫中的資料的改變就應該是永久性的。接下來的其它操作或故障不應該對其執行結果有任何影響。
髒讀是指在一個事務處理過程裡讀取了另一個未提交的事務中的資料。
幻讀是事務非獨立執行時發生的一種現象。例如事務T1對一個表中所有的行的某個資料項做了從“1”修改為“2”的操作,這時事務T2又對這個表中插入了一行資料項,而這個資料項的數值還是為“1”並且提交給資料庫。而操作事務T1的使用者如果再檢視剛剛修改的資料,會發現還有一行沒有修改,其實這行是從事務T2中新增的,就好像產生幻覺一樣,這就是發生了幻讀。
不可重複讀是指在對於資料庫中的某個資料,一個事務範圍內多次查詢卻返回了不同的資料值,這是由於在查詢間隔,被另一個事務修改並提交了。
3.13、 資料庫索引的結構有哪些? 介紹B+樹的結構。
雜湊表和有序陣列
二叉樹和多叉樹
B+樹
1.根結點至少有兩個子女。
2.每個中間節點都至少包含ceil(m / 2)個孩子,最多有m個孩子。
3.每一個葉子節點都包含k-1個元素,其中 m/2 <= k <= m。
4.所有的葉子結點都位於同一層。
5.每個節點中的元素從小到大排列,節點當中k-1個元素正好是k個孩子包含的元素的值域分劃。
3.14、 資料庫中的分頁查詢語句怎麼寫?
select * from table limit (start-1)*limit,limit; --其中start是頁碼,limit是每頁顯示的條數。
3.15、 什麼是一致性雜湊?用來解決什麼問題?
一致性Hash演算法將整個雜湊值空間組織成一個虛擬的圓環,整個空間按順時針方向組織
圓環的正上方的點代表0,0點右側的第一個點代表1,以此類推,
0點的左側是2的32次方-1,把這個圓環叫做Hash環
然後把伺服器ip或者主機名字作為關鍵字Hash,每個伺服器都能確定位置,把資料進行相同的Hash算出的位置,順時針訪問的第一個就是對應的伺服器
一致性Hash演算法對於節點的增減都只需重定位環空間中的一小部分資料,具有較好的容錯性
和可擴充套件性
。
用來解決的問題:
hash( key ) % N,N 為 Redis 的數量,在這裡 N = 4 ;
4 臺 Redis 不夠了,需要再增加 4 臺 Redis ;那麼這個求餘演算法就會變成:hash( key ) % 8 ;
一部分%4一部分%8當前大部分快取的位置都會是錯誤的,極端情況下,就會造成 快取雪崩。
(如果節點太少或分佈不均勻的時候,容易造成 資料傾斜,也就是大部分資料會集中在某一臺伺服器上。,一致性 Hash 演算法提出了【虛擬節點】解決資料傾斜問題)
3.16、 Redis的儲存結構,或者說如何工作的,與mysql的區別?有哪些資料型別?
redis中以key-value
的形式儲存,key固定是字串
,使用字串物件進行表示,value可以是字串(String)、列表(List)、雜湊(Hash)、集合(Set)、有序集合(ZSet)
。
redis和mysql的區別總結:
(1)型別上
從型別上來說,mysql是關係型資料庫,redis是快取資料庫
(2)作用上
mysql用於持久化的儲存資料到硬碟,功能強大,速度較慢,基於磁碟,讀寫速度沒有Redis快,但是不受空間容量限制,價效比高
redis用於儲存使用較為頻繁的資料到快取中,讀取速度快,基於記憶體,讀寫速度快,也可做持久化,但是記憶體空間有限,當資料量超過記憶體空間時,需擴充記憶體,但記憶體價格貴
(3)需求上
mysql和redis因為需求的不同,一般都是配合使用。
需要高效能的地方使用Redis,不需要高效能的地方使用MySQL。儲存資料在MySQL和Redis之間做同步。
3.17、 專案中用到redis,為什麼選用redis,瞭解其他NoSQL資料庫嗎?在你的專案中是如何運用redis的?key是什麼,value是什麼?
(又是涼涼的一道題, )
為什麼選用redis
高效性:Redis讀取的速度是110000次/s,寫的速度是81000次/s
原子性:Redis的所有操作都是原子性的,同時Redis還支援對幾個操作全並後的原子性執行。
支援多種資料結構:string(字串);list(列表);hash(雜湊),set(集合);zset(有序集合)
穩定性:持久化,主從複製(叢集)
其他特性:支援過期時間,支援事務,訊息訂閱。
其他NoSQL資料庫:
memcache介紹
很早出現的NoSql資料庫資料都在記憶體中,一般不持久化支援簡單的key-value模式一般是作為快取資料庫輔助持久化的資料庫
mongoDB介紹
高效能、開源、模式自由(schema free)的文件型資料庫資料都在記憶體中, 如果記憶體不足,把不常用的資料儲存到硬碟雖然是key-value模式,但是對value(尤其是json)提供了豐富的查詢功能支援二進位制資料及大型物件可以根據資料的特點替代RDBMS(關係資料庫管理系統) ,成為獨立的資料庫。或者配合RDBMS,儲存特定的資料。
列式儲存HBase介紹
HBase是Hadoop專案中的資料庫。它用於需要對大量的資料進行隨機、實時的讀寫操作的場景中。HBase的目標就是處理資料量非常龐大的表,可以用普通的計算機處理超過10億行資料,還可處理有數百萬列元素的資料表。
如何運用redis
冷熱資料區分
雖然 Redis支援持久化,但將所有資料儲存在 Redis 中,成本非常昂貴。建議將熱資料 (如 QPS超過 5k) 的資料載入到 Redis 中。低頻資料可儲存在 Mysql、 ElasticSearch中。
業務資料分離
不要將不相關的資料業務都放到一個 Redis中。一方面避免業務相互影響,另一方面避免單例項膨脹,並能在故障時降低影響面,快速恢復。
訊息大小限制
由於 Redis 是單執行緒服務,訊息過大會阻塞並拖慢其他操作。保持訊息內容在 1KB 以下是個好的習慣。嚴禁超過 50KB 的單條記錄。訊息過大還會引起網路頻寬的高佔用,持久化到磁碟時的 IO 問題。
連線數限制
連線的頻繁建立和銷燬,會浪費大量的系統資源,極限情況會造成宿主機當機。請確保使用了正確的 Redis 客戶端連線池配置。
快取 Key 設定失效時間
作為快取使用的 Key,必須要設定失效時間。失效時間並不是越長越好,請根據業務性質進行設定。注意,失效時間的單位有的是秒,有的是毫秒,這個很多同學不注意容易搞錯。
快取不能有中間態
快取應該僅作快取用,去掉後業務邏輯不應發生改變,萬不可切入到業務裡。
快取的高可用會影響業務;
產生深耦合會發生無法預料的效果;
會對維護行產生膚效果。
擴充套件方式首選客戶端 hash
如果應用太小就別考慮了,如單 redis 叢集並不能為你的資料服務,不要著急擴大你的 redis 叢集(包括 M/S 和 Cluster),叢集越大,在狀態同步和持久化方面的效能越差。優先使用客戶端 hash 進行叢集拆分。如:根據使用者 id 分 10 個叢集,使用者尾號為 0 的落在第一個叢集。
操作限制
嚴禁使用 Keys
Keys 命令效率極低,屬於 O(N)操作,會阻塞其他正常命令,在 cluster 上,會是災難性的操作。嚴禁使用,DBA 應該 rename 此命令,從根源禁用。
嚴禁使用 Flush
flush 命令會清空所有資料,屬於高危操作。嚴禁使用,DBA 應該 rename 此命令,從根源禁用,僅 DBA 可操作。
嚴禁作為訊息佇列使用
如沒有非常特殊的需求,嚴禁將 Redis 當作訊息佇列使用。Redis 當作訊息佇列使用,會有容量、網路、效率、功能方面的多種問題。如需要訊息佇列,可使用高吞吐的 Kafka 或者高可靠的 RocketMQ。
嚴禁不設定範圍的批量操作
redis 那麼快,慢查詢除了網路延遲,就屬於這些批量操作函式。大多數線上問題都是由於這些函式引起。
1、[zset] 嚴禁對 zset 的不設範圍操作
ZRANGE、 ZRANGEBYSCORE等多個操作 ZSET 的函式,嚴禁使用 ZRANGE myzset 0 -1 等這種不設定範圍的操作。請指定範圍,如 ZRANGE myzset 0 100。如不確定長度,可使用 ZCARD 判斷長度
2、[hash] 嚴禁對大資料量 Key 使用 HGETALL
HGETALL會取出相關 HASH 的所有資料,如果資料條數過大,同樣會引起阻塞,請確保業務可控。如不確定長度,可使用 HLEN 先判斷長度
3、[key] Redis Cluster 叢集的 mget 操作
Redis Cluster 的 MGET 操作,會到各分片取資料聚合,相比傳統的 M/S架構,效能會下降很多,請提前壓測和評估
4、[其他] 嚴禁使用 sunion, sinter, sdiff等一些聚合操作
禁用 select 函式
select函式用來切換 database,對於使用方來說,這是很容易發生問題的地方,cluster 模式也不支援多個 database,且沒有任何收益,禁用。
禁用事務
redis 本身已經很快了,如無大的必要,建議捕獲異常進行回滾,不要使用事務函式,很少有人這麼幹。
禁用 lua 指令碼擴充套件
lua 指令碼雖然能做很多看起來很 cool 的事情,但它就像是 SQL 的儲存過程,會引入效能和一些難以維護的問題,禁用。
禁止長時間 monitor
monitor函式可以快速看到當前 redis 正在執行的資料流,但是當心,高峰期長時間阻塞在 monitor 命令上,會嚴重影響 redis 的效能。此命令不禁止使用,但使用一定要特別特別注意。
Key 規範
Redis 的 Key 一定要規範,這樣在遇到問題時,能夠進行方便的定位。Redis 屬於無 scheme 的 KV 資料庫,所以,我們靠約定來建立其 scheme 語義。
redis中以key-value的形式儲存,key固定是字串
,使用字串物件進行表示,value可以是字串(String)、列表(List)、雜湊(Hash)、集合(Set)、有序集合(ZSet)
。
3.18、 歸併排序的過程?時間複雜度?空間複雜度?你平常用什麼排序?快速排序。說說在那些場景下適用,哪些場景下不適用。
這個就不總結了,大家面試之前要把排序的幾大演算法認真看看
3.19、 Solr是如何工作的?
solr是基於Lucence開發的企業級搜尋引擎技術,而lucence的原理是倒排索引。
倒排索引:
Demo1:A在吃飯
Demo2:B在睡覺
記錄就變成了這樣
關鍵詞 段落號(出現頻率) 出現位置
吃飯 1(1) 3
在 1(1) 2
2(1) 2
A 1(1) 1
睡覺 2(1) 3
B 2(1) 1