java面試2

qq_duhai發表於2018-03-08
1.分散式架構的認識
    在網際網路大行其道的今天,各種分散式系統已經司空見慣。搜尋引擎、電商網站、微博、微信、O2O平臺。。凡是涉及到大規模使用者、高併發訪問的,無一不是分散式。
   1.微信的架構師說過一句話:“大系統小做“。對於一個大的複雜系統,首先想到的就是對其分拆,拆成多個子系統
   2.儲存分拆
   3.計算分拆
   4.併發、快取
   5.線上計算 vs. 離線計算 / 同步 vs. 非同步
   6.全量 + 增量
   7.讀寫分離+動靜分離
   8.限流+資料一致性

2.多執行緒的認識
多執行緒的概念:多執行緒是一種機制,它允許在程式中併發的執行多個執行緒,且每個執行緒間相互獨立。
Java使用Thread類代表執行緒,所有的執行緒物件都必須是Thread類或其子類的例項。Java可以用三種方式來建立執行緒,如下所示:
1)繼承Thread類建立執行緒
2)實現Runnable介面建立執行緒
3)使用Callable和Future建立執行緒
執行緒有五大狀態:
1、新建狀態(New):使用new操作符建立一個執行緒的時候,執行緒還沒有開始執行;
2、就緒狀態(Runnable):當執行緒呼叫了start方法之後,執行緒就進入就緒狀態;處於就緒狀態的執行緒不一定立即執行run方法,只有獲取到cpu時間才可以執行run方法;
3、執行狀態(running):當執行緒獲取到了cpu執行時間之後,就進入到執行狀態了,呼叫run方法;
4、阻塞狀態(blocked):正在執行的執行緒還沒有結束,暫時讓出cpu,這時其他就緒執行緒就有機會獲得cpu時間;
    以下原因會導致執行緒進入阻塞狀態:
        1、執行緒呼叫sleep方法進入睡眠狀態;
        2、執行緒在呼叫一個在i/o上被阻塞的操作
        3、執行緒試圖去獲得一個鎖,但是這個鎖被其他執行緒持有;。。。。。。
5、死亡狀態(Dead):
    有以下的原因可導致執行緒死亡:
        1、run方法正常退出而正常死亡;
        2、一個未捕獲的異常導致執行緒意外退出而死亡;
可以用isAlive方法來判斷執行緒是否還活著,只要是執行緒處於執行或者阻塞狀態,就返回true;如果執行緒狀態是New且不是可執行的狀態或者執行緒死亡了,則返回false;
執行緒同步(synchronized):
    可以同步方法,也可以同步程式碼塊;對於同步方法來說,每個方法只有獲取到所屬類例項的鎖才可以被執行,一旦該方法被執行,則獨佔鎖,知道方法返回時或者異常退出時才會釋放掉鎖;
    同步程式碼塊也是一樣,當兩個併發執行緒訪問同一個物件中的這個synchronized(this)程式碼塊的時候,一個時間內只有一個執行緒得到執行,另一個執行緒只有在這個執行緒執行完成之後才可以執行;
執行緒同步之Lock:
    Lock是一個介面,它位於java 5.0新增的java.utils.concurrent包的子包locks中,實現Lock介面類具有與synchronized關鍵字相同的功能,但是它的功能強大一些,java.utils.concurrent.locks.ReentrantLock是比較常用的;注意需要在finally中unlock釋放鎖;
執行緒阻塞:
    sleep()方法、suspend和resume方法、yield方法、wait和notify方法都可以使執行緒進入阻塞狀態;但是yield方法和wait方法都會釋放cpu時間,而sleep方法和suspend不會釋放cpu時間;
終止執行緒的方法:
    1、當run方法執行完畢,自動終止;
    2、使用stop方法,不過這個方法不推薦使用,會有意料不到的後果;
    3、使用interrupt方法
多個客戶端一個伺服器的實現方法:
    利用多執行緒技術,伺服器socket負責監聽埠,設定一個無限迴圈,在其中實現:將監聽到的socket例項賦值 給執行緒並且啟動執行緒,由執行緒來完成業務邏輯;


3.jvm垃圾回收機制

說到垃圾回收(Garbage Collection,GC),很多人就會自然而然地把它和Java聯絡起來。在Java中,程式設計師不需要去關心記憶體動態分配和垃圾回收的問題,這一切都交給了JVM來處理。顧名思義,垃圾回收就是釋放垃圾佔用的空間,那麼在Java中,什麼樣的物件會被認定為“垃圾”?那麼當一些物件被確定為垃圾之後,採用什麼樣的策略來進行回收(釋放空間)?在目前的商業虛擬機器中,有哪些典型的垃圾收集器?下面我們就來逐一探討這些問題。以下是本文的目錄大綱:
一.如何確定某個物件是“垃圾”?
    在java中是通過引用來和物件進行關聯的,也就是說如果要操作物件,必須通過引用來進行。那麼很顯然一個簡單的辦法就是通過引用計數來判斷一個物件是否可以被回收。不失一般性,如果一個物件沒有任何引用與之關聯,則說明該物件基本不太可能在其他地方被使用到,那麼這個物件就成為可被回收的物件了。這種方式成為引用計數法。
二.典型的垃圾收集演算法
      在確定了哪些垃圾可以被回收後,垃圾收集器要做的事情就是開始進行垃圾回收,但是這裡面涉及到一個問題是:如何高效地進行垃圾回收。由於Java虛擬機器規範並沒有對如何實現垃圾收集器做出明確的規定,因此各個廠商的虛擬機器可以採用不同的方式來實現垃圾收集器,所以在此只討論幾種常見的垃圾收集演算法的核心思想。
    1.Mark-Sweep(標記-清除)演算法
這是最基礎的垃圾回收演算法,之所以說它是最基礎的是因為它最容易實現,思想也是最簡單的。標記-清除演算法分為兩個階段:標記階段和清除階段。標記階段的任務是標記出所有需要被回收的物件,清除階段就是回收被標記的物件所佔用的空間。具體過程如下圖所示:
從圖中可以很容易看出標記-清除演算法實現起來比較容易,但是有一個比較嚴重的問題就是容易產生記憶體碎片,碎片太多可能會導致後續過程中需要為大物件分配空間時無法找到足夠的空間而提前觸發新的一次垃圾收集動作。
    2.Copying(複製)演算法
為了解決Mark-Sweep演算法的缺陷,Copying演算法就被提了出來。它將可用記憶體按容量劃分為大小相等的兩塊,每次只使用其中的一塊。當這一塊的記憶體用完了,就將還存活著的物件複製到另外一塊上面,然後再把已使用的記憶體空間一次清理掉,這樣一來就不容易出現記憶體碎片的問題。具體過程如下圖所示:
這種演算法雖然實現簡單,執行高效且不容易產生記憶體碎片,但是卻對記憶體空間的使用做出了高昂的代價,因為能夠使用的記憶體縮減到原來的一半。
很顯然,Copying演算法的效率跟存活物件的數目多少有很大的關係,如果存活物件很多,那麼Copying演算法的效率將會大大降低。
    3.Mark-Compact(標記-整理)演算法
為了解決Copying演算法的缺陷,充分利用記憶體空間,提出了Mark-Compact演算法。該演算法標記階段和Mark-Sweep一樣,但是在完成標記之後,它不是直接清理可回收物件,而是將存活物件都向一端移動,然後清理掉端邊界以外的記憶體。
    4.Generational Collection(分代收集)演算法
分代收集演算法是目前大部分JVM的垃圾收集器採用的演算法。它的核心思想是根據物件存活的生命週期將記憶體劃分為若干個不同的區域。一般情況下將堆區劃分為老年代(Tenured Generation)和新生代(Young Generation),老年代的特點是每次垃圾收集時只有少量物件需要被回收,而新生代的特點是每次垃圾回收時都有大量的物件需要被回收,那麼就可以根據不同代的特點採取最適合的收集演算法。
目前大部分垃圾收集器對於新生代都採取Copying演算法,因為新生代中每次垃圾回收都要回收大部分物件,也就是說需要複製的操作次數較少,但是實際中並不是按照1:1的比例來劃分新生代的空間的,一般來說是將新生代劃分為一塊較大的Eden空間和兩塊較小的Survivor空間,每次使用Eden空間和其中的一塊Survivor空間,當進行回收時,將Eden和Survivor中還存活的物件複製到另一塊Survivor空間中,然後清理掉Eden和剛才使用過的Survivor空間。
而由於老年代的特點是每次回收都只回收少量物件,一般使用的是Mark-Compact演算法。
注意:在堆區之外還有一個代就是永久代(Permanet Generation),它用來儲存class類、常量、方法描述等。對永久代的回收主要回收兩部分內容:廢棄常量和無用的類。
    三.典型的垃圾收集器
    垃圾收集演算法是 記憶體回收的理論基礎,而垃圾收集器就是記憶體回收的具體實現。下面介紹一下HotSpot(JDK 7)虛擬機器提供的幾種垃圾收集器,使用者可以根據自己的需求組合出各個年代使用的收集器。
    1.Serial/Serial Old
    Serial/Serial Old收集器是最基本最古老的收集器,它是一個單執行緒收集器,並且在它進行垃圾收集時,必須暫停所有使用者執行緒。Serial收集器是針對新生代的收集器,採用的是Copying演算法,Serial Old收集器是針對老年代的收集器,採用的是Mark-Compact演算法。它的優點是實現簡單高效,但是缺點是會給使用者帶來停頓。
    2.ParNew
    ParNew收集器是Serial收集器的多執行緒版本,使用多個執行緒進行垃圾收集。
    3.Parallel Scavenge
    Parallel Scavenge收集器是一個新生代的多執行緒收集器(並行收集器),它在回收期間不需要暫停其他使用者執行緒,其採用的是Copying演算法,該收集器與前兩個收集器有所不同,它主要是為了達到一個可控的吞吐量。
    4.Parallel Old
    Parallel Old是Parallel Scavenge收集器的老年代版本(並行收集器),使用多執行緒和Mark-Compact演算法。
    5.CMS
    CMS(Current Mark Sweep)收集器是一種以獲取最短回收停頓時間為目標的收集器,它是一種併發收集器,採用的是Mark-Sweep演算法。
    6.G1
    G1收集器是當今收集器技術發展最前沿的成果,它是一款面向服務端應用的收集器,它能充分利用多CPU、多核環境。因此它是一款並行與併發收集器,並且它能建立可預測的停頓時間模型。

4.下單減庫存,如何鎖庫存,如何防止超賣
1.用額外的單程式處理一個佇列,下單請求放到佇列裡,一個個處理,就不會有併發的問題了,但是要額外的後臺程式以及延遲問題,不予考慮。
2.資料庫樂觀鎖,大致的意思是先查詢庫存,然後立馬將庫存+1,然後訂單生成後,在更新庫存前再查詢一次庫存,看看跟預期的庫存數量是否保持一致,不一致就回滾,提示使用者庫存不足。
3.根據update結果來判斷,我們可以在sql2的時候加一個判斷條件update ... where 庫存>0,如果返回false,則說明庫存不足,並回滾事務。
4.藉助檔案排他鎖,在處理下單請求的時候,用flock鎖定一個檔案,如果鎖定失敗說明有其他訂單正在處理,此時要麼等待要麼直接提示使用者"伺服器繁忙"


5.設計模式的使用
設計模式主要分三個型別:建立型、結構型和行為型。 
其中建立型有: 
    一、Singleton,單例模式:保證一個類只有一個例項,並提供一個訪問它的全域性訪問點 ;     應用場景:一個無狀態的類使用單例模式節省記憶體資源。 
    二、Abstract Factory,抽象工廠:提供一個建立一系列相關或相互依賴物件的介面,而無須指定它們的具體類。        應用場景:一系列相互依賴的物件有不同的具體實現。提供一種“封裝機制”來避免客戶程式和這種“多系列具體物件建立工作”的緊耦合。 
    三、Factory Method,工廠方法:定義一個用於建立物件的介面,讓子類決定例項化哪一個類,Factory Method使一個類的例項化延遲到了子類。     應用場景:由於需求的變化,一個類的子類經常面臨著劇烈的變化,但他卻擁有比較穩定的介面。使用一種封裝機制來“隔離這種易變物件的變化”,工廠方法定義一個用於建立物件的介面,讓子類來確定建立哪一個具體類的物件,將物件的例項化延遲。 
     四、Builder,建造模式:將一個複雜物件的構建與他的表示相分離,使得同樣的構建過程可以建立不同的表示。      應用場景:一個類的各個組成部分的具體實現類或者演算法經常面臨著變化,但是將他們組合在一起的演算法卻相對穩定。提供一種封裝機制 將穩定的組合演算法於易變的各個組成部分隔離開來。 
    五、Prototype,原型模式:用原型例項指定建立物件的種類,並且通過拷貝這些原型來建立新的物件。       應用場景:用new建立一個物件需要非常繁瑣的資料準備或者許可權 
行為型有: 
    六、Iterator,迭代器模式:提供一個方法順序訪問一個聚合物件的各個元素,而又不需要暴露該物件的內部表示。       應用場景:迭代。 
    七、Observer,觀察者模式:定義物件間一對多的依賴關係,當一個物件的狀態發生改變時,所有依賴於它的物件都得到通知自動更新。     應用場景: 某個例項的變化將影響其他多個物件。 
    八、Template Method,模板方法:定義一個操作中的演算法的骨架,而將一些步驟延遲到子類中,TemplateMethod使得子類可以不改變一個演算法的結構即可以重定義該演算法的某些特定步驟。   應用場景:一個操作的步驟穩定,而具體細節的改變延遲的子類 
     九、Command,命令模式:將一個請求封裝為一個物件,從而使你可以用不同的請求對客戶進行引數化,對請求排隊和記錄請求日誌,以及支援可撤銷的操作。        應用場景:將命令者與執行者完全解耦。 
    十、State,狀態模式:允許物件在其內部狀態改變時改變他的行為。物件看起來似乎改變了他的類。           應用場景:一個物件的內部狀態改變時,他的行為劇烈的變化。 
    十一、Strategy,策略模式:定義一系列的演算法,把他們一個個封裝起來,並使他們可以互相替換,本模式使得演算法可以獨立於使用它們的客戶。        應用場景: 
    十二、China of Responsibility,職責鏈模式:使多個物件都有機會處理請求,從而避免請求的送發者和接收者之間的耦合關係 
    十三、Mediator,中介者模式:用一箇中介物件封裝一些列的物件互動。 
    十四、Visitor,訪問者模式:表示一個作用於某物件結構中的各元素的操作,它使你可以在不改變各元素類的前提下定義作用於這個元素的新操作。 
    十五、Interpreter,直譯器模式:給定一個語言,定義他的文法的一個表示,並定義一個直譯器,這個直譯器使用該表示來解釋語言中的句子。 
    十六、Memento,備忘錄模式:在不破壞物件的前提下,捕獲一個物件的內部狀態,並在該物件之外儲存這個狀態。 
結構型有: 
    十七、Composite,組合模式:將物件組合成樹形結構以表示部分整體的關係,Composite使得使用者對單個物件和組合物件的使用具有一致性。 
    十八、Facade,外觀模式:為子系統中的一組介面提供一致的介面,fa?ade提供了一高層介面,這個介面使得子系統更容易使用。 
    十九、Proxy,代理模式:為其他物件提供一種代理以控制對這個物件的訪問 
    二十、Adapter,介面卡模式:將一類的介面轉換成客戶希望的另外一個介面,Adapter模式使得原本由於介面不相容而不能一起工作那些類可以一起工作。 
    二十一、Decrator,裝飾模式:動態地給一個物件增加一些額外的職責,就增加的功能來說,Decorator模式相比生成子類更加靈活。 
    二十二、Bridge,橋模式:將抽象部分與它的實現部分相分離,使他們可以獨立的變化。 
    二十三、Flyweight,享元模式 


6.tomcat的配置和效能調優
1、修改tomcat讓其支援NIO
2、增加tomcat的處理執行緒數
3、tomcat記憶體空間的設定:-Xms -Xmx來調整應用程式的初始記憶體和最大記憶體: 


7.附近的人搜尋
1.sphinx geo索引
2.mongodb geo索引
3.mysql sql查詢
4.mysql+geohash
5.redis+geohash

8.mysql執行一次查詢的處理過程,mysql引擎
1.客戶端傳送一條查詢給伺服器;
2.伺服器先會檢查查詢快取,如果命中了快取,則立即返回儲存在快取中的結果。否則進入下一階段;
3.伺服器端進行SQL解析、預處理,再由優化器生成對應的執行計劃;
4.MySQL根據優化器生成的執行計劃,呼叫儲存引擎的API來執行查詢;
5.將結果返回給客戶端。

InnoDB儲存引擎
InnoDB是事務型資料庫的首選引擎,支援事務安全表(ACID),支援行鎖定和外來鍵,上圖也看到了,InnoDB是預設的MySQL引擎。InnoDB主要特性有:
1、InnoDB給MySQL提供了具有提交、回滾和崩潰恢復能力的事物安全(ACID相容)儲存引擎。InnoDB鎖定在行級並且也在SELECT語句中提供一個類似Oracle的非鎖定讀。這些功能增加了多使用者部署和效能。在SQL查詢中,可以自由地將InnoDB型別的表和其他MySQL的表型別混合起來,甚至在同一個查詢中也可以混合
2、InnoDB是為處理巨大資料量的最大效能設計。它的CPU效率可能是任何其他基於磁碟的關係型資料庫引擎鎖不能匹敵的
3、InnoDB儲存引擎完全與MySQL伺服器整合,InnoDB儲存引擎為在主記憶體中快取資料和索引而維持它自己的緩衝池。InnoDB將它的表和索引在一個邏輯表空間中,表空間可以包含數個檔案(或原始磁碟檔案)。這與MyISAM表不同,比如在MyISAM表中每個表被存放在分離的檔案中。InnoDB表可以是任何尺寸,即使在檔案尺寸被限制為2GB的作業系統上
4、InnoDB支援外來鍵完整性約束,儲存表中的資料時,每張表的儲存都按主鍵順序存放,如果沒有顯示在表定義時指定主鍵,InnoDB會為每一行生成一個6位元組的ROWID,並以此作為主鍵
5、InnoDB被用在眾多需要高效能的大型資料庫站點上
InnoDB不建立目錄,使用InnoDB時,MySQL將在MySQL資料目錄下建立一個名為ibdata1的10MB大小的自動擴充套件資料檔案,以及兩個名為ib_logfile0和ib_logfile1的5MB大小的日誌檔案
MyISAM儲存引擎
MyISAM基於ISAM儲存引擎,並對其進行擴充套件。它是在Web、資料倉儲和其他應用環境下最常使用的儲存引擎之一。MyISAM擁有較高的插入、查詢速度,但不支援事物。MyISAM主要特性有:
1、大檔案(達到63位檔案長度)在支援大檔案的檔案系統和作業系統上被支援
2、當把刪除和更新及插入操作混合使用的時候,動態尺寸的行產生更少碎片。這要通過合併相鄰被刪除的塊,以及若下一個塊被刪除,就擴充套件到下一塊自動完成
3、每個MyISAM表最大索引數是64,這可以通過重新編譯來改變。每個索引最大的列數是16
4、最大的鍵長度是1000位元組,這也可以通過編譯來改變,對於鍵長度超過250位元組的情況,一個超過1024位元組的鍵將被用上
5、BLOB和TEXT列可以被索引
6、NULL被允許在索引的列中,這個值佔每個鍵的0~1個位元組
7、所有數字鍵值以高位元組優先被儲存以允許一個更高的索引壓縮
8、每個MyISAM型別的表都有一個AUTO_INCREMENT的內部列,當INSERT和UPDATE操作的時候該列被更新,同時AUTO_INCREMENT列將被重新整理。所以說,MyISAM型別表的AUTO_INCREMENT列更新比InnoDB型別的AUTO_INCREMENT更快
9、可以把資料檔案和索引檔案放在不同目錄
10、每個字元列可以有不同的字符集
11、有VARCHAR的表可以固定或動態記錄長度
12、VARCHAR和CHAR列可以多達64KB
使用MyISAM引擎建立資料庫,將產生3個檔案。檔案的名字以表名字開始,副檔名之處檔案型別:frm檔案儲存表定義、資料檔案的副檔名為.MYD(MYData)、索引檔案的副檔名時.MYI(MYIndex)
MEMORY儲存引擎
MEMORY儲存引擎將表中的資料儲存到記憶體中,未查詢和引用其他表資料提供快速訪問。MEMORY主要特性有:
1、MEMORY表的每個表可以有多達32個索引,每個索引16列,以及500位元組的最大鍵長度
2、MEMORY儲存引擎執行HASH和BTREE縮影
3、可以在一個MEMORY表中有非唯一鍵值
4、MEMORY表使用一個固定的記錄長度格式
5、MEMORY不支援BLOB或TEXT列
6、MEMORY支援AUTO_INCREMENT列和對可包含NULL值的列的索引
7、MEMORY表在所由客戶端之間共享(就像其他任何非TEMPORARY表)
8、MEMORY表記憶體被儲存在記憶體中,記憶體是MEMORY表和伺服器在查詢處理時的空閒中,建立的內部表共享
9、當不再需要MEMORY表的內容時,要釋放被MEMORY表使用的記憶體,應該執行DELETE FROM或TRUNCATE TABLE,或者刪除整個表(使用DROP TABLE)

9.訊息佇列有哪些,有什麼好處
一、訊息佇列概述
訊息佇列中介軟體是分散式系統中重要的元件,主要解決應用解耦,非同步訊息,流量削鋒等問題,實現高效能,高可用,可伸縮和最終一致性架構。目前使用較多的訊息佇列有ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,RocketMQ
二、訊息佇列應用場景
以下介紹訊息佇列在實際應用中常用的使用場景。非同步處理,應用解耦,流量削鋒和訊息通訊四個場景。

10.redis使用經驗




相關文章