來源不詳了
原文地址: Java 基礎(chǔ)面試題-20211228
歡迎訪問我的博客: http://blog.duhbb.com/
題目
- 轉(zhuǎn)發(fā)和重定向的區(qū)別
- HashMap 和 HashTable 的區(qū)別
- 什么是死鎖, 產(chǎn)生死鎖的必要條件是什么? 如何避免死鎖的產(chǎn)生?
- 深拷貝和淺拷貝的區(qū)別
- Java 中注釋的代碼一定不會執(zhí)行嗎? 沒有注釋的代碼一定會執(zhí)行嗎?
轉(zhuǎn)發(fā)和重定向的區(qū)別
- 請求轉(zhuǎn)發(fā): 客戶瀏覽器發(fā)送 http 請求,web 服務(wù)器接受此請求, 調(diào)用內(nèi)部的一個方法在容器內(nèi)部完成請求處理和轉(zhuǎn)發(fā)動作, 將目標(biāo)資源發(fā)送給客戶;在這里, 轉(zhuǎn)發(fā)的路徑必須是同一個 web 容器下的 url, 其不能轉(zhuǎn)向到其他的 web 路徑上去, 中間傳遞的是自己的容器內(nèi)的 request. 在客戶瀏覽器路徑欄顯示的仍然是其第一次訪問的路徑, 也就是說客戶是感覺不到服務(wù)器做了轉(zhuǎn)發(fā)的. 轉(zhuǎn)發(fā)行為是瀏覽器只做了一次訪問請求.
- 重定向過程: 客戶瀏覽器發(fā)送 http 請求,web 服務(wù)器接受后發(fā)送 302 狀態(tài)碼響應(yīng)及對應(yīng)新的 location 給客戶瀏覽器, 客戶瀏覽器發(fā)現(xiàn)是 302 響應(yīng), 則自動再發(fā)送一個新的 http 請求, 請求 url 是新的 location 地址, 服務(wù)器根據(jù)此請求尋找資源并發(fā)送給客戶. 在這里 location 可以重定向到任意 URL, 既然是瀏覽器重新發(fā)出了請求, 則就沒有什么 request 傳遞的概念了. 在客戶瀏覽器路徑欄顯示的是其重定向的路徑, 客戶可以觀察到地址的變化的. 重定向行為是瀏覽器做了至少兩次的訪問請求的.
下面通過一張圖來對比兩者的區(qū)別:
區(qū)別 | 重定向 | 請求轉(zhuǎn)發(fā) |
---|---|---|
在哪里完成 | 客戶端完成 (可以在不同的服務(wù)器下完成) | 服務(wù)器端完成 (必須是在同一臺服務(wù)器下完成) |
瀏覽器發(fā)送請求的次數(shù) | 2 次或者 2 次以上 | 1 次 |
地址欄 URL 是否發(fā)生改變 | 地址欄發(fā)生變化 | 地址欄的地址不變 |
是否共享 request | 不共享數(shù)據(jù) (經(jīng)過重定向后,request 內(nèi)的對象將無法使用) | 共享數(shù)據(jù) (以前的 request 中存放的變量不會失效, 就像把兩個頁面拼到了一起) |
第二次請求發(fā)起者 | 瀏覽器 | 服務(wù)器 |
第二次的請求路徑方式 | 絕對路徑 | 相對路徑 |
速度 | 因為還要瀏覽器發(fā)送第二次請求, 重定向相對慢一點 | 快 |
語句 | response.sendRedirect("success.jsp"); | request.getRequestDispatcher("success.jsp").forward(request,response); |
原文鏈接:https://blog.csdn.net/Weixiaohuai/article/details/103991831
HashMap 和 HashTable 的區(qū)別
- HashMap 不是線程安全的
HashMap 是 map 接口的實現(xiàn)類, 是將鍵映射到值的對象, 其中鍵和值都是對象, 并且不能包含重復(fù)鍵, 但可以包含重復(fù)值.HashMap 允許 null key 和 null value, 而 HashTable 不允許. - HashTable 是線程安全 Collection.
HashMap 是 HashTable 的輕量級實現(xiàn), 他們都完成了 Map 接口, 主要區(qū)別在于 HashMap 允許 null key 和 null value, 由于非線程安全, 效率上可能高于 Hashtable.
區(qū)別如下:
- HashMap 允許將 null 作為一個 entry 的 key 或者 value, 而 Hashtable 不允許.
- HashMap 把 Hashtable 的 contains 方法去掉了, 改成 containsValue 和 containsKey. 因為 contains 方法容易讓人引起誤解.
- HashTable 繼承自 Dictionary 類, 而 HashMap 是 Java1.2 引進(jìn)的 Map interface 的一個實現(xiàn).
- HashTable 的方法是 Synchronize 的, 而 HashMap 不是, 在多個線程訪問 Hashtable 時, 不需要自己為它的方法實現(xiàn)同步, 而 HashMap 就必須為之提供外同步.
- Hashtable 和 HashMap 采用的 hash/rehash 算法都大概一樣, 所以性能不會有很大的差異.
作者:hunter886
鏈接:http://www.reibang.com/p/5c34133ed372
來源: 簡書
著作權(quán)歸作者所有. 商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán), 非商業(yè)轉(zhuǎn)載請注明出處.
那為什么 HashTable 的 key 或者 value 不能為 null 呢?
以下回答摘自 stackoverflow:
Hashtable 是較古老的類, 通常不鼓勵使用它.
在之后的使用中, 設(shè)計人員發(fā)現(xiàn)開發(fā)中通常需要一個空鍵或者空值, 于是就在 HashMap 中增加了對 null 的支持.
HashMap 最為 HashTable 之后實現(xiàn)的類, 具有更高級的功能, 這基本上只是對 Hashtable 功能的改進(jìn).
創(chuàng)建 HashMap 時, 它專門設(shè)計為將空值作為鍵處理并將其作為特殊情況處理.
補(bǔ)充:JDK 源碼中作者的注釋:
To successfully store and retrieve objects from a Hashtable, the objects used as keys must implement the hashCode method and the equals method.
要從 Hashtable 成功存儲和檢索對象, 用作鍵的對象必須實現(xiàn) hashCode 方法和 equals 方法.
由于 null 不是對象, 因此不能在其上調(diào)用 equals() 或 hashCode(), 因此 Hashtable 無法將其計算哈希值以用作鍵.
作者: 王李紅
鏈接:https://www.zhihu.com/question/264749854/answer/773203452
來源: 知乎
著作權(quán)歸作者所有. 商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán), 非商業(yè)轉(zhuǎn)載請注明出處.
死鎖
什么是死鎖?
所謂死鎖, 是指多個進(jìn)程在運行過程中因爭奪資源而造成的一種僵局, 當(dāng)進(jìn)程處于這種僵持狀態(tài)時, 若無外力作用, 它們都將無法再向前推進(jìn). 因此我們舉個例子來描述, 如果此時有一個線程 A, 按照先鎖 a 再獲得鎖 b 的的順序獲得鎖, 而在此同時又有另外一個線程 B, 按照先鎖 b 再鎖 a 的順序獲得鎖.
產(chǎn)生死鎖的原因?
可歸結(jié)為如下兩點:
競爭資源
系統(tǒng)中的資源可以分為兩類:
- 可剝奪資源, 是指某進(jìn)程在獲得這類資源后, 該資源可以再被其他進(jìn)程或系統(tǒng)剝奪,CPU 和主存均屬于可剝奪性資源;
- 另一類資源是不可剝奪資源, 當(dāng)系統(tǒng)把這類資源分配給某進(jìn)程后, 再不能強(qiáng)行收回, 只能在進(jìn)程用完后自行釋放, 如磁帶機(jī), 打印機(jī)等.
產(chǎn)生死鎖中的競爭資源之一指的是競爭不可剝奪資源 (例如: 系統(tǒng)中只有一臺打印機(jī), 可供進(jìn)程 P1 使用, 假定 P1 已占用了打印機(jī), 若 P2 繼續(xù)要求打印機(jī)打印將阻塞)
產(chǎn)生死鎖中的競爭資源另外一種資源指的是競爭臨時資源 (臨時資源包括硬件中斷, 信號, 消息, 緩沖區(qū)內(nèi)的消息等), 通常消息通信順序進(jìn)行不當(dāng), 則會產(chǎn)生死鎖
進(jìn)程間推進(jìn)順序非法
若 P1 保持了資源 R1,P2 保持了資源 R2, 系統(tǒng)處于不安全狀態(tài), 因為這兩個進(jìn)程再向前推進(jìn), 便可能發(fā)生死鎖.
例如, 當(dāng) P1 運行到 P1:Request(R2) 時, 將因 R2 已被 P2 占用而阻塞;當(dāng) P2 運行到 P2:Request(R1) 時, 也將因 R1 已被 P1 占用而阻塞, 于是發(fā)生進(jìn)程死鎖
死鎖產(chǎn)生的 4 個必要條件?
產(chǎn)生死鎖的必要條件:
- 互斥條件: 進(jìn)程要求對所分配的資源進(jìn)行排它性控制, 即在一段時間內(nèi)某資源僅為一進(jìn)程所占用.
- 請求和保持條件: 當(dāng)進(jìn)程因請求資源而阻塞時, 對已獲得的資源保持不放.
- 不剝奪條件: 進(jìn)程已獲得的資源在未使用完之前, 不能剝奪, 只能在使用完時由自己釋放.
- 環(huán)路等待條件: 在發(fā)生死鎖時, 必然存在一個進(jìn)程--資源的環(huán)形鏈.
解決死鎖的基本方法
預(yù)防死鎖:
- 資源一次性分配: 一次性分配所有資源, 這樣就不會再有請求了:(破壞請求條件)
- 只要有一個資源得不到分配, 也不給這個進(jìn)程分配其他的資源:(破壞請保持條件)
- 可剝奪資源: 即當(dāng)某進(jìn)程獲得了部分資源, 但得不到其它資源, 則釋放已占有的資源 (破壞不可剝奪條件)
- 資源有序分配法: 系統(tǒng)給每類資源賦予一個編號, 每一個進(jìn)程按編號遞增的順序請求資源, 釋放則相反 (破壞環(huán)路等待條件)
1 以確定的順序獲得鎖
如果必須獲取多個鎖, 那么在設(shè)計的時候需要充分考慮不同線程之前獲得鎖的順序.
針對兩個特定的鎖, 開發(fā)者可以嘗試按照鎖對象的 hashCode 值大小的順序, 分別獲得兩個鎖, 這樣鎖總是會以特定的順序獲得鎖, 那么死鎖也不會發(fā)生. 問題變得更加復(fù)雜一些, 如果此時有多個線程, 都在競爭不同的鎖, 簡單按照鎖對象的 hashCode 進(jìn)行排序 (單純按照 hashCode 順序排序會出現(xiàn)"環(huán)路等待"), 可能就無法滿足要求了, 這個時候開發(fā)者可以使用銀行家算法, 所有的鎖都按照特定的順序獲取, 同樣可以防止死鎖的發(fā)生, 該算法在這里就不再贅述了, 有興趣的可以自行了解一下.
2 超時放棄
當(dāng)使用 synchronized 關(guān)鍵詞提供的內(nèi)置鎖時, 只要線程沒有獲得鎖, 那么就會永遠(yuǎn)等待下去, 然而 Lock 接口提供了 boolean tryLock(long time, TimeUnit unit) throws InterruptedException 方法, 該方法可以按照固定時長等待鎖, 因此線程可以在獲取鎖超時以后, 主動釋放之前已經(jīng)獲得的所有的鎖. 通過這種方式, 也可以很有效地避免死鎖.
避免死鎖
預(yù)防死鎖的幾種策略, 會嚴(yán)重地?fù)p害系統(tǒng)性能. 因此在避免死鎖時, 要施加較弱的限制, 從而獲得 較滿意的系統(tǒng)性能. 由于在避免死鎖的策略中, 允許進(jìn)程動態(tài)地申請資源. 因而, 系統(tǒng)在進(jìn)行資源分配之前預(yù)先計算資源分配的安全性. 若此次分配不會導(dǎo)致系統(tǒng)進(jìn)入不安全的狀態(tài), 則將資源分配給進(jìn)程;否則, 進(jìn)程等待. 其中最具有代表性的避免死鎖算法是銀行家算法.
銀行家算法: 首先需要定義狀態(tài)和安全狀態(tài)的概念. 系統(tǒng)的狀態(tài)是當(dāng)前給進(jìn)程分配的資源情況. 因此, 狀態(tài)包含兩個向量 Resource(系統(tǒng)中每種資源的總量) 和 Available(未分配給進(jìn)程的每種資源的總量) 及兩個矩陣 Claim(表示進(jìn)程對資源的需求) 和 Allocation(表示當(dāng)前分配給進(jìn)程的資源). 安全狀態(tài)是指至少有一個資源分配序列不會導(dǎo)致死鎖. 當(dāng)進(jìn)程請求一組資源時, 假設(shè)同意該請求, 從而改變了系統(tǒng)的狀態(tài), 然后確定其結(jié)果是否還處于安全狀態(tài). 如果是, 同意這個請求;如果不是, 阻塞該進(jìn)程知道同意該請求后系統(tǒng)狀態(tài)仍然是安全的.
檢測死鎖
- 首先為每個進(jìn)程和每個資源指定一個唯一的號碼;
- 然后建立資源分配表和進(jìn)程等待表.
死鎖檢測的工具
- Jstack 命令
jstack 是 java 虛擬機(jī)自帶的一種堆棧跟蹤工具.jstack 用于打印出給定的 java 進(jìn)程 ID 或 core file 或遠(yuǎn)程調(diào)試服務(wù)的 Java 堆棧信息. Jstack 工具可以用于生成 java 虛擬機(jī)當(dāng)前時刻的線程快照. 線程快照是當(dāng)前 java 虛擬機(jī)內(nèi)每一條線程正在執(zhí)行的方法堆棧的集合, 生成線程快照的主要目的是定位線程出現(xiàn)長時間停頓的原因, 如線程間死鎖, 死循環(huán), 請求外部資源導(dǎo)致的長時間等待等. 線程出現(xiàn)停頓的時候通過 jstack 來查看各個線程的調(diào)用堆棧, 就可以知道沒有響應(yīng)的線程到底在后臺做什么事情, 或者等待什么資源. - JConsole 工具
Jconsole 是 JDK 自帶的監(jiān)控工具, 在 JDK/bin 目錄下可以找到. 它用于連接正在運行的本地或者遠(yuǎn)程的 JVM, 對運行在 Java 應(yīng)用程序的資源消耗和性能進(jìn)行監(jiān)控, 并畫出大量的圖表, 提供強(qiáng)大的可視化界面. 而且本身占用的服務(wù)器內(nèi)存很小, 甚至可以說幾乎不消耗.
解除死鎖:
當(dāng)發(fā)現(xiàn)有進(jìn)程死鎖后, 便應(yīng)立即把它從死鎖狀態(tài)中解脫出來, 常采用的方法有:
- 剝奪資源: 從其它進(jìn)程剝奪足夠數(shù)量的資源給死鎖進(jìn)程, 以解除死鎖狀態(tài);
- 撤消進(jìn)程: 可以直接撤消死鎖進(jìn)程或撤消代價最小的進(jìn)程, 直至有足夠的資源可用, 死鎖狀態(tài). 消除為止;所謂代價是指優(yōu)先級, 運行代價, 進(jìn)程的重要性和價值等.
原文鏈接: https://www.cnblogs.com/crazymakercircle/p/14323919.html
深拷貝和淺拷貝的區(qū)別
所謂深淺拷貝, 都是進(jìn)行復(fù)制, 那么區(qū)別主要在于復(fù)制出來的新對象和原來的對象是否會互相影響, 改一個, 另一個也會變.
- 淺拷貝: 對于僅僅是復(fù)制了引用 (地址), 換句話說, 復(fù)制了之后, 原來的變量和新的變量指向同一個東西, 彼此之間的操作會互相影響, 為 淺拷貝.
- 深拷貝: 而如果是在堆中重新分配內(nèi)存, 擁有不同的地址, 但是值是一樣的, 復(fù)制后的對象與原來的對象是完全隔離, 互不影響, 為深拷貝.
深淺拷貝的主要區(qū)別就是: 復(fù)制的是引用 (地址) 還是復(fù)制的是實例.
https://github.com/YvetteLau/Step-By-Step/issues/17#issuecomment-497601234
Java 注釋
感覺這個問題有點弱智:
- 注釋了的代碼坑定不會執(zhí)行啊, 要是能執(zhí)行那才是奇了怪了;
- 沒有注釋的代碼不一定會執(zhí)行的
if (1 == 2) {
System.out.println("never get here!");
}
你說這個會執(zhí)行嗎?
原文地址: Java 基礎(chǔ)面試題-20211228
歡迎訪問我的博客: http://blog.duhbb.com/