面試題彙總
文章目錄
一、數據結構
前序(根、左、右)
中序(左、根、右)
後序(左、右、根)
參考:https://www.cnblogs.com/llguanli/p/7363657.html
2.
二、網絡
methord | 描述 |
---|---|
GET | 請求指定頁面信息,並返回實體主體 |
HEAD | 類似於GET請求,只不過返回的響應中沒有具體的內容,用於獲取報頭 |
POST | 向指定資源提交數據進行處理請求(例如提交表單或者上傳文件)。數據被包含在請求體中。POST請求可能會導致新的資源的建立和/或已有資源的修改。 |
PUT | 從客戶端向服務器傳送的數據取代指定的文檔的內容。(全部取代) |
PATCH | 從客戶端向服務器傳送的數據取代指定的文檔的內容。(部分取代) |
DELETE | 請求服務器刪除指定的頁面。 |
CONNECT | HTTP/1.1協議中預留給能夠將連接改爲管道方式的代理服務器。 |
OPTIONS | 允許客戶端查看服務器的性能。 |
TRACE | 回顯服務器收到的請求,主要用於測試或診斷。 |
響應碼 | 說明 | 備註 |
---|---|---|
200 | OK | 請求已成功 |
201 | Created | 資源已創建 |
204 | No Content | 請求已成功,但無返回內容 |
304 | Not Modified | 緩存有效 |
400 | Bad Request | 語義有誤,當前請求無法被服務器理解,請求參數錯誤 |
401 | Unauthorized | 當前請求需要用戶認證(登錄) |
403 | Forbidden | 用戶已認證(登錄),但權限不足 |
404 | Not Found | 請求源未在服務器上被發現 |
405 | Method Not Allowed | 請求方法不能被用於請求相應的資源,如使用PUT方法訪問只接受POST方法的API |
500 | Internal Server Error | 服務端內部錯誤 |
502 | Bad Gateway | 網關錯誤 |
504 | Gateway Timeout | 網關超時 |
根據HTTP協議規定,GET請求用於信息獲取,應該是安全的和冪等的(無副作用),雖然獲取的結果會變化,但請求不會有任何副作用。
領域 | GET | POST |
---|---|---|
作用 | 查詢數據 | 創建、修改數據 |
長度限制 | HTTP協議中無限制 但由於各個瀏覽器有自己的對於URI的長度限制 因此會有長度限制 |
無限制 |
後退、刷新操作 | 無影響 | 會重複提交數據 前端哪些解決方案 後端哪些解決方案 |
請求過程 | TCP三次握手,併發送數據 1. 瀏覽器請求TCP連接 2. 服務器響應TCP連接 3. 瀏覽器確認TCP連接,併發送GET請求頭和數據 4. 服務器響應200,OK |
TCP三次握手後,發送數據 1. 瀏覽器請求TCP連接 2. 服務器響應TCP連接 3. 瀏覽器確認TCP連接,併發送POST請求頭 4. 服務器返回100 continue響應 5. 瀏覽器發送POST的數據 6. 服務器響應200,OK |
緩存 | 可以緩存 | 無法緩存 |
歷史 | 數據會保留在瀏覽器歷史中 | 數據不會有歷史 |
數據類型 | ASCII字符 | 無限制 |
安全性 | 差,數據暴露,遺留歷史 | 數據不顯示,無歷史記錄 |
(1) URL部分:協議(HTTP\HTTPS)、DNS域名解析過程、資源路徑
DNS解析過程:www.google.com
- 瀏覽器檢查自身緩存,域名所對應IP地址
- 瀏覽器緩存未命中,檢查操作系統緩存(hosts文件),是否存在域名對應IP地址
- hosts文件未命中,請求LDNS(本地域名服務器)查詢域名
- LDNS查詢本地域名解析緩存結果,命中則返回
- LDNS未命中緩存,繼續向上級DNS服務器查詢,直至查詢返回域名信息
(2) TCP/IP、DNS、HTTP、HTML、渲染
三、操作系統
ls、tail -f、less、more、pwd、rm -rf、mv、cp、find、chmod、chown、grep、top、cat、ps -ef|grep tomcat
2.
四、設計模式
分爲三類
創建型模式:單例、工廠、抽象工廠、建造者模式、原型模式
結構型模式:適配器模式、過濾器模式、橋接模式、組合模式、裝飾器模式、外觀模式、代理模式、享元模式
行爲型模式:責任鏈模式、命令模式、解釋器模式、迭代器模式、觀察者模式、狀態模式、空對象模式、策略模式、模板模式、訪問者模式、反應器模式
2.
五、Java基礎
-
鎖的分類
- 公平鎖、非公平鎖
公平鎖是指多個線程按照申請鎖的順序來獲取鎖。
比如:ReentrantLock,默認是非公平鎖,也可以通過構造函數傳入公平模式創建公平的可重入鎖。而Synchronized只是非公平鎖,誰拿到就是誰的,跟申請順序無關。 - 排他鎖、共享鎖
排他鎖,也叫互斥鎖、寫鎖是指該鎖一次只能被一個線程所持有,是一種概念。
共享鎖是指該鎖可被多個線程所持有,是一種概念。
ReentrantLock是排他鎖,ReadWriteLock,其中讀是共享鎖,寫是排他鎖。讀寫,寫讀 ,寫寫的過程是互斥的。Synchronized只能是排他鎖。 - 可重入鎖、讀寫鎖
ReentrantLock,可重入鎖,是排他鎖的一種實現,加鎖後其他線程無法再獲取這個加鎖對象。ReentrantLock是基於AQS實現,AQS的實現基礎即爲CAS。
讀寫鎖是一種自旋鎖,即不斷重試。比如讀鎖存在,嘗試進行寫鎖時,會不斷重試,直至讀鎖釋放,纔可以獲取到寫鎖。或當在進行寫加鎖時,讀會不斷重試,直至寫鎖釋放。讀與讀之間不會互斥,會共享鎖。
爲了防止餓死情況,即讀一直存在,寫鎖拿不到,會在寫嘗試加鎖時,禁止後續的讀再拿到共享鎖,而是等待讀鎖釋放,由等待的寫鎖進行操作。適用於讀多寫少的情況。 - 樂觀鎖、悲觀鎖
是指看待併發同步的角度。
樂觀鎖:認爲對於同一個數據的併發操作,一般是不會發生修改的。
悲觀鎖:認爲對於同一個數據的併發操作,一定會發生修改。
樂觀鎖的實現方案:CAS算法(compare and swap)、自旋
悲觀鎖的實現方案:Synchronized、ReentrantLock、數據庫行鎖、表級鎖等 - 分段鎖
分段鎖是一種設計,比如ConcurrentHashMap,採用了分段鎖方式實現高效的併發操作。
ConcurrentHashMap結構設計有16個Segment,Segment結構即爲HashMap,同時繼承了ReentrantLock,從而實現最高支持16個併發操作。 - 自旋鎖
一種鎖設計,是指當一個線程在獲取鎖的時候,如果鎖已經被其它線程獲取,那麼該線程將循環等待,然後不斷的判斷鎖是否能夠被成功獲取,直到獲取到鎖纔會退出循環。
優點:自動重試獲取鎖,不會阻塞,因爲線程一直是active狀態,不斷循環嘗試獲得鎖,因此無需線程上下文切換。
缺點:可能會導致busy-waiting忙等待,不公平的自旋鎖可能會導致線程飢餓,一直獲取不到鎖。
實現原理:CAS思想,如果compareAndSwap成功,則嘗試加鎖成功,否則繼續循環。
- 公平鎖、非公平鎖
-
Synchronized的同步原理
synchronized關鍵字可以修飾普通方法、靜態方法、代碼塊,主要分爲代碼塊的同步和方法的同步兩種,兩種同步底層原理相同,但是實現方式稍有不同。
底層原理
Monitor對象,任何同步的訪問必須先獲取monitor對象,才能進行操作,然後再釋放monitor對象。
代碼塊的同步:
指令控制,monitorenter,monitorexit。
monitorenter:
每個對象有一個監視器鎖(monitor)。當monitor被佔用時就會處於鎖定狀態,線程執行monitorenter指令時嘗試獲取monitor的所有權,過程如下:
- 如果monitor的進入數爲0,則該線程進入monitor,然後將進入數設置爲1,該線程即爲monitor的所有者。
- 如果線程已經佔有該monitor,只是重新進入,則進入monitor的進入數進行加1。
- 如果其他線程已經佔用了monitor,則該線程進入阻塞狀態,直到monitor的進入數爲0,再重新嘗試獲取monitor的所有權。
monitorexit:
執行monitorexit的線程必須是objectref所對應的monitor的所有者。
指令執行時,monitor的進入數減1,如果減1後進入數爲0,那線程退出monitor,不再是這個monitor的所有者。其他被這個monitor阻塞的線程可以嘗試去獲取這個 monitor 的所有權。
方法的同步:
方法的同步分爲普通方法和靜態方法。靜態方法屬於類,因此需要獲取類鎖,每個類只有一個類鎖,因此同步的靜態方法只能獲得鎖後調用,非同步的方法可以隨意調用。每個類可能會實例化爲很多實例,每個實例有一個對象鎖,不同對象之間加鎖不同。
可以認爲類鎖也是對象鎖,其實類也是一個Class對象,所有靜態的都是走的類這個對象。類鎖和方法鎖之間不衝突,互相無影響。
方法的同步採用的是ACC_SYNCHRONIZED標記,即標誌此方法爲同步方法。
當方法調用時,調用指令將會檢查方法的 ACC_SYNCHRONIZED 訪問標誌是否被設置,如果設置了,執行線程將先獲取monitor,獲取成功之後才能執行方法體,方法執行完後再釋放monitor。
鎖就存在於Java對象頭中。
Java對象在內存中保存,由三部分組成:Java對象頭,實例數據,對齊填充字節。
Java對象頭由三部分組成:Mark Word,指向類的指針,數組長度(只有數組對象纔有)。
以下爲Mark Word關於鎖的狀態。默認無鎖,標誌位爲01。
JVM一般是這樣使用鎖和Mark Word的:
- 當沒有被當成鎖時,這就是一個普通的對象,Mark Word記錄對象的HashCode,鎖標誌位是01,是否偏向鎖那一位是0。
- 當對象被當做同步鎖並有一個線程A搶到了鎖時,鎖標誌位還是01,但是否偏向鎖那一位改成1,前23bit記錄搶到鎖的線程id,表示進入偏向鎖狀態。當對象被當做同步鎖並有一個線程A搶到了鎖時,鎖標誌位還是01,但是否偏向鎖那一位改成1,前23bit記錄搶到鎖的線程id,表示進入偏向鎖狀態。
- 當線程A再次試圖來獲得鎖時,JVM發現同步鎖對象的標誌位是01,是否偏向鎖是1,也就是偏向狀態,Mark Word中記錄的線程id就是線程A自己的id,表示線程A已經獲得了這個偏向鎖,可以執行同步鎖的代碼。
- 當線程B試圖獲得這個鎖時,JVM發現同步鎖處於偏向狀態,但是Mark Word中的線程id記錄的不是B,那麼線程B會先用CAS操作試圖獲得鎖,這裏的獲得鎖操作是有可能成功的,因爲線程A一般不會自動釋放偏向鎖。如果搶鎖成功,就把Mark Word裏的線程id改爲線程B的id,代表線程B獲得了這個偏向鎖,可以執行同步鎖代碼。如果搶鎖失敗,則繼續執行步驟5。
- 偏向鎖狀態搶鎖失敗,代表當前鎖有一定的競爭,偏向鎖將升級爲輕量級鎖。JVM會在當前線程的線程棧中開闢一塊單獨的空間,裏面保存指向對象鎖Mark Word的指針,同時在對象鎖Mark Word中保存指向這片空間的指針。上述兩個保存操作都是CAS操作,如果保存成功,代表線程搶到了同步鎖,就把Mark Word中的鎖標誌位改成00,可以執行同步鎖代碼。如果保存失敗,表示搶鎖失敗,競爭太激烈,繼續執行步驟6。
- 輕量級鎖搶鎖失敗,JVM會使用自旋鎖,自旋鎖不是一個鎖狀態,只是代表不斷的重試,嘗試搶鎖。從JDK1.7開始,自旋鎖默認啓用,自旋次數由JVM決定。如果搶鎖成功則執行同步鎖代碼,如果失敗則繼續執行步驟7。
- 自旋鎖重試之後如果搶鎖依然失敗,同步鎖會升級至重量級鎖,鎖標誌位改爲10。在這個狀態下,未搶到鎖的線程都會被阻塞。
以上即爲JVM使用鎖的過程。
領域 | Synchronized | ReentrantLock |
---|---|---|
條件 | 只有一個 | 可以使用condition組合靈活控制 |
順序 | 固定非公平鎖 | 公平鎖、非公平鎖都支持 |
鎖超時 | 阻塞等待 | 可以嘗試加鎖,可以控制等待時間,可以中斷 |
操作 | 加鎖 | 加鎖、finally解鎖 |
比如:AtomicInteger、AtomicLong等。線程安全的類。
AtomicInteger中會調用Unsafe類下的CompareAndSwapInt方法,通過CAS的思想與自旋的方式,實現同步非阻塞的方式。
抽象類:AbstractQueuedSynchronizer,抽象的隊列式同步器,定義了一套多線程訪問共享資源的同步器框架,是java.util.concurrent的核心。
CAS指令,CPU指令,compare and swap,Unsafe類下的cas操作會在虛擬機中進行特殊處理,處理爲一條指令信息,通過硬件原子操作實現非阻塞同步,通過沖突檢測和操作完成。
CAS需要三個操作數,分別是內存位置(用V表示),舊的預期值(用A表示)和新值(用B表示)。CAS執行時,當且僅當V符合舊預期值A時,處理器用新值B更新V的值,否則它就不執行。
CAS+自旋重試,從而實現樂觀鎖式的操作。
Unsafe類是java中非常特別的一個類。它名字就叫做“不安全”,提供的操作可以直接讀寫內存、獲得地址偏移值、鎖定或釋放線程。
通過正常途徑是無法獲得Unsafe實例的,首先它的構造方法是私有的,然後,即使你調用它的getUnsafe方法,也會拋出SecurityException,因爲getUnsafe方法中檢查該CallerClass(調用方)是不是由系統類加載器BootstrapClassLoader加載。除非通過反射機制,才能跳過安全檢查。
功能:
- 讀功能:讀取內存中的某塊數據
- 寫功能:
- CAS操作:compareAndSwapXXX,原子操作,cpu在執行cas時對這一塊內存是獨佔排他的。在併發包中很多操作真正執行的也是cas,併發包中的類併發性能比使用 synchronized 關鍵字好也在於此:鎖的粒度小了許多並且少了線程上下文切換。
- park、unpark:線程掛起、恢復線程。(比如:ReentrantLock,在線程加鎖失敗時會進行掛起,就是走的park,直至超時或中斷)
什麼是進程?什麼是線程?進程與線程的區別?什麼是多線程?多線程解決什麼問題?多線程可能會引入哪些問題?
參考:https://blog.csdn.net/yaosiming2011/article/details/44280797
同步、異步是結果,阻塞、非阻塞是過程。
同步、異步是目的,阻塞、非阻塞是實現方式。
調用同步的方法在沒有拿到鎖的情況下會出現阻塞,在獲得鎖的情況下不會出現阻塞。
BIO:blocking IO,阻塞式IO。
六、數據庫
- 原子性(Atomicity):事務開始後所有操作,要麼全部做完,要麼全部不做,不可能停滯在中間環節。事務執行過程中出錯,會回滾到事務開始前的狀態,所有的操作就像沒有發生一樣。也就是說事務是一個不可分割的整體,就像化學中學過的原子,是物質構成的基本單位。
- 一致性(Consistency):事務開始前和結束後,數據庫的完整性約束沒有被破壞 。比如A向B轉賬,不可能A扣了錢,B卻沒收到。
- 隔離性(Isolation):同一時間,只允許一個事務請求同一數據,不同的事務之間彼此沒有任何干擾。
- 持久性(Durability):事務完成後,事務對數據庫的所有更新將被保存到數據庫。
- read-uncommitted,讀未提交,導致
- read-committed,不可重複讀
- repeatable-read,可重複讀
- serializable,串行化
- 髒讀:事務A讀取到事務B還未提交的新數據,但事務B最後執行失敗,回滾了數據,因此事務A讀到了錯誤的髒數據。
- 不可重複讀:事務A多次讀取同一數據,由於事務B在更新、修改此數據,導致事務A多次讀同一數據出現不同結果。(針對某行記錄的修改)
- 幻讀:事務A統計某一條件的所有數據信息,事務B剛創建一條符合條件的數據,在事務A根據相同條件再查詢時,發現統計數據又多了一條,好像出現了幻覺。(針對結果集的刪除、新增)
鎖是一種方式,並非數據庫獨有。
多版本併發控制機制
InnoDB的MVCC,是通過在每行記錄後面保存兩個隱藏的列來實現的,分別保存了這個行的創建時間和刪除時間。這裏存儲的並不是實際的時間值,而是系統版本號(可以理解爲自增ID),其實是CAS(compare and swap)的思想。
六、開源框架
- RPC框架
- MQ框架
- MQ消息重複如何處理
- MQ如何保證順序,是否可以併發消費順序