互聯網Java工程師面試題
內容涵蓋:Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、
Redis、MySQL、Spring、Spring Boot、Spring Cloud、RabbitMQ、Kafka、 Linux 等技術棧
目錄
互聯網 Java 工程師面試題..........................................................................................1
........................................................................................................................................1
MyBatis 面試題........................................................................................................ 33 一、什麼是 Mybatis?...............................................................................33
二、 Mybaits 的優勢:...............................................................................33
三、 MyBatis 框架的缺點:.......................................................................34
四、 MyBatis 框架適用場合:...................................................................34
五、 MyBatis 與 Hibernate 有哪些不一樣?..............................................35
六、 #{}和${}的區別是什麼?.....................................................................35
七、 當實體類中的屬性名和表中的字段名不同 ,怎麼辦 ?........... 35
八、 模糊查詢 like 語句該怎麼寫?...........................................................36
九、 一般一個 Xml 映射文件,都會寫一個 Dao 接口與之對應,請問,這個 Dao 接口的工做原理是什麼?Dao 接口裏的方法,參數不一樣時,方法能重載嗎?..........................................................................................37
十、 Mybatis 是如何進行分頁的?分頁插件的原理是什麼?.............38 十一、Mybatis 是如何將 sql 執行結果封裝爲目標對象並返回的?都有哪些映射形式?..........................................................................................38 十二、如何執行批量插入?...........................................................................39
1三、 如何獲取自動生成的(主)鍵值?........................................................ 40
1四、 在 mapper 中如何傳遞多個參數?..................................................40
1五、 Mybatis 動態 sql 有什麼用?執行原理?有哪些動態 sql?.......42
1六、 Xml 映射文件中,除了常見的 select|insert|updae|delete 標籤以外,還有哪些標籤?..................................................................................42
1八、爲何說 Mybatis 是半自動 ORM 映射工具?它與全自動的區別在哪裏?......................................................................................................43 1九、 一對1、一對多的關聯查詢 ?.....................................................43
20、 MyBatis 實現一對一有幾種方式?具體怎麼操做的?...................45
2一、 MyBatis 實現一對多有幾種方式,怎麼操做的?............................45
2二、 Mybatis 是否支持延遲加載?若是支持,它的實現原理是什麼?46
2三、 Mybatis 的一級、二級緩存:............................................................46
2四、 什麼是 MyBatis 的接口綁定?有哪些實現方式?........................47 2五、使用 MyBatis 的 mapper 接口調用時有哪些要求?...................47
2六、 Mapper 編寫有哪幾種方式?.........................................................47
2七、 簡述 Mybatis 的插件運行原理,以及如何編寫一個插件。........50
ZooKeeper 面試題...................................................................................................50html
Mybatis 在處理#{}時,會將 sql 中的#{}替換爲?號,調用 PreparedStatement 的 set 方法來賦值;
Mybatis 在處理${}時,就是把${}替換成變量的值。
使用#{}能夠有效的防止 SQL 注入,提升系統安全性。
七、當實體類中的屬性名和表中的字段名不同 ,怎麼辦 ?
第 1 種: 經過在查詢的 sql 語句中定義字段名的別名,讓字段名的別名和實體類的屬性名一致。
<select id=」selectorder」 parametertype=」int」 resultetype=」 me.gacl.domain.order」> select order_id id, order_no orderno ,order_price price form
orders where order_id=#{id};
第 2 種: 經過
<!–用 id 屬性來映射主鍵字段–>
<!–用 result 屬性來映射非主鍵字段,property 爲實體類屬性名,column 爲數據表中的屬性–>
八、 模糊查詢 like 語句該怎麼寫?
第 1 種:在 Java 代碼中添加 sql 通配符。
string wildcardname = 「%smi%」;
list
第 2 種:在 sql 語句中拼接通配符,會引發 sql 注入
string wildcardname = 「smi」; list
九、一般一個 Xml 映射文件,都會寫一個 Dao 接口與之對應,請問,這個 Dao 接口的工做原理是什麼?Dao 接口裏的方法,參數不一樣時,方法能重載嗎?
Dao 接口即 Mapper 接口。接口的全限名,就是映射文件中的 namespace 的值;接口的方法名,就是映射文件中 Mapper 的 Statement 的 id 值;接口方法內的參數,就是傳遞給 sql 的參數。
Mapper 接口是沒有實現類的,當調用接口方法時,接口全限名+方法名拼接字符串做爲 key 值,可惟必定位一個 MapperStatement。在 Mybatis 中,每個
二、 第二種: 使用 @param 註解:
public interface usermapper { user selectuser(@param(「username」) string
username,@param(「hashedpassword」) string hashedpassword);
}
而後,就能夠在 xml 像下面這樣使用(推薦封裝爲一個 map,做爲單個參數傳遞給 mapper):
三、 第三種:多個參數封裝成 map
try {
//映射文件的命名空間.SQL 片斷的 ID,就能夠調用對應的映射文件中的
SQL
//因爲咱們的參數超過了兩個,而方法中只有一個 Object 參數收集,所以咱們使用 Map 集合來裝載咱們的參數
Map < String, Object > map = new HashMap(); map.put("start", start); map.put("end", end);
return sqlSession.selectList("StudentID.pagination", map);
} catch (Exception e) {
e.printStackTrace(); sqlSession.rollback();
throw e;
} finally {
MybatisUtil.closeSqlSession();
}
1五、Mybatis 動態 sql 有什麼用?執行原理?有哪些動態 sql?
Mybatis 動態 sql 能夠在 Xml 映射文件內,以標籤的形式編寫動態 sql,執行原理是根據表達式的值 完成邏輯判斷並動態拼接 sql 的功能。
Mybatis 提供了 9 種動態 sql 標籤:trim | where | set | foreach | if | choose | when | otherwise | bind。
1六、Xml 映射文件中,除了常見的 select|insert|updae|delete
標籤以外,還有哪些標籤?
答:
1七、Mybatis 的 Xml 映射文件中,不一樣的 Xml 映射文件,id 是否能夠重複?
不一樣的 Xml 映射文件,若是配置了 namespace,那麼 id 能夠重複;若是沒有配置 namespace,那麼 id 不能重複;
緣由就是 namespace+id 是做爲 Map<String, MapperStatement>的 key
使用的,若是沒有 namespace,就剩下 id,那麼,id 重複會致使數據互相覆蓋。有了 namespace,天然 id 就能夠重複,namespace 不一樣,namespace+id 天然也就不一樣。
1八、爲何說 Mybatis 是半自動 ORM 映射工具?它與全自動的區別在哪裏?
Hibernate 屬於全自動 ORM 映射工具,使用 Hibernate 查詢關聯對象或者關聯集合對象時,能夠根據對象關係模型直接獲取,因此它是全自動的。而 Mybatis 在查詢關聯對象或關聯集合對象時,須要手動編寫 sql 來完成,因此,稱之爲半自動 ORM 映射工具。
1九、 一對1、一對多的關聯查詢 ?
1四、Dubbo 集羣容錯有幾種方案?
集羣容錯方案 說明
Failover Cluster 失敗自動切換,自動重試其它服務器(默認)
Failfast Cluster 快速失敗,當即報錯,只發起一次調用
Failsafe Cluster 失敗安全,出現異常時,直接忽略
Failback Cluster 失敗自動恢復,記錄失敗請求,定時重發
Forking Cluster 並行調用多個服務器,只要一個成功即返回
Broadcast Cluster 廣播逐個調用全部提供者,任意一個報錯則報錯
1五、Dubbo 服務降級,失敗重試怎麼作?
能夠經過 dubbo:reference 中設置 mock="return null"。mock 的值也能夠修改成 true,而後再跟接口同一個路徑下實現一個 Mock 類,命名規則是 「接口名稱+Mock」 後綴。而後在 Mock 類裏實現本身的降級邏輯
1六、Dubbo 使用過程當中都遇到了些什麼問題?
在註冊中心找不到對應的服務,檢查 service 實現類是否添加了@service 註解沒法鏈接到註冊中心,檢查配置文件中的對應的測試 ip 是否正確
1七、Dubbo Monitor 實現原理?
Consumer 端在發起調用以前會先走 filter 鏈;provider 端在接收到請求時也是先走 filter 鏈,而後才進行真正的業務邏輯處理。
默認狀況下,在 consumer 和 provider 的 filter 鏈中都會有 Monitorfilter。
一、 MonitorFilter 向 DubboMonitor 發送數據
二、 DubboMonitor 將數據進行聚合後(默認聚合 1min 中的統計數據)暫存到
ConcurrentMap<Statistics, AtomicReference> statisticsMap,而後使用一個
含有 3 個線程(線程名字:DubboMonitorSendTimer)的線程池每隔 1min 鍾,調用 SimpleMonitorService 遍歷發送 statisticsMap 中的統計數據,每發送完畢一個,就重置當前的 Statistics 的 AtomicReference
三、 SimpleMonitorService 將這些聚合數據塞入 BlockingQueue queue 中(隊列大寫爲 100000)
四、 SimpleMonitorService 使用一個後臺線程(線程名爲:
DubboMonitorAsyncWriteLogThread)將 queue 中的數據寫入文件(該線程以
死循環的形式來寫)
五、 SimpleMonitorService 還會使用一個含有 1 個線程(線程名字:
DubboMonitorTimer)的線程池每隔 5min 鍾,將文件中的統計數據畫成圖表
1八、Dubbo 用到哪些設計模式?
Dubbo 框架在初始化和通訊過程當中使用了多種設計模式,可靈活控制類加載、權限控制等功能。
工廠模式
Provider 在 export 服務時,會調用 ServiceConfig 的 export 方法。ServiceConfig 中有個字段:
private static final Protocol protocol =
ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtensi on();
Dubbo 裏有不少這種代碼。這也是一種工廠模式,只是實現類的獲取採用了 JDK SPI 的機制。這麼實現的優勢是可擴展性強,想要擴展實現,只須要在 classpath 下增長個文件就能夠了,代碼零侵入。另外,像上面的 Adaptive 實現,能夠作到調用時動態決定調用哪一個實現,可是因爲這種實現採用了動態代理,會形成代碼調試比較麻煩,須要分析出實際調用的實現類。
裝飾器模式
Dubbo 在啓動和調用階段都大量使用了裝飾器模式。以 Provider 提供的調用鏈爲
例,具體的調用鏈代碼是在 ProtocolFilterWrapper 的 buildInvokerChain 完成的,具體是將註解中含有 group=provider 的 Filter 實現,按照 order 排序,最後的調用順序是:
EchoFilter -> ClassLoaderFilter -> GenericFilter -> ContextFilter ->
ExecuteLimitFilter -> TraceFilter -> TimeoutFilter -> MonitorFilter -> ExceptionFilter
更確切地說,這裏是裝飾器和責任鏈模式的混合使用。例如,EchoFilter 的做用是判斷是不是回聲測試請求,是的話直接返回內容,這是一種責任鏈的體現。而像
ClassLoaderFilter 則只是在主功能上添加了功能,更改當前線程的 ClassLoader,這是典型的裝飾器模式。
觀察者模式
Dubbo 的 Provider 啓動時,須要與註冊中心交互,先註冊本身的服務,再訂閱本身的服務,訂閱時,採用了觀察者模式,開啓一個 listener。註冊中心會每 5 秒定時檢查是否有服務更新,若是有更新,向該服務的提供者發送一個 notify 消息,
provider 接受到 notify 消息後,即運行 NotifyListener 的 notify 方法,執行監聽器方法。
動態代理模式
Dubbo 擴展 JDK SPI 的類 ExtensionLoader 的 Adaptive 實現是典型的動態代理實現。Dubbo 須要靈活地控制實現類,即在調用階段動態地根據參數決定調用哪一個實現類,因此採用先生成代理類的方法,可以作到靈活的調用。生成代理類的
代碼是 ExtensionLoader 的 createAdaptiveExtensionClassCode 方法。代理類的主要邏輯是,獲取 URL 參數中指定參數的值做爲獲取實現類的 key。
1九、Dubbo 配置文件是如何加載到 Spring 中的?
Spring 容器在啓動的時候,會讀取到 Spring 默認的一些 schema 以及 Dubbo 自定義的 schema,每一個 schema 都會對應一個本身的 NamespaceHandler, NamespaceHandler 裏面經過 BeanDefinitionParser 來解析配置信息並轉化爲須要加載的 bean 對象!
20、Dubbo SPI 和 Java SPI 區別?
JDK SPI
JDK 標準的 SPI 會一次性加載全部的擴展實現,若是有的擴展吃實話很耗時,但也沒用上,很浪費資源。
因此只但願加載某個的實現,就不現實了
DUBBO SPI
1,對 Dubbo 進行擴展,不須要改動 Dubbo 的源碼
2,延遲加載,能夠一次只加載本身想要加載的擴展實現。
3,增長了對擴展點 IOC 和 AOP 的支持,一個擴展點能夠直接 setter 注入其它擴展點。
3,Dubbo 的擴展機制能很好的支持第三方 IoC 容器,默認支持 Spring Bean。
2一、Dubbo 支持分佈式事務嗎?
目前暫時不支持,可與經過 tcc-transaction 框架實現
介紹:tcc-transaction 是開源的 TCC 補償性分佈式事務框架
Git 地址:https://github.com/changmingxie/tcc-transaction
TCC-Transaction 經過 Dubbo 隱式傳參的功能,避免本身對業務代碼的入侵。
2二、Dubbo 能夠對結果進行緩存嗎?
爲了提升數據訪問的速度。Dubbo 提供了聲明式緩存,以減小用戶加緩存的工做量
<dubbo:reference cache="true" />
其實比普通的配置文件就多了一個標籤 cache="true"
2三、服務上線怎麼兼容舊版本?
能夠用版本號(version)過渡,多個不一樣版本的服務註冊到註冊中心,版本號不一樣的服務相互間不引用。這個和服務分組的概念有一點相似。
2四、Dubbo 必須依賴的包有哪些?
Dubbo 必須依賴 JDK,其餘爲可選。
2五、Dubbo telnet 命令能作什麼?
dubbo 服務發佈以後,咱們能夠利用 telnet 命令進行調試、管理。
Dubbo2.0.5 以上版本服務提供端口支持 telnet 命令
鏈接服務
telnet localhost 20880 //鍵入回車進入 Dubbo 命令模式。
查看服務列表
dubbo>ls
com.test.TestService
dubbo>ls com.test.TestService create delete query
• ls (list services and methods)
• ls : 顯示服務列表。
• ls -l : 顯示服務詳細信息列表。
• ls XxxService:顯示服務的方法列表。
• ls -l XxxService:顯示服務的方法詳細信息列表。
2六、Dubbo 支持服務降級嗎?
以經過 dubbo:reference 中設置 mock="return null"。mock 的值也能夠修改成 true,而後再跟接口同一個路徑下實現一個 Mock 類,命名規則是 「接口名稱+Mock」 後綴。而後在 Mock 類裏實現本身的降級邏輯
2七、Dubbo 如何優雅停機?
Dubbo 是經過 JDK 的 ShutdownHook 來完成優雅停機的,因此若是使用 kill -9 PID 等強制關閉指令,是不會執行優雅停機的,只有經過 kill PID 時,纔會執行。
2八、Dubbo 和 Dubbox 之間的區別?
Dubbox 是繼 Dubbo 中止維護後,噹噹網基於 Dubbo 作的一個擴展項目,如加了服務可 Restful 調用,更新了開源組件等。
2九、Dubbo 和 Spring Cloud 的區別?
根據微服務架構在各方面的要素,看看 Spring Cloud 和 Dubbo 都提供了哪些支持。
Dubbo Spring Cloud
服務註冊中心 Zookeep
er Spring Cloud Netflix Eureka
服務調用方式 RPC REST API
服務網關 無 Spring Cloud Netflix Zuul
斷路器 不完善 Spring Cloud Netflix Hystrix
分佈式配置 無 Spring Cloud Config
服務跟蹤 無 Spring Cloud Sleuth
消息總線 無 Spring Cloud Bus
數據流 無 Spring Cloud Stream
批量任務 無 Spring Cloud Task
…… …… ……
使用 Dubbo 構建的微服務架構就像組裝電腦,各環節咱們的選擇自由度很高,可是最終結果頗有可能由於一條內存質量不行就點不亮了,老是讓人不怎麼放心,可是若是你是一名高手,那這些都不是問題;而 Spring Cloud 就像品牌機,在
Spring Source 的整合下,作了大量的兼容性測試,保證了機器擁有更高的穩定性,可是若是要在使用非原裝組件外的東西,就須要對其基礎有足夠的瞭解。
30、你還了解別的分佈式框架嗎?
別的還有 spring 的 spring cloud,facebook 的 thrift,twitter 的 finagle 等
Elasticsearch 面試題
一、elasticsearch 瞭解多少,說說大家公司 es 的集羣架構,索引數據大小,分片有多少,以及一些調優手段 。
面試官:想了解應聘者以前公司接觸的 ES 使用場景、規模,有沒有作過比較大規模的索引設計、規劃、調優。
解答:
如實結合本身的實踐場景回答便可。
好比:ES 集羣架構 13 個節點,索引根據通道不一樣共 20+索引,根據日期,每日遞增 20+,索引:10 分片,每日遞增 1 億+數據,每一個通道天天索引大小控制:150GB 以內。
僅索引層面調優手段:
1.一、設計階段調優
一、 根據業務增量需求,採起基於日期模板建立索引,經過 roll over API 滾動索引;
二、 使用別名進行索引管理;
三、 天天凌晨定時對索引作 force_merge 操做,以釋放空間; 四、採起冷熱分離機制,熱數據存儲到 SSD,提升檢索效率;冷數據按期進行 shrink 操做,以縮減存儲;
五、 採起 curator 進行索引的生命週期管理;
六、 僅針對須要分詞的字段,合理的設置分詞器;
七、 Mapping 階段充分結合各個字段的屬性,是否須要檢索、是否須要存儲等。……..
1.二、寫入調優
一、 寫入前副本數設置爲 0;
二、 寫入前關閉 refresh_interval 設置爲-1,禁用刷新機制;
三、 寫入過程當中:採起 bulk 批量寫入;
四、 寫入後恢復副本數和刷新間隔;
五、 儘可能使用自動生成的 id。
1.三、查詢調優
一、 禁用 wildcard;
二、 禁用批量 terms(成百上千的場景);
三、 充分利用倒排索引機制,能 keyword 類型儘可能 keyword;
四、 數據量大時候,能夠先基於時間敲定索引再檢索;
五、 設置合理的路由機制。
1.四、其餘調優
部署調優,業務調優等。
上面的說起一部分,面試者就基本對你以前的實踐或者運維經驗有所評估了。
二、elasticsearch 的倒排索引是什麼
面試官:想了解你對基礎概念的認知。
解答:通俗解釋一下就能夠。
傳統的咱們的檢索是經過文章,逐個遍歷找到對應關鍵詞的位置。
而倒排索引,是經過分詞策略,造成了詞和文章的映射關係表,這種詞典+映射表即爲倒排索引。
有了倒排索引,就能實現 o(1)時間複雜度的效率檢索文章了,極大的提升了檢索效率。node
學術的解答方式:
倒排索引,相反於一篇文章包含了哪些詞,它從詞出發,記載了這個詞在哪些文檔中出現過,由兩部分組成——詞典和倒排表。
加分項:倒排索引的底層實現是基於:FST(Finite State Transducer)數據結構。
lucene 從 4+版本後開始大量使用的數據結構是 FST。FST 有兩個優勢:
一、 空間佔用小。經過對詞典中單詞前綴和後綴的重複利用,壓縮了存儲空間;
二、 查詢速度快。O(len(str))的查詢時間複雜度。
三、elasticsearch 索引數據多了怎麼辦,如何調優,部署
面試官:想了解大數據量的運維能力。
解答:索引數據的規劃,應在前期作好規劃,正所謂「設計先行,編碼在後」,這樣纔能有效的避免突如其來的數據激增致使集羣處理能力不足引起的線上客戶檢索或者其餘業務受到影響。
如何調優,正如問題 1 所說,這裏細化一下:
3.1 動態索引層面
基於模板+時間+rollover api 滾動建立索引,舉例:設計階段定義:blog 索引的模板格式爲:blog_index_時間戳的形式,天天遞增數據。
這樣作的好處:不至於數據量激增致使單個索引數據量很是大,接近於上線 2 的
32 次冪-1,索引存儲達到了 TB+甚至更大。
一旦單個索引很大,存儲等各類風險也隨之而來,因此要提早考慮+及早避免。
3.2 存儲層面
冷熱數據分離存儲,熱數據(好比最近 3 天或者一週的數據),其他爲冷數據。對於冷數據不會再寫入新數據,能夠考慮按期 force_merge 加 shrink 壓縮操做,節省存儲空間和檢索效率。
3.3 部署層面
一旦以前沒有規劃,這裏就屬於應急策略。
結合 ES 自身的支持動態擴展的特色,動態新增機器的方式能夠緩解集羣壓力,注意:若是以前主節點等規劃合理,不須要重啓集羣也能完成動態新增的。
四、elasticsearch 是如何實現 master 選舉的
面試官:想了解 ES 集羣的底層原理,再也不只關注業務層面了。
解答:
前置前提:
一、 只有候選主節點(master:true)的節點才能成爲主節點。
二、 最小主節點數(min_master_nodes)的目的是防止腦裂。
這個我看了各類網上分析的版本和源碼分析的書籍,雲裏霧裏。
覈對了一下代碼,核心入口爲 findMaster,選擇主節點成功返回對應 Master,不然返回 null。選舉流程大體描述以下:
第一步:確認候選主節點數達標,elasticsearch.yml 設置的值 discovery.zen.minimum_master_nodes;第二步:比較:先斷定是否具有 master 資格,具有候選主節點資格的優先返回;若兩節點都爲候選主節點,則 id 小的值會主節點。注意這裏的 id 爲 string 類型。
題外話:獲取節點 id 的方法。
1GET /_cat/nodes?v&h=ip,port,heapPercent,heapMax,id,name
2ip port heapPercent heapMax id name
五、詳細描述一下 Elasticsearch 索引文檔的過程
面試官:想了解 ES 的底層原理,再也不只關注業務層面了。
解答:
這裏的索引文檔應該理解爲文檔寫入 ES,建立索引的過程。
文檔寫入包含:單文檔寫入和批量 bulk 寫入,這裏只解釋一下:單文檔寫入流程。
記住官方文檔中的這個圖。mysql
第一步:客戶寫集羣某節點寫入數據,發送請求。(若是沒有指定路由/協調節點,請求的節點扮演路由節點的角色。)
第二步:節點 1 接受到請求後,使用文檔_id 來肯定文檔屬於分片 0。請求會被轉到另外的節點,假定節點 3。所以分片 0 的主分片分配到節點 3 上。
第三步:節點 3 在主分片上執行寫操做,若是成功,則將請求並行轉發到節點 1 和節點 2 的副本分片上,等待結果返回。全部的副本分片都報告成功,節點 3 將向協調節點(節點 1)報告成功,節點 1 向請求客戶端報告寫入成功。
若是面試官再問:第二步中的文檔獲取分片的過程?
回答:藉助路由算法獲取,路由算法就是根據路由和文檔 id 計算目標的分片 id 的過程。
1shard = hash(_routing) % (num_of_primary_shards)
六、詳細描述一下 Elasticsearch 搜索的過程?
面試官:想了解 ES 搜索的底層原理,再也不只關注業務層面了。
解答:
搜索拆解爲「query then fetch」 兩個階段。
query 階段的目的:定位到位置,但不取。
步驟拆解以下:
一、 假設一個索引數據有 5 主+1 副本 共 10 分片,一次請求會命中(主或者副本分片中)的一個。
二、 每一個分片在本地進行查詢,結果返回到本地有序的優先隊列中。
三、 第 2)步驟的結果發送到協調節點,協調節點產生一個全局的排序列表。
fetch 階段的目的:取數據。
路由節點獲取全部文檔,返回給客戶端。
七、Elasticsearch 在部署時,對 Linux 的設置有哪些優化方法
面試官:想了解對 ES 集羣的運維能力。
解答:
一、 關閉緩存 swap;
二、 堆內存設置爲:Min(節點內存/2, 32GB);
三、 設置最大文件句柄數;
四、 線程池+隊列大小根據業務須要作調整;
五、 磁盤存儲 raid 方式——存儲有條件使用 RAID10,增長單節點性能以及避免單節點存儲故障。
八、lucence 內部結構是什麼?
面試官:想了解你的知識面的廣度和深度。
解答:linux
Lucene 是有索引和搜索的兩個過程,包含索引建立,索引,搜索三個要點。能夠基於這個脈絡展開一些。
最近面試一些公司,被問到的關於 Elasticsearch 和搜索引擎相關的問題,以及本身總結的回答。
九、Elasticsearch 是如何實現 Master 選舉的?
一、 Elasticsearch 的選主是 ZenDiscovery 模塊負責的,主要包含 Ping(節點之間經過這個 RPC 來發現彼此)和 Unicast(單播模塊包含一個主機列表以控制哪些節點須要 ping 通)這兩部分;
二、 對全部能夠成爲 master 的節點(node.master: true)根據 nodeId 字典排
序,每次選舉每一個節點都把本身所知道節點排一次序,而後選出第一個(第 0 位)節點,暫且認爲它是 master 節點。
三、 若是對某個節點的投票數達到必定的值(能夠成爲 master 節點數 n/2+1)而且該節點本身也選舉本身,那這個節點就是 master。不然從新選舉一直到知足上述條件。
四、 補充:master 節點的職責主要包括集羣、節點和索引的管理,不負責文檔級別的管理;data 節點能夠關閉 http 功能*。
十、Elasticsearch 中的節點(好比共 20 個),其中的 10 個
選了一個 master,另外 10 個選了另外一個 master,怎麼辦?
一、 當集羣 master 候選數量不小於 3 個時,能夠經過設置最少投票經過數量
(discovery.zen.minimum_master_nodes)超過全部候選節點一半以上來解決腦裂問題;
二、 當候選數量爲兩個時,只能修改成惟一的一個 master 候選,其餘做爲 data 節點,避免腦裂問題。
十一、客戶端在和集羣鏈接時,如何選擇特定的節點執行請求的?
一、TransportClient 利用 transport 模塊遠程鏈接一個 elasticsearch 集羣。它並不加入到集羣中,只是簡單的得到一個或者多個初始化的 transport 地址,並以 輪詢 的方式與這些地址進行通訊。
十二、詳細描述一下 Elasticsearch 索引文檔的過程。
協調節點默認使用文檔 ID 參與計算(也支持經過 routing),以便爲路由提供合適的分片。
shard = hash(document_id) % (num_of_primary_shards)
一、 當分片所在的節點接收到來自協調節點的請求後,會將請求寫入到 Memory
Buffer,而後定時(默認是每隔 1 秒)寫入到 Filesystem Cache,這個從 Momery
Buffer 到 Filesystem Cache 的過程就叫作 refresh;
二、 固然在某些狀況下,存在 Momery Buffer 和 Filesystem Cache 的數據可能會丟失,ES 是經過 translog 的機制來保證數據的可靠性的。其實現機制是接收到請求後,同時也會寫入到 translog 中,當 Filesystem cache 中的數據寫入到磁盤中時,纔會清除掉,這個過程叫作 flush;
三、 在 flush 過程當中,內存中的緩衝將被清除,內容被寫入一個新段,段的 fsync 將建立一個新的提交點,並將內容刷新到磁盤,舊的 translog 將被刪除並開始一個新的 translog。
四、 flush 觸發的時機是定時觸發(默認 30 分鐘)或者 translog 變得太大(默認爲 512M)時;nginx
補充:關於 Lucene 的 Segement:
一、 Lucene 索引是由多個段組成,段自己是一個功能齊全的倒排索引。
二、 段是不可變的,容許 Lucene 將新的文檔增量地添加到索引中,而不用從頭重建索引。
三、 對於每個搜索請求而言,索引中的全部段都會被搜索,而且每一個段會消耗 CPU 的時鐘周、文件句柄和內存。這意味着段的數量越多,搜索性能會越低。
四、 爲了解決這個問題,Elasticsearch 會合並小段到一個較大的段,提交新的合併段到磁盤,並刪除那些舊的小段。
1三、詳細描述一下 Elasticsearch 更新和刪除文檔的過程。
一、 刪除和更新也都是寫操做,可是 Elasticsearch 中的文檔是不可變的,所以不能被刪除或者改動以展現其變動;
二、 磁盤上的每一個段都有一個相應的.del 文件。當刪除請求發送後,文檔並無真的被刪除,而是在.del 文件中被標記爲刪除。該文檔依然能匹配查詢,可是會在結果中被過濾掉。當段合併時,在.del 文件中被標記爲刪除的文檔將不會被寫入新段。
三、 在新的文檔被建立時,Elasticsearch 會爲該文檔指定一個版本號,當執行更新時,舊版本的文檔在.del 文件中被標記爲刪除,新版本的文檔被索引到一個新段。
舊版本的文檔依然能匹配查詢,可是會在結果中被過濾掉。
1四、詳細描述一下 Elasticsearch 搜索的過程。
一、 搜索被執行成一個兩階段過程,咱們稱之爲 Query Then Fetch;
二、 在初始查詢階段時,查詢會廣播到索引中每個分片拷貝(主分片或者副本分片)。 每一個分片在本地執行搜索並構建一個匹配文檔的大小爲 from + size 的優先隊列。
PS:在搜索的時候是會查詢 Filesystem Cache 的,可是有部分數據還在 Memory
Buffer,因此搜索是近實時的。
三、 每一個分片返回各自優先隊列中 全部文檔的 ID 和排序值 給協調節點,它合併這些值到本身的優先隊列中來產生一個全局排序後的結果列表。
四、 接下來就是 取回階段,協調節點辨別出哪些文檔須要被取回並向相關的分片提交多個 GET 請求。每一個分片加載並 豐富 文檔,若是有須要的話,接着返回文檔給協調節點。一旦全部的文檔都被取回了,協調節點返回結果給客戶端。
五、 補充:Query Then Fetch 的搜索類型在文檔相關性打分的時候參考的是本分片的數據,這樣在文檔數量較少的時候可能不夠準確,DFS Query Then Fetch 增長了一個預查詢的處理,詢問 Term 和 Document frequency,這個評分更準確,可是性能會變差。*c++
1五、在 Elasticsearch 中,是怎麼根據一個詞找到對應的倒排索引的?
SEE:
• Lucene 的索引文件格式(1) • Lucene 的索引文件格式(2)
1六、Elasticsearch 在部署時,對 Linux 的設置有哪些優化方法?
一、64 GB 內存的機器是很是理想的, 可是 32 GB 和 16 GB 機器也是很常見的。
少於 8 GB 會拔苗助長。
二、 若是你要在更快的 CPUs 和更多的核心之間選擇,選擇更多的核心更好。多個內核提供的額外併發遠賽過稍微快一點點的時鐘頻率。
三、 若是你負擔得起 SSD,它將遠遠超出任何旋轉介質。 基於 SSD 的節點,查詢和索引性能都有提高。若是你負擔得起,SSD 是一個好的選擇。
四、 即便數據中心們近在咫尺,也要避免集羣跨越多個數據中心。絕對要避免集羣跨越大的地理距離。
五、 請確保運行你應用程序的 JVM 和服務器的 JVM 是徹底同樣的。 在
Elasticsearch 的幾個地方,使用 Java 的本地序列化。
六、 經過設置 gateway.recover_after_nodes、gateway.expected_nodes、
gateway.recover_after_time 能夠在集羣重啓的時候避免過多的分片交換,這可能會讓數據恢復從數個小時縮短爲幾秒鐘。
七、 Elasticsearch 默認被配置爲使用單播發現,以防止節點無心中加入集羣。只有在同一臺機器上運行的節點纔會自動組成集羣。最好使用單播代替組播。
八、 不要隨意修改垃圾回收器(CMS)和各個線程池的大小。
九、 把你的內存的(少於)一半給 Lucene(但不要超過 32 GB!),經過
ES_HEAP_SIZE 環境變量設置。
十、 內存交換到磁盤對服務器性能來講是致命的。若是內存交換到磁盤上,一個100 微秒的操做可能變成 10 毫秒。 再想一想那麼多 10 微秒的操做時延累加起來。 不難看出 swapping 對於性能是多麼可怕。
十一、 Lucene 使用了大量的文件。同時,Elasticsearch 在節點和 HTTP 客戶端之間進行通訊也使用了大量的套接字。 全部這一切都須要足夠的文件描述符。你應該增長你的文件描述符,設置一個很大的值,如 64,000。
補充:索引階段性能提高方法
一、 使用批量請求並調整其大小:每次批量數據 5–15 MB 大是個不錯的起始點。
二、 存儲:使用 SSD
三、 段和合並:Elasticsearch 默認值是 20 MB/s,對機械磁盤應該是個不錯的設置。若是你用的是 SSD,能夠考慮提升到 100–200 MB/s。若是你在作批量導入,徹底不在乎搜索,你能夠完全關掉合併限流。另外還能夠增長 index.translog.flush_threshold_size 設置,從默認的 512 MB 到更大一些的值,好比 1 GB,這能夠在一次清空觸發的時候在事務日誌裏積累出更大的段。
四、 若是你的搜索結果不須要近實時的準確度,考慮把每一個索引的 index.refresh_interval 改到 30s。
五、 若是你在作大批量導入,考慮經過設置 index.number_of_replicas: 0 關閉副本。
1七、對於 GC 方面,在使用 Elasticsearch 時要注意什麼?
一、 SEE:https://elasticsearch.cn/article/32
二、 倒排詞典的索引須要常駐內存,沒法 GC,須要監控 data node 上 segment memory 增加趨勢。
三、 各種緩存,field cache, filter cache, indexing cache, bulk queue 等等,要設置合理的大小,而且要應該根據最壞的狀況來看 heap 是否夠用,也就是各種緩存所有佔滿的時候,還有 heap 空間能夠分配給其餘任務嗎?避免採用 clear cache 等「自欺欺人」的方式來釋放內存。
四、 避免返回大量結果集的搜索與聚合。確實須要大量拉取數據的場景,能夠採用 scan & scroll api 來實現。
五、 cluster stats 駐留內存並沒有法水平擴展,超大規模集羣能夠考慮分拆成多個集羣經過 tribe node 鏈接。
六、 想知道 heap 夠不夠,必須結合實際應用場景,並對集羣的 heap 使用狀況作持續的監控。
1八、Elasticsearch 對於大數據量(上億量級)的聚合如何實現?
Elasticsearch 提供的首個近似聚合是 cardinality 度量。它提供一個字段的基數,即該字段的 distinct或者 unique值的數目。它是基於 HLL 算法的。HLL 會先對咱們的輸入做哈希運算,而後根據哈希運算的結果中的 bits 作機率估算從而獲得基數。其特色是:可配置的精度,用來控制內存的使用(更精確 = 更多內存);小的數據集精度是很是高的;咱們能夠經過配置參數,來設置去重須要的固定內存使用量。不管數千仍是數十億的惟一值,內存使用量只與你配置的精確度相關。
1九、在併發狀況下,Elasticsearch 若是保證讀寫一致?
一、 能夠經過版本號使用樂觀併發控制,以確保新版本不會被舊版本覆蓋,由應用層來處理具體的衝突;
二、 另外對於寫操做,一致性級別支持 quorum/one/all,默認爲 quorum,即只有當大多數分片可用時才容許寫操做。但即便大多數可用,也可能存在由於網絡等緣由致使寫入副本失敗,這樣該副本被認爲故障,分片將會在一個不一樣的節點上重建。
三、 對於讀操做,能夠設置 replication 爲 sync(默認),這使得操做在主分片和副本分片都完成後纔會返回;若是設置 replication 爲 async 時,也能夠經過設置搜索請求參數_preference 爲 primary 來查詢主分片,確保文檔是最新版本。
20、如何監控 Elasticsearch 集羣狀態?
Marvel 讓你能夠很簡單的經過 Kibana 監控 Elasticsearch。你能夠實時查看你的集羣健康狀態和性能,也能夠分析過去的集羣、索引和節點指標。
2一、介紹下大家電商搜索的總體技術架構。git
2二、介紹一下大家的個性化搜索方案?
SEE 基於 word2vec 和 Elasticsearch 實現個性化搜索
2三、是否瞭解字典樹?經常使用字典數據結構以下所示:程序員
Trie 的核心思想是空間換時間,利用字符串的公共前綴來下降查詢時間的開銷以達到提升效率的目的。它有 3 個基本性質:
一、 根節點不包含字符,除根節點外每個節點都只包含一個字符。
二、 從根節點到某一節點,路徑上通過的字符鏈接起來,爲該節點對應的字符串。
三、 每一個節點的全部子節點包含的字符都不相同。
一、 能夠看到,trie 樹每一層的節點數是 26^i 級別的。因此爲了節省空間,咱們還能夠用動態鏈表,或者用數組來模擬動態。而空間的花費,不會超過單詞數×單詞長度。
二、 實現:對每一個結點開一個字母集大小的數組,每一個結點掛一個鏈表,使用左兒子右兄弟表示法記錄這棵樹;
三、 對於中文的字典樹,每一個節點的子節點用一個哈希表存儲,這樣就不用浪費太大的空間,並且查詢速度上能夠保留哈希的複雜度 O(1)。
2四、拼寫糾錯是如何實現的?
一、 拼寫糾錯是基於編輯距離來實現;編輯距離是一種標準的方法,它用來表示通過插入、刪除和替換操做從一個字符串轉換到另一個字符串的最小操做步數;
二、 編輯距離的計算過程:好比要計算 batyu 和 beauty 的編輯距離,先建立一個 7×8 的表(batyu 長度爲 5,coffee 長度爲 6,各加 2),接着,在以下位置填入黑色數字。其餘格的計算過程是取如下三個值的最小值:
若是最上方的字符等於最左方的字符,則爲左上方的數字。不然爲左上方的數字
+1。(對於 3,3 來講爲 0)
左方數字+1(對於 3,3 格來講爲 2)上方數字+1(對於 3,3 格來講爲 2)
最終取右下角的值即爲編輯距離的值 3。
對於拼寫糾錯,咱們考慮構造一個度量空間(Metric Space),該空間內任何關係知足如下三條基本條件:
d(x,y) = 0 -- 假如 x 與 y 的距離爲 0,則 x=y
d(x,y) = d(y,x) -- x 到 y 的距離等同於 y 到 x 的距離 d(x,y) + d(y,z) >= d(x,z) -- 三角不等式
一、 根據三角不等式,則知足與 query 距離在 n 範圍內的另外一個字符轉 B,其與 A 的距離最大爲 d+n,最小爲 d-n。
二、 BK 樹的構造就過程以下:每一個節點有任意個子節點,每條邊有個值表示編輯距離。全部子節點到父節點的邊上標註 n 表示編輯距離剛好爲 n。好比,咱們有棵
樹父節點是」book」和兩個子節點」cake」和」books」,」book」到」books」 的邊標號 1,」book」到」cake」的邊上標號 4。從字典裏構造好樹後,不管何
時你想插入新單詞時,計算該單詞與根節點的編輯距離,而且查找數值爲
d(neweord, root)的邊。遞歸得與各子節點進行比較,直到沒有子節點,你就能夠建立新的子節點並將新單詞保存在那。好比,插入」boo」到剛纔上述例子的樹中,咱們先檢查根節點,查找 d(「book」, 「boo」) = 1 的邊,而後檢查標號爲
1 的邊的子節點,獲得單詞」books」。咱們再計算距離 d(「books」, 「boo」)=2,則將新單詞插在」books」以後,邊標號爲 2。
三、查詢類似詞以下:計算單詞與根節點的編輯距離 d,而後遞歸查找每一個子節點標號爲 d-n 到 d+n(包含)的邊。假如被檢查的節點與搜索單詞的距離 d 小於 n,則返回該節點並繼續查詢。好比輸入 cape 且最大容忍距離爲 1,則先計算和根的編輯距離 d(「book」, 「cape」)=4,而後接着找和根節點之間編輯距離爲 3 到 5 的,這個就找到了 cake 這個節點,計算 d(「cake」, 「cape」)=1,知足條件因此返回 cake,而後再找和 cake 節點編輯距離是 0 到 2 的,分別找到 cape 和 cart 節點,這樣就獲得 cape 這個知足條件的結果。
Memcached 面試題
一、Memcached 是什麼,有什麼做用?
Memcached 是一個開源的,高性能的內存綬存軟件,從名稱上看 Mem 就是內存的意思,而 Cache 就是緩存的意思。Memcached 的做用:經過在事先規劃好的內存空間中臨時綬存數據庫中的各種數據,以達到減小業務對數據庫的直接高併發訪問,從而達到提高數據庫的訪問性能,加速網站集羣動態應用服務的能力。
memcached 服務在企業集羣架構中有哪些應用場景?
1、做爲數據庫的前端緩存應用 a、完整緩存(易),靜態緩存
例如:商品分類(京東),以及商品信息,可事先放在內存裏,而後再對外提供數據訪問,這種先放到內存,咱們稱之爲預熱,(先把數據存緩存中),用戶訪問時能夠只讀取 memcached 緩存,不讀取數據庫了。
b、執點緩存(難)
須要前端 web 程序配合,只緩存熱點的數據,即緩存常常被訪問的數據。
先預熱數據庫裏的基礎數據,而後在動態更新,選讀取緩存,若是緩存裏沒有對應的數據,程序再去讀取數據庫,而後程序把讀取的新數據放入緩存存儲。
特殊說明 :
• 若是碰到電商秒殺等高併發的業務,必定要事先預熱,或者其它思想實現,例如:稱殺只是獲取資格,而不是瞬間秒殺到手商品。
那麼什麼是獲取資格?_
• 就是在數據庫中,把 0 標成 1.就有資格啦。再慢慢的去領取商品訂單。
由於秒殺過程太長會佔用服務器資源。
• 若是數據更新,同時觸發緩存更新,防止給用戶過時數據。
• 對於持久化緩存存儲系統,例如:redis,能夠替代一部分數據庫的存儲,一些簡單的數據業務,投票,統計,好友關注,商品分類等。nosql= not only sql
2、做業集羣的 session 會話共享存儲。
• Memcached 服務在不一樣企業業務應用場景中的工做流程
• 當 web 程序須要訪問後端數據庫獲取數據時會優先訪問 Memcached 內存緩存,若是緩存中有數據就直接獲取返回前端服務及用戶,若是沒有數據(沒有命中),在由程序請求後端的數據庫服務器,獲取到對應的數據後,除了返回給前端服務及用戶數據外,還會把數據放到 Memcached 內存中進行緩存,等待下次請求被訪問,Memcache 內存始終是數據庫的擋箭牌,從而大大的減輕數據庫的訪問壓力,提升整個網站架構的響應速度,提高了用戶體驗。
• 當程序更新,修改或刪除數據庫中已有的數據時,會同時發送請求通知 Memcached 已經緩存的同一個 ID 內容的舊數據失效,從而保證 Memcache 中數據和數據庫中的數據一致。
• 若是在高併發場合,除了通知 Memcached 過程的緩存失效外,還會經過相關機制,使得在用戶訪問新數據前,經過程序預先把更新過的數據推送到 memcache 中緩存起來,這樣能夠減小數據庫的訪問壓力,提高 Memcached 中緩存命中率。
• 數據庫插件能夠再寫入更新數據庫後,自動拋給 MC 緩存起來,自身不
Cache.
二、Memcached 服務分佈式集羣如何實現?
特殊說明:Memcached 集羣和 web 服務集羣是不同的,全部 Memcached 的數據總和纔是數據庫的數據。每臺 Memcached 都是部分數據。
(一臺 memcached 的數據,就是一部分 mysql 數據庫的數據)
a、 程序端實現
程序加載全部 mc 的 ip 列表,經過對 key 作 hash (一致性哈希算法)
例如:web1 (key)===>對應 A,B,C,D,E,F,G…..若干臺服務器。(經過哈希算法實現)
b、 負載均衡器
經過對 key 作 hash (一致性哈希算法)
一致哈希算法的目的是不但保證每一個對象只請求一個對應的服務器,並且當節點宕機,緩存服務器的更新從新分配比例降到最低。
三、Memcached 服務特色及工做原理是什麼?
a、徹底基於內存緩存的 b、節點之間相互獨立
c、 C/S 模式架構,C 語言編寫,總共 2000 行代碼。
d、 異步I/O 模型,使用 libevent 做爲事件通知機制。
e、 被緩存的數據以 key/value 鍵值對形式存在的。
f、 所有數據存放於內存中,無持久性存儲的設計,重啓服務器,內存裏的數據會丟失。
g、 當內存中緩存的數據容量達到啓動時設定的內存值時,就自動使用 LRU 算法刪除過時的緩存數據。
h、 能夠對存儲的數據設置過時時間,這樣過時後的數據自動被清除,服務自己不會監控過時,而是在訪問的時候查看 key 的時間戳,判斷是否過時。
j、memcache 會對設定的內存進行分塊,再把塊分組,而後再提供服務。
四、簡述 Memcached 內存管理機制原理?
早期的 Memcached 內存管理方式是經過 malloc 的分配的內存,使用完後經過 free 來回收內存,這種方式容易產生內存碎片,並下降操做系統對內存的管理效率。加劇操做系統內存管理器的負擔,最壞的狀況下,會致使操做系統比 memcached 進程自己還慢,爲了解決這個問題,Slab Allocation 內存分配機制就延生了。
如今 Memcached 利用 Slab Allocation 機制來分配和管理內存。
Slab
Allocation 機制原理是按照預先規定的大小,將分配給 memcached 的內存分割
成特定長度的內存塊(chunk),再把尺寸相同的內存塊,分紅組
(chunks slab class),這些內存塊不會釋放,能夠重複利用。
並且,slab allocator 還有重複使用已分配的內存的目的。 也就是說,分配到的內存不會釋放,而是重複利用。
Slab Allocation 的主要術語
Page
分配給 Slab 的內存空間,默認是 1MB。分配給 Slab 以後根據 slab 的大小切分紅 chunk。
Chunk
用於緩存記錄的內存空間。
SlabClass
特定大小的 chunk 的組。
集羣架構方面的問題
五、memcached 是怎麼工做的?
Memcached 的神奇來自兩階段哈希(two-stage hash)。Memcached 就像一個巨大的、存儲了不少<key,value>對的哈希表。經過 key,能夠存儲或查詢任意的數據。
客戶端能夠把數據存儲在多臺 memcached 上。當查詢數據時,客戶端首先參考節點列表計算出 key 的哈希值(階段一哈希),進而選中一個節點;客戶端將請求發送給選中的節點,而後 memcached 節點經過一個內部的哈希算法(階段二哈希),查找真正的數據(item)。
六、memcached 最大的優點是什麼?
Memcached 最大的好處就是它帶來了極佳的水平可擴展性,特別是在一個巨大的系統中。因爲客戶端本身作了一次哈希,那麼咱們很容易增長大量 memcached 到集羣中。memcached 之間沒有相互通訊,所以不會增長 memcached 的負載;沒有多播協議,不會網絡通訊量爆炸(implode)。memcached 的集羣很好用。內存不夠了?增長几臺 memcached 吧;CPU 不夠用了?再增長几臺吧;有多餘的內存?在增長几臺吧,不要浪費了。
基於 memcached 的基本原則,能夠至關輕鬆地構建出不一樣類型的緩存架構。除了這篇 FAQ,在其餘地方很容易找到詳細資料的。
七、memcached 和 MySQL 的 query
cache 相比,有什麼優缺點?
把 memcached 引入應用中,仍是須要很多工做量的。MySQL 有個使用方便的 query cache,能夠自動地緩存 SQL 查詢的結果,被緩存的 SQL 查詢能夠被反覆地快速執行。Memcached 與之相比,怎麼樣呢?MySQL 的 query cache 是集中式的,鏈接到該 query cache 的 MySQL 服務器都會受益。
• 當您修改表時,MySQL 的 query cache 會馬上被刷新(flush)。存儲一個 memcached item 只須要不多的時間,可是當寫操做很頻繁時,MySQL 的 query cache 會常常讓全部緩存數據都失效。
• 在多核 CPU 上,MySQL 的 query cache 會遇到擴展問題(scalability issues)。在多核 CPU 上,query cache 會增長一個全局鎖(global lock), 因爲須要刷新更多的緩存數據,速度會變得更慢。
• 在 MySQL 的 query cache 中,咱們是不能存儲任意的數據的(只能是 SQL 查詢結果)。而利用 memcached,咱們能夠搭建出各類高效的緩存。好比,能夠執行多個獨立的查詢,構建出一個用戶對象(user object),而後將用戶對象緩存到 memcached 中。而 query cache 是 SQL 語句級別的,不可能作到這一點。在小的網站中,query cache 會有所幫助,但隨着網站規模的增長, query cache 的弊將大於利。
• query cache可以利用的內存容量受到MySQL服務器空閒內存空間的限制。給數據庫服務器增長更多的內存來緩存數據,當然是很好的。可是,有了 memcached,只要您有空閒的內存,均可以用來增長 memcached 集羣的規模,而後您就能夠緩存更多的數據。
八、memcached 和服務器的 local cache(好比 PHP 的 APC、
mmap 文件等)相比,有什麼優缺點?
首先,local cache 有許多與上面(query cache)相同的問題。local cache 可以利用的內存容量受到(單臺)服務器空閒內存空間的限制。不過,local
cache 有一點比 memcached 和 query cache 都要好,那就是它不但能夠存儲任意的數據,並且沒有網絡存取的延遲。
• local cache 的數據查詢更快。考慮把 highly common 的數據放在 local cache 中吧。若是每一個頁面都須要加載一些數量較少的數據,考慮把它們放在 local
cached 吧。
• local cache 缺乏集體失效(group
invalidation)的特性。在 memcached 集羣中,刪除或更新一個 key 會讓全部的觀察者覺察到。可是在local cache中, 咱們只能通知全部的服務器刷新cache
(很慢,不具擴展性),或者僅僅依賴緩存超時失效機制。
• local cache 面臨着嚴重的內存限制,這一點上面已經提到。
九、memcached 的 cache 機制是怎樣的?
Memcached 主要的 cache 機制是 LRU(最近最少用)算法+超時失效。當您存數據到 memcached 中,能夠指定該數據在緩存中能夠呆多久 Which is forever, or some time in the future。若是 memcached 的內存不夠用了,過時的 slabs 會優先被替換,接着就輪到最老的未被使用的 slabs。
十、memcached 如何實現冗餘機制?
不實現!咱們對這個問題感到很驚訝。Memcached 應該是應用的緩存層。它的設計自己就不帶有任何冗餘機制。若是一個 memcached 節點失去了全部數據,您應該能夠從數據源(好比數據庫)再次獲取到數據。您應該特別注意,您的應用應該能夠容忍節點的失效。不要寫一些糟糕的查詢代碼,寄但願於 memcached 來保證一切!若是您擔憂節點失效會大大加劇數據庫的負擔,那麼您能夠採起一些辦法。好比您能夠增長更多的節點(來減小丟失一個節點的影響),熱備節點
(在其餘節點 down 了的時候接管 IP),等等。
十一、memcached 如何處理容錯的?
不處理! 在 memcached 節點失效的狀況下,集羣沒有必要作任何容錯處理。若是發生了節點失效,應對的措施徹底取決於用戶。節點失效時,下面列出幾種方案供您選擇:
• 忽略它! 在失效節點被恢復或替換以前,還有不少其餘節點能夠應對節點失效帶來的影響。
• 把失效的節點從節點列表中移除。作這個操做千萬要當心!在默認狀況下(餘數式哈希算法),客戶端添加或移除節點,會致使全部的緩存數據不可用!由於哈希參照的節點列表變化了,大部分 key 會由於哈希值的改變而被映射到
(與原來)不一樣的節點上。
• 啓動熱備節點,接管失效節點所佔用的 IP。這樣能夠防止哈希紊亂
(hashing chaos)。
• 若是但願添加和移除節點,而不影響原先的哈希結果,能夠使用一致性哈希算法(consistent hashing)。您能夠百度一下一致性哈希算法。支持一致性哈希的客戶端已經很成熟,並且被普遍使用。去嘗試一下吧!
• 兩次哈希(reshing)。當客戶端存取數據時,若是發現一個節點 down 了,就再作一次哈希(哈希算法與前一次不一樣),從新選擇另外一個節點(須要注意的時,客戶端並無把 down 的節點從節點列表中移除,下次仍是有可能先哈希到它)。若是某個節點時好時壞,兩次哈希的方法就有風險了,好的節點和壞的節點上均可能存在髒數據(stale data)。
十二、如何將 memcached 中 item 批量導入導出?
您不該該這樣作!Memcached 是一個非阻塞的服務器。任何可能致使
memcached 暫停或瞬時拒絕服務的操做都應該值得深思熟慮。向 memcached 中批量導入數據每每不是您真正想要的!想象看,若是緩存數據在導出導入之間發生了變化,您就須要處理髒數據了;
1三、若是緩存數據在導出導入之間過時了,您又怎麼處理這些數據呢?
所以,批量導出導入數據並不像您想象中的那麼有用。不過在一個場景卻是頗有用。若是您有大量的從不變化的數據,而且但願緩存很快熱(warm)起來,批量導入緩存數據是頗有幫助的。雖然這個場景並不典型,但卻常常發生,所以咱們會考慮在未來實現批量導出導入的功能。
若是一個 memcached 節點 down 了讓您很痛苦,那麼您還會陷入其餘不少麻煩。
您的系統太脆弱了。您須要作一些優化工做。好比處理」驚羣」問題(好比
memcached 節點都失效了,反覆的查詢讓您的數據庫不堪重負…這個問題在 FAQ 的其餘提到過),或者優化很差的查詢。記住,Memcached 並非您逃避優化查詢的藉口。
1四、memcached 是如何作身份驗證的?
沒有身份認證機制!memcached 是運行在應用下層的軟件(身份驗證應該是應用上層的職責)。memcached 的客戶端和服務器端之因此是輕量級的,部分緣由就是徹底沒有實現身份驗證機制。這樣,memcached 能夠很快地建立新鏈接,服務器端也無需任何配置。
若是您但願限制訪問,您能夠使用防火牆,或者讓 memcached 監聽 unix domain socket。
1五、memcached 的多線程是什麼?如何使用它們?
線程就是定律(threads rule)!在 Steven Grimm 和 Facebook 的努力下,
memcached 1.2 及更高版本擁有了多線程模式。多線程模式容許 memcached 可以充分利用多個 CPU,並在 CPU 之間共享全部的緩存數據。memcached 使用一種簡單的鎖機制來保證數據更新操做的互斥。相比在同一個物理機器上運行多個 memcached 實例,這種方式可以更有效地處理 multi gets。
若是您的系統負載並不重,也許您不須要啓用多線程工做模式。若是您在運行一個擁有大規模硬件的、龐大的網站,您將會看到多線程的好處。
簡單地總結一下:命令解析(memcached 在這裏花了大部分時間)能夠運行在多線程模式下。memcached 內部對數據的操做是基於不少全局鎖的(所以這部分工
做不是多線程的)。將來對多線程模式的改進,將移除大量的全局鎖,提升 memcached 在負載極高的場景下的性能。
1六、memcached 能接受的 key 的最大長度是多少?
key 的最大長度是 250 個字符。須要注意的是,250 是 memcached 服務器端內部的限制,若是您使用的客戶端支持」key 的前綴」或相似特性,那麼 key(前綴
+原始 key)的最大長度是能夠超過 250 個字符的。咱們推薦使用使用較短的 key,由於能夠節省內存和帶寬。
memcached 對 item 的過時時間有什麼限制?
過時時間最大能夠達到 30 天。memcached 把傳入的過時時間(時間段)解釋成時間點後,一旦到了這個時間點,memcached 就把 item 置爲失效狀態。這是一個簡單但 obscure 的機制。
1七、memcached 最大能存儲多大的單個 item?
1MB。若是你的數據大於 1MB,能夠考慮在客戶端壓縮或拆分到多個 key 中。
爲何單個 item 的大小被限制在 1M byte 以內?
啊…這是一個你們常常問的問題!
簡單的回答:由於內存分配器的算法就是這樣的。
詳細的回答:Memcached 的內存存儲引擎(引擎未來可插拔…),使用 slabs 來管理內存。內存被分紅大小不等的 slabs chunks(先分紅大小相等的 slabs,而後每一個 slab 被分紅大小相等 chunks,不一樣 slab 的 chunk 大小是不相等的)。chunk 的大小依次從一個最小數開始,按某個因子增加,直到達到最大的可能值。
1八、memcached 可以更有效地使用內存嗎?
Memcache 客戶端僅根據哈希算法來決定將某個 key 存儲在哪一個節點上,而不考慮節點的內存大小。所以,您能夠在不一樣的節點上使用大小不等的緩存。可是通常都是這樣作的:擁有較多內存的節點上能夠運行多個 memcached 實例,每一個實例使用的內存跟其餘節點上的實例相同。
1九、什麼是二進制協議,我該關注嗎?
關於二進制最好的信息固然是二進制協議規範:
二進制協議嘗試爲端提供一個更有效的、可靠的協議,減小客戶端/服務器端因處理協議而產生的 CPU 時間。
根據 Facebook 的測試,解析 ASCII 協議是 memcached 中消耗 CPU 時間最多的環節。因此,咱們爲何不改進 ASCII 協議呢?
20、memcached 的內存分配器是如何工做的?爲何不適用
malloc/free!?爲什麼要使用 slabs?
實際上,這是一個編譯時選項。默認會使用內部的 slab 分配器。您確實確實應該使用內建的 slab 分配器。最先的時候,memcached 只使用 malloc/free 來管理內存。然而,這種方式不能與 OS 的內存管理之前很好地工做。反覆地 malloc/free 形成了內存碎片,OS 最終花費大量的時間去查找連續的內存塊來知足 malloc 的請求,而不是運行 memcached 進程。若是您不一樣意,固然能夠使用 malloc!只
是不要在郵件列表中抱怨啊
slab 分配器就是爲了解決這個問題而生的。內存被分配並劃分紅 chunks,一直被重複使用。由於內存被劃分紅大小不等的 slabs,若是 item 的大小與被選擇存放它的 slab 不是很合適的話,就會浪費一些內存。Steven Grimm 正在這方面已經作出了有效的改進。
2一、memcached 是原子的嗎?
全部的被髮送到 memcached 的單個命令是徹底原子的。若是您針對同一份數據同時發送了一個 set 命令和一個 get 命令,它們不會影響對方。它們將被串行化、前後執行。即便在多線程模式,全部的命令都是原子的,除非程序有 bug:)
命令序列不是原子的。若是您經過 get 命令獲取了一個 item,修改了它,而後想把它 set 回 memcached,咱們不保證這個 item 沒有被其餘進程(process,未必是操做系統中的進程)操做過。在併發的狀況下,您也可能覆寫了一個被其餘進程 set 的 item。
memcached 1.2.5 以及更高版本,提供了 gets 和 cas 命令,它們能夠解決上面的問題。若是您使用 gets 命令查詢某個 key 的 item,memcached 會給您返回該 item 當前值的惟一標識。若是您覆寫了這個 item 並想把它寫回到 memcached 中,您能夠經過 cas 命令把那個惟一標識一塊兒發送給 memcached。若是該 item 存放在 memcached 中的惟一標識與您提供的一致,您的寫操做將會成功。若是另外一個進程在這期間也修改了這個 item,那麼該 item 存放在 memcached 中的惟一標識將會改變,您的寫操做就會失敗
2二、如何實現集羣中的 session 共享存儲?
Session 是運行在一臺服務器上的,全部的訪問都會到達咱們的惟一服務器上,這樣咱們能夠根據客戶端傳來的 sessionID,來獲取 session,或在對應 Session 不存在的狀況下(session 生命週期到了/用戶第一次登陸),建立一個新的 Session;可是,若是咱們在集羣環境下,假設咱們有兩臺服務器 A,B,用戶的請求會由
Nginx 服務器進行轉發(別的方案也是同理),用戶登陸時,Nginx 將請求轉發至服務器 A 上,A 建立了新的 session,並將 SessionID 返回給客戶端,用戶在瀏覽其餘頁面時,客戶端驗證登陸狀態,Nginx 將請求轉發至服務器 B,因爲 B 上
並無對應客戶端發來 sessionId 的 session,因此會從新建立一個新的 session,而且再將這個新的 sessionID 返回給客戶端,這樣,咱們能夠想象一下,用戶每一次操做都有 1/2 的機率進行再次的登陸,這樣不只對用戶體驗特別差,還會讓服務器上的 session 激增,加大服務器的運行壓力。
爲了解決集羣環境下的 seesion 共享問題,共有 4 種解決方案:
1.粘性 session
粘性 session 是指 Ngnix 每次都將同一用戶的全部請求轉發至同一臺服務器上,即將用戶與服務器綁定。
2.服務器 session 複製
即每次 session 發生變化時,建立或者修改,就廣播給全部集羣中的服務器,使全部的服務器上的 session 相同。
3.session 共享
緩存 session,使用 redis, memcached。
4.session 持久化
將 session 存儲至數據庫中,像操做數據同樣才作 session。
2三、memcached 與 redis 的區別?
一、 Redis 不只僅支持簡單的 k/v 類型的數據,同時還提供 list,set,zset,hash 等數據結構的存儲。而 memcache 只支持簡單數據類型,須要客戶端本身處理複雜對象
二、 Redis 支持數據的持久化,能夠將內存中的數據保持在磁盤中,重啓的時候能夠再次加載進行使用(PS:持久化在 rdb、aof)。
三、 因爲 Memcache 沒有持久化機制,所以宕機全部緩存數據失效。Redis 配置爲持久化,宕機重啓後,將自動加載宕機時刻的數據到緩存系統中。具備更好的災備機制。
四、 Memcache 能夠使用 Magent 在客戶端進行一致性 hash 作分佈式。Redis 支持在服務器端作分佈式(PS:Twemproxy/Codis/Redis-cluster 多種分佈式實現方式)
五、 Memcached 的簡單限制就是鍵(key)和 Value 的限制。最大鍵長爲 250 個字符。能夠接受的儲存數據不能超過 1MB(可修改配置文件變大),由於這是典型 slab 的最大值,不適合虛擬機使用。而 Redis 的 Key 長度支持到 512k。
六、 Redis 使用的是單線程模型,保證了數據按順序提交。Memcache 須要使用 cas 保證數據一致性。CAS(Check and Set)是一個確保併發一致性的機制,屬於「樂觀鎖」範疇;原理很簡單:拿版本號,操做,對比版本號,若是一致就操做,不一致就放棄任何操做
cpu 利用。因爲 Redis 只使用單核,而 Memcached 能夠使用多核,因此平均每個核上 Redis 在存儲小數據時比 Memcached 性能更 高。而在 100k 以上的數據中,Memcached 性能要高於 Redis 。
七、 memcache 內存管理:使用 Slab Allocation。原理至關簡單,預先分配一系列大小固定的組,而後根據數據大小選擇最合適的塊存儲。避免了內存碎片。(缺點:不能變長,浪費了必定空間)memcached 默認狀況下下一個 slab 的最大值爲前一個的 1.25 倍。
八、 redis 內存管理: Redis 經過定義一個數組來記錄全部的內存分配狀況, Redis 採用的是包裝的 malloc/free,相較於 Memcached 的內存 管理方法來講,要簡單不少。因爲 malloc 首先以鏈表的方式搜索已管理的內存中可用的空間分配,致使內存碎片比較多
Redis 面試題
一、什麼是 Redis?
Redis 是徹底開源免費的,遵照 BSD 協議,是一個高性能的 key-value 數據庫。
Redis 與其餘 key - value 緩存產品有如下三個特色:
Redis 支持數據的持久化,能夠將內存中的數據保存在磁盤中,重啓的時候能夠再次加載進行使用。
Redis 不只僅支持簡單的 key-value 類型的數據,同時還提供 list,set,zset, hash 等數據結構的存儲。
Redis 支持數據的備份,即 master-slave 模式的數據備份。
Redis 優點
性能極高 – Redis 能讀的速度是 110000 次/s,寫的速度是 81000 次/s 。
豐富的數據類型 – Redis 支持二進制案例的 Strings, Lists, Hashes, Sets 及
Ordered Sets 數據類型操做。
原子 – Redis 的全部操做都是原子性的,意思就是要麼成功執行要麼失敗徹底不執行。單個操做是原子性的。多個操做也支持事務,即原子性,經過 MULTI 和 EXEC 指令包起來。
豐富的特性 – Redis 還支持 publish/subscribe, 通知, key 過時等等特性。
Redis 與其餘 key-value 存儲有什麼不一樣?
Redis 有着更爲複雜的數據結構而且提供對他們的原子性操做,這是一個不一樣於其餘數據庫的進化路徑。Redis 的數據類型都是基於基本數據結構的同時對程序員透明,無需進行額外的抽象。
Redis 運行在內存中可是能夠持久化到磁盤,因此在對不一樣數據集進行高速讀寫時須要權衡內存,由於數據量不能大於硬件內存。在內存數據庫方面的另外一個優勢是,相比在磁盤上相同的複雜的數據結構,在內存中操做起來很是簡單,這樣 Redis 能夠作不少內部複雜性很強的事情。同時,在磁盤格式方面他們是緊湊的以追加的方式產生的,由於他們並不須要進行隨機訪問。
二、Redis 的數據類型?
答:Redis 支持五種數據類型:string(字符串),hash(哈希),list(列表), set(集合)及 zsetsorted set:有序集合)。
咱們實際項目中比較經常使用的是 string,hash 若是你是 Redis 中高級用戶,還須要加上下面幾種數據結構 HyperLogLog、Geo、Pub/Sub。
若是你說還玩過 Redis Module,像 BloomFilter,RedisSearch,Redis-ML,面試官得眼睛就開始發亮了。
三、使用 Redis 有哪些好處?
一、 速度快,由於數據存在內存中,相似於 HashMap,HashMap 的優點就是查找和操做的時間複雜度都是 O1)
二、 支持豐富數據類型,支持 string,list,set,Zset,hash 等
三、 支持事務,操做都是原子性,所謂的原子性就是對數據的更改要麼所有執行,要麼所有不執行
四、 豐富的特性:可用於緩存,消息,按 key 設置過時時間,過時後將會自動刪除
四、Redis 相比 Memcached 有哪些優點?
一、 Memcached 全部的值均是簡單的字符串,redis 做爲其替代者,支持更爲豐富的數據類
二、 Redis 的速度比 Memcached 快很
三、 Redis 能夠持久化其數據
五、Memcache 與 Redis 的區別都有哪些?
一、 存儲方式 Memecache 把數據所有存在內存之中,斷電後會掛掉,數據不能超過內存大小。 Redis 有部份存在硬盤上,這樣能保證數據的持久性。
二、 數據支持類型 Memcache 對數據類型支持相對簡單。 Redis 有複雜的數據類型。
三、 使用底層模型不一樣 它們之間底層實現方式 以及與客戶端之間通訊的應用協議不同。 Redis 直接本身構建了 VM 機制 ,由於通常的系統調用系統函數的話,會浪費必定的時間去移動和請求。
六、Redis 是單進程單線程的?
答:Redis 是單進程單線程的,redis 利用隊列技術將併發訪問變爲串行訪問,消除了傳統數據庫串行控制的開銷。
七、一個字符串類型的值能存儲最大容量是多少?
答:512M
八、Redis 的持久化機制是什麼?各自的優缺點?
Redis 提供兩種持久化機制 RDB 和 AOF 機制:
一、RDBRedis DataBase)持久化方式: 是指用數據集快照的方式半持久化模式) 記錄 redis 數據庫的全部鍵值對,在某個時間點將數據寫入一個臨時文件,持久化結束後,用這個臨時文件替換上次持久化的文件,達到數據恢復。
優勢:
一、 只有一個文件 dump.rdb,方便持久化。
二、 容災性好,一個文件能夠保存到安全的磁盤。
三、 性能最大化,fork 子進程來完成寫操做,讓主進程繼續處理命令,因此是 IO 最大化。使用單獨子進程來進行持久化,主進程不會進行任何 IO 操做,保證了 redis 的高性能) 4.相對於數據集大時,比 AOF 的啓動效率更高。
缺點:
一、 數據安全性低。RDB 是間隔一段時間進行持久化,若是持久化之間 redis 發生故障,會發生數據丟失。因此這種方式更適合數據要求不嚴謹的時候)
二、 AOFAppend-only file)持久化方式: 是指全部的命令行記錄以 redis 命令請求協議的格式徹底持久化存儲)保存爲 aof 文件。
優勢:
一、 數據安全,aof 持久化能夠配置 appendfsync 屬性,有 always,每進行一次命令操做就記錄到 aof 文件中一次。
二、 經過 append 模式寫文件,即便中途服務器宕機,能夠經過 redis-check-aof 工具解決數據一致性問題。
三、 AOF 機制的 rewrite 模式。AOF 文件沒被 rewrite 以前(文件過大時會對命令進行合併重寫),能夠刪除其中的某些命令(好比誤操做的 flushall))
缺點:
一、 AOF 文件比 RDB 文件大,且恢復速度慢。
二、 數據集大的時候,比 rdb 啓動效率低。
九、Redis 常見性能問題和解決方案:
一、 Master 最好不要寫內存快照,若是 Master 寫內存快照,save 命令調度 rdbSave 函數,會阻塞主線程的工做,當快照比較大時對性能影響是很是大的,會間斷性暫停服務
二、 若是數據比較重要,某個 Slave 開啓 AOF 備份數據,策略設置爲每秒同步一
三、 爲了主從複製的速度和鏈接的穩定性,Master 和 Slave 最好在同一個局域網
四、 儘可能避免在壓力很大的主庫上增長從
五、 主從複製不要用圖狀結構,用單向鏈表結構更爲穩定,即:Master <- Slave1 <- Slave2 <- Slave3…這樣的結構方便解決單點故障問題,實現 Slave 對 Master 的替換。若是 Master 掛了,能夠馬上啓用 Slave1 作 Master,其餘不變。
十、redis 過時鍵的刪除策略?
一、 定時刪除:在設置鍵的過時時間的同時,建立一個定時器 timer). 讓定時器在鍵的過時時間來臨時,當即執行對鍵的刪除操做。
二、 惰性刪除:聽任鍵過時無論,可是每次從鍵空間中獲取鍵時,都檢查取得的鍵是否過時,若是過時的話,就刪除該鍵;若是沒有過時,就返回該鍵。
三、 按期刪除:每隔一段時間程序就對數據庫進行一次檢查,刪除裏面的過時鍵。至於要刪除多少過時鍵,以及要檢查多少個數據庫,則由算法決定。
十一、Redis 的回收策略(淘汰策略)?
volatile-lru:從已設置過時時間的數據集(server.db[i].expires)中挑選最近最少使用的數據淘汰
volatile-ttl:從已設置過時時間的數據集(server.db[i].expires)中挑選將要過時的數據淘汰
volatile-random:從已設置過時時間的數據集(server.db[i].expires)中任意選擇數據淘汰
allkeys-lru:從數據集(server.db[i].dict)中挑選最近最少使用的數據淘汰
allkeys-random:從數據集(server.db[i].dict)中任意選擇數據淘汰
no-enviction(驅逐):禁止驅逐數據
注意這裏的 6 種機制,volatile 和 allkeys 規定了是對已設置過時時間的數據集淘汰數據仍是從所有數據集淘汰數據,後面的 lru、ttl 以及 random 是三種不一樣的淘汰策略,再加上一種 no-enviction 永不回收的策略。
使用策略規則:
一、 若是數據呈現冪律分佈,也就是一部分數據訪問頻率高,一部分數據訪問頻率低,則使用 allkeys-lru
二、 若是數據呈現平等分佈,也就是全部的數據訪問頻率都相同,則使用 allkeys-random
十二、爲何 edis 須要把全部數據放到內存中?
答:Redis 爲了達到最快的讀寫速度將數據都讀到內存中,並經過異步的方式將數據寫入磁盤。因此 redis 具備快速和數據持久化的特徵。若是不將數據放在內存中,磁盤 I/O 速度爲嚴重影響 redis 的性能。在內存愈來愈便宜的今天,redis 將會愈來愈受歡迎。若是設置了最大使用的內存,則數據已有記錄數達到內存限值後不能繼續插入新值。
1三、Redis 的同步機制瞭解麼?
答:Redis 能夠使用主從同步,從從同步。第一次同步時,主節點作一次 bgsave,並同時將後續修改操做記錄到內存 buffer,待完成後將 rdb 文件全量同步到複製節點,複製節點接受完成後將 rdb 鏡像加載到內存。加載完成後,再通知主節點將期間修改的操做記錄同步到複製節點進行重放就完成了同步過程。
1四、Pipeline 有什麼好處,爲何要用 pipeline?
答:能夠將屢次 IO 往返的時間縮減爲一次,前提是 pipeline 執行的指令之間沒有因果相關性。使用 redis-benchmark 進行壓測的時候能夠發現影響 redis 的 QPS 峯值的一個重要因素是 pipeline 批次指令的數目。
1五、是否使用過 Redis 集羣,集羣的原理是什麼?
1)、Redis Sentinal 着眼於高可用,在 master 宕機時會自動將 slave 提高爲 master,繼續提供服務。
2)、Redis Cluster 着眼於擴展性,在單個 redis 內存不足時,使用 Cluster 進行分片存儲。
1六、Redis 集羣方案什麼狀況下會致使整個集羣不可用?
答:有 A,B,C 三個節點的集羣,在沒有複製模型的狀況下,若是節點 B 失敗了,那麼整個集羣就會覺得缺乏 5501-11000 這個範圍的槽而不可用。
1七、Redis 支持的 Java 客戶端都有哪些?官方推薦用哪一個?
答:Redisson、Jedis、lettuce 等等,官方推薦使用 Redisson。
1八、Jedis 與 Redisson 對比有什麼優缺點?
答:Jedis 是 Redis 的 Java 實現的客戶端,其 API 提供了比較全面的 Redis 命令的支持;Redisson 實現了分佈式和可擴展的 Java 數據結構,和 Jedis 相比,功能較爲簡單,不支持字符串操做,不支持排序、事務、管道、分區等 Redis 特性。
Redisson 的宗旨是促進使用者對 Redis 的關注分離,從而讓使用者可以將精力更集中地放在處理業務邏輯上。
1九、Redis 如何設置密碼及驗證密碼?
設置密碼:config set requirepass 123456
受權密碼:auth 123456
20、說說 Redis 哈希槽的概念?
答:Redis 集羣沒有使用一致性 hash,而是引入了哈希槽的概念,Redis 集羣有
16384 個哈希槽,每一個 key 經過 CRC16 校驗後對 16384 取模來決定放置哪一個槽,集羣的每一個節點負責一部分 hash 槽。
2一、Redis 集羣的主從複製模型是怎樣的?
答:爲了使在部分節點失敗或者大部分節點沒法通訊的狀況下集羣仍然可用,因此集羣使用了主從複製模型,每一個節點都會有 N-1 個複製品.
2二、Redis 集羣會有寫操做丟失嗎?爲何?
答:Redis 並不能保證數據的強一致性,這意味這在實際中集羣在特定的條件下可能會丟失寫操做。
2三、 Redis 集羣之間是如何複製的?答:異步複製
2四、 Redis 集羣最大節點個數是多少?
答:16384 個。
2五、 Redis 集羣如何選擇數據庫?
答:Redis 集羣目前沒法作數據庫選擇,默認在 0 數據庫。
2六、 怎麼測試 Redis 的連通性?
答:使用 ping 命令。
2七、怎麼理解 Redis 事務?
答:
1) 事務是一個單獨的隔離操做:事務中的全部命令都會序列化、按順序地執行。
事務在執行的過程當中,不會被其餘客戶端發送來的命令請求所打斷。
2) 事務是一個原子操做:事務中的命令要麼所有被執行,要麼所有都不執行。
2八、 Redis 事務相關的命令有哪幾個?答:MULTI、EXEC、DISCARD、WATCH
2九、 Redis key 的過時時間和永久有效分別怎麼設置?
答:EXPIRE 和 PERSIST 命令。
30、Redis 如何作內存優化?
答:儘量使用散列表(hashes),散列表(是說散列表裏面存儲的數少)使用的內存很是小,因此你應該儘量的將你的數據模型抽象到一個散列表裏面。好比你的 web 系統中有一個用戶對象,不要爲這個用戶的名稱,姓氏,郵箱,密碼設置單獨的 key,而是應該把這個用戶的全部信息存儲到一張散列表裏面.
3一、Redis 回收進程如何工做的?
答:一個客戶端運行了新的命令,添加了新的數據。Redi 檢查內存使用狀況,若是大於 maxmemory 的限制, 則根據設定好的策略進行回收。一個新的命令被執行,等等。因此咱們不斷地穿越內存限制的邊界,經過不斷達到邊界而後不斷地回收回到邊界如下。若是一個命令的結果致使大量內存被使用(例如很大的集合的交集保存到一個新的鍵),不用多久內存限制就會被這個內存使用量超越。
3二、都有哪些辦法能夠下降 Redis 的內存使用狀況呢?
答:若是你使用的是 32 位的 Redis 實例,能夠好好利用 Hash,list,sorted set,set 等集合類型數據,由於一般狀況下不少小的 Key-Value 能夠用更緊湊的方式存放到一塊兒。
3三、Redis 的內存用完了會發生什麼?
答:若是達到設置的上限,Redis 的寫命令會返回錯誤信息(可是讀命令還能夠正常返回。)或者你能夠將 Redis 當緩存來使用配置淘汰機制,當 Redis 達到內存上限時會沖刷掉舊的內容。
3四、一個 Redis 實例最多能存放多少的 keys?List、Set、
Sorted Set 他們最多能存放多少元素?
答:理論上 Redis 能夠處理多達 232 的 keys,而且在實際中進行了測試,每一個實例至少存放了 2 億 5 千萬的 keys。咱們正在測試一些較大的值。任何 list、set、和 sorted set 均可以放 232 個元素。換句話說,Redis 的存儲極限是系統中的可用內存值。
3五、MySQL 裏有 2000w 數據,redis 中只存 20w 的數據,如
何保證 redis 中的數據都是熱點數據?
答:Redis 內存數據集大小上升到必定大小的時候,就會施行數據淘汰策略。
相關知識:Redis 提供 6 種數據淘汰策略:
volatile-lru:從已設置過時時間的數據集(server.db[i].expires)中挑選最近最少使用的數據淘汰
volatile-ttl:從已設置過時時間的數據集(server.db[i].expires)中挑選將要過時的數據淘汰 volatile-random:從已設置過時時間的數據集(server.db[i].expires)中任意選擇數據淘汰
allkeys-lru:從數據集(server.db[i].dict)中挑選最近最少使用的數據淘汰
allkeys-random:從數據集(server.db[i].dict)中任意選擇數據淘汰
no-enviction(驅逐):禁止驅逐數據
3六、Redis 最適合的場景?
一、 會話緩存(Session Cache)
最經常使用的一種使用 Redis 的情景是會話緩存(session cache)。用 Redis 緩存會話比其餘存儲(如 Memcached)的優點在於:Redis 提供持久化。當維護一個不是嚴格要求一致性的緩存時,若是用戶的購物車信息所有丟失,大部分人都會不高興的,如今,他們還會這樣嗎? 幸運的是,隨着 Redis 這些年的改進,很容
易找到怎麼恰當的使用 Redis 來緩存會話的文檔。甚至廣爲人知的商業平臺
Magento 也提供 Redis 的插件。
二、 全頁緩存(FPC)
除基本的會話 token 以外,Redis 還提供很簡便的 FPC 平臺。回到一致性問題,即便重啓了 Redis 實例,由於有磁盤的持久化,用戶也不會看到頁面加載速度的降低,這是一個極大改進,相似 PHP 本地 FPC。 再次以 Magento 爲例,Magento 提供一個插件來使用 Redis 做爲全頁緩存後端。 此外,對 WordPress 的用戶來講,Pantheon 有一個很是好的插件 wp-redis,這個插件能幫助你以最快速度加載你曾瀏覽過的頁面。
三、 隊列
Reids 在內存存儲引擎領域的一大優勢是提供 list 和 set 操做,這使得 Redis 能做爲一個很好的消息隊列平臺來使用。Redis 做爲隊列使用的操做,就相似於本地程序語言(如 Python)對 list 的 push/pop 操做。 若是你快速的在 Google 中搜索「Redis queues」,你立刻就能找到大量的開源項目,這些項目的目的就是利用 Redis 建立很是好的後端工具,以知足各類隊列需求。例如,Celery 有一個後臺就是使用 Redis 做爲 broker,你能夠從這裏去查看。
4,排行榜/計數器
Redis 在內存中對數字進行遞增或遞減的操做實現的很是好。集合(Set)和有序集合(Sorted Set)也使得咱們在執行這些操做的時候變的很是簡單,Redis 只是正好提供了這兩種數據結構。因此,咱們要從排序集合中獲取到排名最靠前的 10 個用戶–咱們稱之爲「user_scores」,咱們只須要像下面同樣執行便可: 固然,這是假定你是根據你用戶的分數作遞增的排序。若是你想返回用戶及用戶的分數,你須要這樣執行: ZRANGE user_scores 0 10 WITHSCORES Agora Games 就
是一個很好的例子,用 Ruby 實現的,它的排行榜就是使用 Redis 來存儲數據的,你能夠在這裏看到。
五、發佈/訂閱
最後(但確定不是最不重要的)是 Redis 的發佈/訂閱功能。發佈/訂閱的使用場景確實很是多。我已看見人們在社交網絡鏈接中使用,還可做爲基於發佈/訂閱的腳本觸發器,甚至用 Redis 的發佈/訂閱功能來創建聊天系統!
3七、假如 Redis 裏面有 1 億個 key,其中有 10w 個 key 是以某個固定的已知的前綴開頭的,若是將它們所有找出來?答:使用 keys 指令能夠掃出指定模式的 key 列表。
對方接着追問:若是這個 redis 正在給線上的業務提供服務,那使用 keys 指令會有什麼問題?
這個時候你要回答 redis 關鍵的一個特性:redis 的單線程的。keys 指令會致使線程阻塞一段時間,線上服務會停頓,直到指令執行完畢,服務才能恢復。這個時候能夠使用 scan 指令,scan 指令能夠無阻塞的提取出指定模式的 key 列表,可是會有必定的重複機率,在客戶端作一次去重就能夠了,可是總體所花費的時間會比直接用 keys 指令長。
3八、若是有大量的 key 須要設置同一時間過時,通常須要注意什麼?
答:若是大量的 key 過時時間設置的過於集中,到過時的那個時間點,redis 可能會出現短暫的卡頓現象。通常須要在時間上加一個隨機值,使得過時時間分散一些。
3九、使用過 Redis 作異步隊列麼,你是怎麼用的?
答:通常使用 list 結構做爲隊列,rpush 生產消息,lpop 消費消息。當 lpop 沒有消息的時候,要適當 sleep 一會再重試。
若是對方追問可不能夠不用 sleep 呢?
list 還有個指令叫 blpop,在沒有消息的時候,它會阻塞住直到消息到來。若是對方追問能不能生產一次消費屢次呢?使用 pub/sub 主題訂閱者模式,能夠實現
1:N 的消息隊列。
若是對方追問 pub/sub 有什麼缺點?
在消費者下線的狀況下,生產的消息會丟失,得使用專業的消息隊列如 RabbitMQ 等。
若是對方追問 redis 如何實現延時隊列?
我估計如今你很想把面試官一棒打死若是你手上有一根棒球棍的話,怎麼問的這麼詳細。可是你很剋制,而後神態自若的回答道:使用 sortedset,拿時間戳做爲 score,消息內容做爲 key 調用 zadd 來生產消息,消費者用 zrangebyscore 指令獲取 N 秒以前的數據輪詢進行處理。到這裏,面試官暗地裏已經對你豎起了大拇指。可是他不知道的是此刻你卻豎起了中指,在椅子背後。
40、使用過 Redis 分佈式鎖麼,它是什麼回事?
先拿 setnx 來爭搶鎖,搶到以後,再用 expire 給鎖加一個過時時間防止鎖忘記了釋放。
這時候對方會告訴你說你回答得不錯,而後接着問若是在 setnx 以後執行 expire 以前進程意外 crash 或者要重啓維護了,那會怎麼樣?
這時候你要給予驚訝的反饋:唉,是喔,這個鎖就永遠得不到釋放了。緊接着你須要抓一抓本身得腦殼,故做思考片刻,好像接下來的結果是你主動思考出來的,而後回答:我記得 set 指令有很是複雜的參數,這個應該是能夠同時把 setnx 和 expire 合成一條指令來用的!對方這時會顯露笑容,內心開始默唸:摁,這小子還不錯。
MySQL 面試題
一、MySQL 中有哪幾種鎖?
一、 表級鎖:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖衝突的機率最高,併發度最低。
二、 行級鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的機率最低,併發度也最高。
三、 頁面鎖:開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,併發度通常。
二、MySQL 中有哪些不一樣的表格?
共有 5 種類型的表格:
一、 MyISAM
二、 Heap
三、 Merge
四、 INNODB
五、 ISAM
三、簡述在 MySQL 數據庫中 MyISAM 和 InnoDB 的區別
MyISAM:
不支持事務,可是每次查詢都是原子的;
支持表級鎖,即每次操做是對整個表加鎖;
存儲表的總行數;
一個 MYISAM 表有三個文件:索引文件、表結構文件、數據文件;
採用菲彙集索引,索引文件的數據域存儲指向數據文件的指針。輔索引與主索引基本一致,可是輔索引不用保證惟一性。
InnoDb:
支持 ACID 的事務,支持事務的四種隔離級別;
支持行級鎖及外鍵約束:所以能夠支持寫併發;
不存儲總行數:
一個 InnoDb 引擎存儲在一個文件空間(共享表空間,表大小不受操做系統控制,一個表可能分佈在多個文件裏),也有可能爲多個(設置爲獨立表空,表大小受操做系統文件大小限制,通常爲 2G),受操做系統文件大小的限制;
主鍵索引採用彙集索引(索引的數據域存儲數據文件自己),輔索引的數據域存儲主鍵的值;所以從輔索引查找數據,須要先經過輔索引找到主鍵值,再訪問輔索引;最好使用自增主鍵,防止插入數據時,爲維持 B+樹結構,文件的大調整。
四、MySQL 中 InnoDB 支持的四種事務隔離級別名稱,以及逐級之間的區別?
SQL 標準定義的四個隔離級別爲:
一、 read uncommited :讀到未提交數據
二、 read committed:髒讀,不可重複讀
三、 repeatable read:可重讀
四、 serializable :串行事物
五、CHAR 和 VARCHAR 的區別?
一、 CHAR 和 VARCHAR 類型在存儲和檢索方面有所不一樣
二、 CHAR 列長度固定爲建立表時聲明的長度,長度值範圍是 1 到 255 當 CHAR 值被存儲時,它們被用空格填充到特定長度,檢索 CHAR 值時需刪除尾隨空格。
六、主鍵和候選鍵有什麼區別?
表格的每一行都由主鍵惟一標識,一個表只有一個主鍵。
主鍵也是候選鍵。按照慣例,候選鍵能夠被指定爲主鍵,而且能夠用於任何外鍵引用。
七、myisamchk 是用來作什麼的?
它用來壓縮 MyISAM 表,這減小了磁盤或內存使用。
MyISAM Static 和 MyISAM Dynamic 有什麼區別?
在 MyISAM Static 上的全部字段有固定寬度。動態 MyISAM 表將具備像 TEXT,
BLOB 等字段,以適應不一樣長度的數據類型。
MyISAM Static 在受損狀況下更容易恢復。
八、若是一個表有一列定義爲 TIMESTAMP,將發生什麼?
每當行被更改時,時間戳字段將獲取當前時間戳。
列設置爲 AUTO INCREMENT 時,若是在表中達到最大值,會發生什麼狀況?
它會中止遞增,任何進一步的插入都將產生錯誤,由於密鑰已被使用。
怎樣才能找出最後一次插入時分配了哪一個自動增量?
LAST_INSERT_ID 將返回由 Auto_increment 分配的最後一個值,而且不須要指定表名稱。
九、你怎麼看到爲表格定義的全部索引?
索引是經過如下方式爲表格定義的:
SHOW INDEX FROM
十、LIKE 聲明中的%和_是什麼意思?
%對應於 0 個或更多字符,_只是 LIKE 語句中的一個字符。如何在 Unix 和 MySQL 時間戳之間進行轉換?
UNIX_TIMESTAMP 是從 MySQL 時間戳轉換爲 Unix 時間戳的命令
FROM_UNIXTIME 是從 Unix 時間戳轉換爲 MySQL 時間戳的命令
十一、列對比運算符是什麼?
在 SELECT 語句的列比較中使用=,<>,<=,<,> =,>,<<,>>,<=>,AND, OR 或 LIKE 運算符。
十二、BLOB 和 TEXT 有什麼區別?
BLOB 是一個二進制對象,能夠容納可變數量的數據。TEXT 是一個不區分大小寫的 BLOB。
BLOB 和 TEXT 類型之間的惟一區別在於對 BLOB 值進行排序和比較時區分大小寫,對 TEXT 值不區分大小寫。
1三、MySQL_fetch_array 和 MySQL_fetch_object 的區別是
什麼?
如下是 MySQL_fetch_array 和 MySQL_fetch_object 的區別: MySQL_fetch_array() – 將結果行做爲關聯數組或來自數據庫的常規數組返回。
MySQL_fetch_object – 從數據庫返回結果行做爲對象。
1四、MyISAM 表格將在哪裏存儲,而且還提供其存儲格式?
每一個 MyISAM 表格以三種格式存儲在磁盤上:
·「.frm」文件存儲表定義 ·數據文件具備「.MYD」(MYData)擴展名
索引文件具備「.MYI」(MYIndex)擴展名
1五、MySQL 如何優化 DISTINCT?
DISTINCT 在全部列上轉換爲 GROUP BY,並與 ORDER BY 子句結合使用。
SELECT DISTINCT t1.a FROM t1,t2 where t1.a=t2.a;
1六、如何顯示前 50 行?
在 MySQL 中,使用如下代碼查詢顯示前 50 行:
SELECT
FROM
LIMIT 0,50;
1七、能夠使用多少列建立索引?
任何標準表最多能夠建立 16 個索引列。
1八、NOW()和 CURRENT_DATE()有什麼區別?
NOW()命令用於顯示當前年份,月份,日期,小時,分鐘和秒。
CURRENT_DATE()僅顯示當前年份,月份和日期。
1九、什麼是非標準字符串類型?
一、 TINYTEXT
二、 TEXT
三、 MEDIUMTEXT
四、 LONGTEXT
20、什麼是通用 SQL 函數?
一、 CONCAT(A, B) – 鏈接兩個字符串值以建立單個字符串輸出。一般用於將兩個或多個字段合併爲一個字段。
二、 FORMAT(X, D)- 格式化數字 X 到 D 有效數字。
三、 CURRDATE(), CURRTIME()- 返回當前日期或時間。
四、 NOW() – 將當前日期和時間做爲一個值返回。
五、 MONTH(),DAY(),YEAR(),WEEK(),WEEKDAY() – 從日期值中提取給定數據。
六、 HOUR(),MINUTE(),SECOND() – 從時間值中提取給定數據。
七、 DATEDIFF(A,B) – 肯定兩個日期之間的差別,一般用於計算年齡
八、 SUBTIMES(A,B) – 肯定兩次之間的差別。
九、 FROMDAYS(INT) – 將整數天數轉換爲日期值。
2一、MySQL 支持事務嗎?
在缺省模式下,MySQL 是 autocommit 模式的,全部的數據庫更新操做都會即時提交,因此在缺省狀況下,MySQL 是不支持事務的。
可是若是你的 MySQL 表類型是使用 InnoDB Tables 或 BDB tables 的話,你的
MySQL 就能夠使用事務處理,使用 SET
AUTOCOMMIT=0 就能夠使 MySQL 容許在非 autocommit 模式,在非
autocommit 模式下,你必須使用 COMMIT 來提交你的更改,或者用 ROLLBACK 來回滾你的更改。
2二、MySQL 裏記錄貨幣用什麼字段類型好
NUMERIC 和 DECIMAL 類型被 MySQL 實現爲一樣的類型,這在 SQL92 標準容許。他們被用於保存值,該值的準確精度是極其重要的值,例如與金錢有關的數據。當聲明一個類是這些類型之一時,精度和規模的能被(而且一般是)指定。
例如:
salary DECIMAL(9,2)
在這個例子中,9(precision)表明將被用於存儲值的總的小數位數,而 2(scale)表明將被用於存儲小數點後的位數。
所以,在這種狀況下,能被存儲在 salary 列中的值的範圍是從-9999999.99 到
9999999.99。
2三、MySQL 有關權限的表都有哪幾個?
MySQL 服務器經過權限表來控制用戶對數據庫的訪問,權限表存放在 MySQL 數
據庫裏,由 MySQL_install_db 腳本初始化。這些權限表分別 user,db,table_priv, columns_priv 和 host。
2四、列的字符串類型能夠是什麼?
字符串類型是:
一、 SET
二、 BLOB
三、 ENUM
四、 CHAR
五、 TEXT
2五、MySQL 數據庫做發佈系統的存儲,一天五萬條以上的增量,預計運維三年,怎麼優化?
一、 設計良好的數據庫結構,容許部分數據冗餘,儘可能避免 join 查詢,提升效率。
二、 選擇合適的表字段數據類型和存儲引擎,適當的添加索引。
三、 MySQL 庫主從讀寫分離。
四、 找規律分表,減小單表中的數據量提升查詢速度。
五、 添加緩存機制,好比 memcached,apc 等。
六、 不常常改動的頁面,生成靜態頁面。
七、 書寫高效率的 SQL。好比 SELECT * FROM TABEL 改成 SELECT field_1, field_2, field_3 FROM TABLE.
2六、鎖的優化策略
一、 讀寫分離
二、 分段加鎖
三、 減小鎖持有的時間
4.多個線程儘可能以相同的順序去獲取資源
不能將鎖的粒度過於細化,否則可能會出現線程的加鎖和釋放次數過多,反而效率不如一次加一把大鎖。
2七、索引的底層實現原理和優化
B+樹,通過優化的 B+樹
主要是在全部的葉子結點中增長了指向下一個葉子節點的指針,所以 InnoDB 建議爲大部分表使用默認自增的主鍵做爲主索引。
2八、什麼狀況下設置了索引但沒法使用
一、 以「%」開頭的 LIKE 語句,模糊匹配
二、 OR 語句先後沒有同時使用索引
三、 數據類型出現隱式轉化(如 varchar 不加單引號的話可能會自動轉換爲 int 型)
2九、實踐中如何優化 MySQL
最好是按照如下順序優化:
一、 SQL 語句及索引的優化
二、 數據庫表結構的優化
三、 系統配置的優化
四、 硬件的優化
詳細能夠查看 阿里 P8 架構師談:MySQL 慢查詢優化、索引優化、以及表等優化總結
30、優化數據庫的方法
一、 選取最適用的字段屬性,儘量減小定義字段寬度,儘可能把字段設置 NOTNULL,例如’省份’、’性別’最好適用 ENUM
二、 使用鏈接(JOIN)來代替子查詢
三、 適用聯合(UNION)來代替手動建立的臨時表
四、 事務處理
五、 鎖定表、優化事務處理
六、 適用外鍵,優化鎖定表
七、 創建索引
八、 優化查詢語句
3一、簡單描述 MySQL 中,索引,主鍵,惟一索引,聯合索引的區別,對數據庫的性能有什麼影響(從讀寫兩方面)
索引是一種特殊的文件(InnoDB 數據表上的索引是表空間的一個組成部分),它們包含着對數據表裏全部記錄的引用指針。
普通索引(由關鍵字 KEY 或 INDEX 定義的索引)的惟一任務是加快對數據的訪問速度。
普通索引容許被索引的數據列包含重複的值。若是能肯定某個數據列將只包含彼此各不相同的值,在爲這個數據列建立索引的時候就應該用關鍵字 UNIQUE 把它定義爲一個惟一索引。也就是說,惟一索引能夠保證數據記錄的惟一性。
主鍵,是一種特殊的惟一索引,在一張表中只能定義一個主鍵索引,主鍵用於惟一標識一條記錄,使用關鍵字 PRIMARY KEY 來建立。
索引能夠覆蓋多個數據列,如像 INDEX(columnA, columnB)索引,這就是聯合索引。
索引能夠極大的提升數據的查詢速度,可是會下降插入、刪除、更新表的速度,由於在執行這些寫操做時,還要操做索引文件。
3二、數據庫中的事務是什麼?
事務(transaction)是做爲一個單元的一組有序的數據庫操做。若是組中的全部操做都成功,則認爲事務成功,即便只有一個操做失敗,事務也不成功。若是全部操做完成,事務則提交,其修改將做用於全部其餘數據庫進程。若是一個操做失敗,則事務將回滾,該事務全部操做的影響都將取消。
事務特性:
一、 原子性:即不可分割性,事務要麼所有被執行,要麼就所有不被執行。
二、 一致性或可串性。事務的執行使得數據庫從一種正確狀態轉換成另外一種正確狀態
三、 隔離性。在事務正確提交以前,不容許把該事務對數據的任何改變提供給任何其餘事務,
四、 持久性。事務正確提交後,其結果將永久保存在數據庫中,即便在事務提交後有了其餘故障,事務的處理結果也會獲得保存。
或者這樣理解:
事務就是被綁定在一塊兒做爲一個邏輯工做單元的 SQL 語句分組,若是任何一個語句操做失敗那麼整個操做就被失敗,之後操做就會回滾到操做前狀態,或者是上有個節點。爲了確保要麼執行,要麼不執行,就能夠使用事務。要將有組語句做爲事務考慮,就須要經過 ACID 測試,即原子性,一致性,隔離性和持久性。
3三、SQL 注入漏洞產生的緣由?如何防止?
SQL 注入產生的緣由:程序開發過程當中不注意規範書寫 sql 語句和對特殊字符進行過濾,致使客戶端能夠經過全局變量 POST 和 GET 提交一些 sql 語句正常執行。
防止 SQL 注入的方式:
開啓配置文件中的 magic_quotes_gpc 和 magic_quotes_runtime 設置
執行 sql 語句時使用 addslashes 進行 sql 語句轉換
Sql 語句書寫儘可能不要省略雙引號和單引號。
過濾掉 sql 語句中的一些關鍵詞:update、insert、delete、select、 * 。
提升數據庫表和字段的命名技巧,對一些重要的字段根據程序的特色命名,取不易被猜到的。
3四、爲表中得字段選擇合適得數據類型
字段類型優先級: 整形>date,time>enum,char>varchar>blob,text
優先考慮數字類型,其次是日期或者二進制類型,最後是字符串類型,同級別得數據類型,應該優先選擇佔用空間小的數據類型
3五、存儲時期
Datatime:以 YYYY-MM-DD HH:MM:SS 格式存儲時期時間,精確到秒,佔用 8 個字節得存儲空間,datatime 類型與時區無關
Timestamp:以時間戳格式存儲,佔用 4 個字節,範圍小 1970-1-1 到 2038-1-19,顯示依賴於所指定得時區,默認在第一個列行的數據修改時能夠自動得修改 timestamp 列得值
Date:(生日)佔用得字節數比使用字符串.datatime.int 儲存要少,使用 date 只須要 3 個字節,存儲日期月份,還能夠利用日期時間函數進行日期間得計算
Time:存儲時間部分得數據
注意:不要使用字符串類型來存儲日期時間數據(一般比字符串佔用得儲存空間小,在進行查找過濾能夠利用日期得函數)
使用 int 存儲日期時間不如使用 timestamp 類型
3六、對於關係型數據庫而言,索引是至關重要的概念,請回答有關索引的幾個問題:
一、 索引的目的是什麼?
快速訪問數據表中的特定信息,提升檢索速度
建立惟一性索引,保證數據庫表中每一行數據的惟一性。
加速表和表之間的鏈接
使用分組和排序子句進行數據檢索時,能夠顯著減小查詢中分組和排序的時間
二、 索引對數據庫系統的負面影響是什麼?
負面影響:
建立索引和維護索引須要耗費時間,這個時間隨着數據量的增長而增長;索引須要佔用物理空間,不光是表須要佔用數據空間,每一個索引也須要佔用物理空間;當對錶進行增、刪、改、的時候索引也要動態維護,這樣就下降了數據的維護速度。
三、 爲數據表創建索引的原則有哪些?
在最頻繁使用的、用以縮小查詢範圍的字段上創建索引。
在頻繁使用的、須要排序的字段上創建索引
四、 什麼狀況下不宜創建索引?對於查詢中不多涉及的列或者重複值比較多的列,不宜創建索引。
對於一些特殊的數據類型,不宜創建索引,好比文本字段(text)等
3七、解釋 MySQL 外鏈接、內鏈接與自鏈接的區別
先說什麼是交叉鏈接: 交叉鏈接又叫笛卡爾積,它是指不使用任何條件,直接將一個表的全部記錄和另外一個表中的全部記錄一一匹配。
內鏈接 則是隻有條件的交叉鏈接,根據某個條件篩選出符合條件的記錄,不符合條件的記錄不會出如今結果集中,即內鏈接只鏈接匹配的行。
外鏈接 其結果集中不只包含符合鏈接條件的行,並且還會包括左表、右表或兩個表中
的全部數據行,這三種狀況依次稱之爲左外鏈接,右外鏈接,和全外鏈接。
左外鏈接,也稱左鏈接,左表爲主表,左表中的全部記錄都會出如今結果集中,對於那些在右表中並無匹配的記錄,仍然要顯示,右邊對應的那些字段值以
NULL 來填充。右外鏈接,也稱右鏈接,右表爲主表,右表中的全部記錄都會出如今結果集中。左鏈接和右鏈接能夠互換,MySQL 目前還不支持全外鏈接。
3八、Myql 中的事務回滾機制概述
事務是用戶定義的一個數據庫操做序列,這些操做要麼全作要麼全不作,是一個不可分割的工做單位,事務回滾是指將該事務已經完成的對數據庫的更新操做撤銷。
要同時修改數據庫中兩個不一樣表時,若是它們不是一個事務的話,當第一個表修改完,可能第二個表修改過程當中出現了異常而沒能修改,此時就只有第二個表依舊是未修改以前的狀態,而第一個表已經被修改完畢。而當你把它們設定爲一個事務的時候,當第一個表修改完,第二表修改出現異常而沒能修改,第一個表和第二個表都要回到未修改的狀態,這就是所謂的事務回滾
3九、SQL 語言包括哪幾部分?每部分都有哪些操做關鍵字?
SQL 語言包括數據定義(DDL)、數據操縱(DML),數據控制(DCL)和數據查詢(DQL)四個部分。
數據定義:Create Table,Alter Table,Drop Table, Craete/Drop Index 等
數據操縱:Select ,insert,update,delete,
數據控制:grant,revoke
數據查詢:select
40、完整性約束包括哪些?
數據完整性(Data Integrity)是指數據的精確(Accuracy)和可靠性(Reliability)。
分爲如下四類:
一、 實體完整性:規定表的每一行在表中是唯一的實體。
二、 域完整性:是指表中的列必須知足某種特定的數據類型約束,其中約束又包括取值範圍、精度等規定。
三、 參照完整性:是指兩個表的主關鍵字和外關鍵字的數據應一致,保證了表之間的數據的一致性,防止了數據丟失或無心義的數據在數據庫中擴散。 四、用戶定義的完整性:不一樣的關係數據庫系統根據其應用環境的不一樣,每每還須要一些特殊的約束條件。用戶定義的完整性便是針對某個特定關係數據庫的約束條件,它反映某一具體應用必須知足的語義要求。
與表有關的約束:包括列約束(NOT NULL(非空約束))和表約束(PRIMARY KEY、 foreign key、check、UNIQUE) 。
4一、什麼是鎖?
答:數據庫是一個多用戶使用的共享資源。當多個用戶併發地存取數據時,在數據庫中就會產生多個事務同時存取同一數據的狀況。若對併發操做不加控制就可能會讀取和存儲不正確的數據,破壞數據庫的一致性。
加鎖是實現數據庫併發控制的一個很是重要的技術。當事務在對某個數據對象進行操做前,先向系統發出請求,對其加鎖。加鎖後事務就對該數據對象有了必定的控制,在該事務釋放鎖以前,其餘的事務不能對此數據對象進行更新操做。
基本鎖類型:鎖包括行級鎖和表級鎖
4二、什麼叫視圖?遊標是什麼?
答:視圖是一種虛擬的表,具備和物理表相同的功能。能夠對視圖進行增,改,查,操做,視圖一般是有一個表或者多個表的行或列的子集。對視圖的修改不影響基本表。它使得咱們獲取數據更容易,相比多表查詢。
遊標:是對查詢出來的結果集做爲一個單元來有效的處理。遊標能夠定在該單元中的特定行,從結果集的當前行檢索一行或多行。能夠對結果集當前行作修改。
通常不使用遊標,可是須要逐條處理數據的時候,遊標顯得十分重要。
4三、什麼是存儲過程?用什麼來調用?
答:存儲過程是一個預編譯的 SQL 語句,優勢是容許模塊化的設計,就是說只需建立一次,之後在該程序中就能夠調用屢次。若是某次操做須要執行屢次 SQL,使用存儲過程比單純 SQL 語句執行要快。能夠用一個命令對象來調用存儲過程。
4四、如何通俗地理解三個範式?
答:第一範式:1NF 是對屬性的原子性約束,要求屬性具備原子性,不可再分解;
第二範式:2NF 是對記錄的唯一性約束,要求記錄有唯一標識,即實體的唯一性;
第三範式:3NF 是對字段冗餘性的約束,即任何字段不能由其餘字段派生出來,它要求字段沒有冗餘。。
範式化設計優缺點:
優勢:
能夠儘可能得減小數據冗餘,使得更新快,體積小
缺點:對於查詢須要多個表進行關聯,減小寫得效率增長讀得效率,更難進行索引優化
反範式化:
優勢:能夠減小表得關聯,能夠更好得進行索引優化缺點:數據冗餘以及數據異常,數據得修改須要更多的成本
4五、什麼是基本表?什麼是視圖?
答:基本表是自己獨立存在的表,在 SQL 中一個關係就對應一個表。 視圖是從一個或幾個基本表導出的表。視圖自己不獨立存儲在數據庫中,是一個虛表
4六、試述視圖的優勢?
答:(1) 視圖可以簡化用戶的操做 (2) 視圖使用戶能以多種角度看待同一數據; (3) 視圖爲數據庫提供了必定程度的邏輯獨立性; (4) 視圖可以對機密數據提供安全保護。
4七、 NULL 是什麼意思
答:NULL 這個值表示 UNKNOWN(未知):它不表示「」(空字符串)。對 NULL 這個值的任何比較都會生產一個 NULL 值。您不能把任何值與一個 NULL 值進行比較,並在邏輯上但願得到一個答案。
使用 IS NULL 來進行 NULL 判斷
4八、主鍵、外鍵和索引的區別?
主鍵、外鍵和索引的區別
定義:
主鍵–惟一標識一條記錄,不能有重複的,不容許爲空
外鍵–表的外鍵是另外一表的主鍵, 外鍵能夠有重複的, 能夠是空值
索引–該字段沒有重複值,但能夠有一個空值
做用:
主鍵–用來保證數據完整性
外鍵–用來和其餘表創建聯繫用的
索引–是提升查詢排序的速度
個數:
主鍵–主鍵只能有一個
外鍵–一個表能夠有多個外鍵
索引–一個表能夠有多個惟一索引
4九、你能夠用什麼來確保表格裏的字段只接受特定範圍裏的值?
答:Check 限制,它在數據庫表格裏被定義,用來限制輸入該列的值。
觸發器也能夠被用來限制數據庫表格裏的字段可以接受的值,可是這種辦法要求觸發器在表格裏被定義,這可能會在某些狀況下影響到性能。
50、說說對 SQL 語句優化有哪些方法?(選擇幾條)
一、 Where 子句中:where 表之間的鏈接必須寫在其餘 Where 條件以前,那些能夠過濾掉最大數量記錄的條件必須寫在 Where 子句的末尾.HAVING 最後。
二、 用 EXISTS 替代 IN、用 NOT EXISTS 替代 NOT IN。
三、 避免在索引列上使用計算
四、 避免在索引列上使用 IS NULL 和 IS NOT NULL
五、 對查詢進行優化,應儘可能避免全表掃描,首先應考慮在 where 及 order by 涉及的列上創建索引。
六、 應儘可能避免在 where 子句中對字段進行 null 值判斷,不然將致使引擎放棄使用索引而進行全表掃描
七、 應儘可能避免在 where 子句中對字段進行表達式操做,這將致使引擎放棄使用索引而進行全表掃描
Java 併發編程(一)
一、在 java 中守護線程和本地線程區別? java 中的線程分爲兩種:守護線程(Daemon)和用戶線程(User)。任何線程均可以設置爲守護線程和用戶線程,經過方法 Thread.setDaemon(bool on);true 則把該線程設置爲守護線程,反之則爲用戶線程。Thread.setDaemon() 必須在 Thread.start()以前調用,不然運行時會拋出異常。
二者的區別:
惟一的區別是判斷虛擬機(JVM)什麼時候離開,Daemon 是爲其餘線程提供服務,若是所有的 User Thread 已經撤離,Daemon 沒有可服務的線程,JVM 撤離。也能夠理解爲守護線程是 JVM 自動建立的線程(但不必定),用戶線程是程序建立的線程;好比 JVM 的垃圾回收線程是一個守護線程,當全部線程已經撤離,再也不產生垃圾,守護線程天然就沒事可幹了,當垃圾回收線程是 Java 虛擬機上僅剩的線程時,Java 虛擬機會自動離開。
擴展:Thread Dump 打印出來的線程信息,含有 daemon 字樣的線程即爲守護進程,可能會有:服務守護進程、編譯守護進程、windows 下的監聽 Ctrl+break 的守護進程、Finalizer 守護進程、引用處理守護進程、GC 守護進程。
二、線程與進程的區別?
進程是操做系統分配資源的最小單元,線程是操做系統調度的最小單元。
一個程序至少有一個進程,一個進程至少有一個線程。
三、什麼是多線程中的上下文切換?
多線程會共同使用一組計算機上的 CPU,而線程數大於給程序分配的 CPU 數量時,爲了讓各個線程都有執行的機會,就須要輪轉使用 CPU。不一樣的線程切換使用 CPU 發生的切換數據等就是上下文切換。
四、死鎖與活鎖的區別,死鎖與飢餓的區別?
死鎖:是指兩個或兩個以上的進程(或線程)在執行過程當中,因爭奪資源而形成的一種互相等待的現象,若無外力做用,它們都將沒法推動下去。
產生死鎖的必要條件:
一、 互斥條件:所謂互斥就是進程在某一時間內獨佔資源。
二、 請求與保持條件:一個進程因請求資源而阻塞時,對已得到的資源保持不放。
三、 不剝奪條件:進程已得到資源,在末使用完以前,不能強行剝奪。
四、 循環等待條件:若干進程之間造成一種頭尾相接的循環等待資源關係。
活鎖:任務或者執行者沒有被阻塞,因爲某些條件沒有知足,致使一直重複嘗試,失敗,嘗試,失敗。
活鎖和死鎖的區別在於,處於活鎖的實體是在不斷的改變狀態,所謂的「活」, 而處於死鎖的實體表現爲等待;活鎖有可能自行解開,死鎖則不能。
飢餓:一個或者多個線程由於種種緣由沒法得到所須要的資源,致使一直沒法執行的狀態。
Java 中致使飢餓的緣由:
一、 高優先級線程吞噬全部的低優先級線程的 CPU 時間。
二、 線程被永久堵塞在一個等待進入同步塊的狀態,由於其餘線程老是能在它以前持續地對該同步塊進行訪問。
三、 線程在等待一個自己也處於永久等待完成的對象(好比調用這個對象的 wait 方法),由於其餘線程老是被持續地得到喚醒。
五、Java 中用到的線程調度算法是什麼?
採用時間片輪轉的方式。能夠設置線程的優先級,會映射到下層的系統上面的優先級上,如非特別須要,儘可能不要用,防止線程飢餓。
六、什麼是線程組,爲何在 Java 中不推薦使用?
ThreadGroup 類,能夠把線程歸屬到某一個線程組中,線程組中能夠有線程對象,也能夠有線程組,組中還能夠有線程,這樣的組織結構有點相似於樹的形式。
爲何不推薦使用?由於使用有不少的安全隱患吧,沒有具體追究,若是須要使用,推薦使用線程池。
七、爲何使用 Executor 框架?
每次執行任務建立線程 new Thread()比較消耗性能,建立一個線程是比較耗時、耗資源的。
調用 new Thread()建立的線程缺少管理,被稱爲野線程,並且能夠無限制的建立,線程之間的相互競爭會致使過多佔用系統資源而致使系統癱瘓,還有線程之間的頻繁交替也會消耗不少系統資源。
接使用 new Thread() 啓動的線程不利於擴展,好比定時執行、按期執行、定時按期執行、線程中斷等都不便實現。
八、在 Java 中 Executor 和 Executors 的區別?
Executors 工具類的不一樣方法按照咱們的需求建立了不一樣的線程池,來知足業務的需求。
Executor 接口對象能執行咱們的線程任務。
ExecutorService 接口繼承了 Executor 接口並進行了擴展,提供了更多的方法咱們能得到任務執行的狀態而且能夠獲取任務的返回值。
使用 ThreadPoolExecutor 能夠建立自定義線程池。
Future 表示異步計算的結果,他提供了檢查計算是否完成的方法,以等待計算的完成,並能夠使用 get()方法獲取計算的結果。
九、如何在 Windows 和 Linux 上查找哪一個線程使用的 CPU 時間最長?
參考:
http://daiguahub.com/2016/07/31/使用 jstack 找出消耗 CPU 最多的線程代碼
/
十、什麼是原子操做?在 Java Concurrency API 中有哪些原子類(atomic classes)?
原子操做(atomic operation)意爲」不可被中斷的一個或一系列操做」 。
處理器使用基於對緩存加鎖或總線加鎖的方式來實現多處理器之間的原子操做。
在 Java 中能夠經過鎖和循環 CAS 的方式來實現原子操做。 CAS 操做——
Compare & Set,或是 Compare & Swap,如今幾乎全部的 CPU 指令都支持 CAS 的原子操做。
原子操做是指一個不受其餘操做影響的操做任務單元。原子操做是在多線程環境下避免數據不一致必須的手段。
int++並非一個原子操做,因此當一個線程讀取它的值並加 1 時,另一個線程有可能會讀到以前的值,這就會引起錯誤。
爲了解決這個問題,必須保證增長操做是原子的,在 JDK1.5 以前咱們能夠使用同步技術來作到這一點。到 JDK1.5,java.util.concurrent.atomic 包提供了 int 和 long 類型的原子包裝類,它們能夠自動的保證對於他們的操做是原子的而且不須要使用同步。
java.util.concurrent 這個包裏面提供了一組原子類。其基本的特性就是在多線程環境下,當有多個線程同時執行這些類的實例包含的方法時,具備排他性,即當某個線程進入方法,執行其中的指令時,不會被其餘線程打斷,而別的線程就像自旋鎖同樣,一直等到該方法執行完成,才由 JVM 從等待隊列中選擇一個另外一個線程進入,這只是一種邏輯上的理解。
原子類:AtomicBoolean,AtomicInteger,AtomicLong,AtomicReference 原子數組:AtomicIntegerArray,AtomicLongArray,AtomicReferenceArray 原子屬性更新器:AtomicLongFieldUpdater,AtomicIntegerFieldUpdater,
AtomicReferenceFieldUpdater
解決 ABA 問題的原子類:AtomicMarkableReference(經過引入一個 boolean 來反映中間有沒有變過),AtomicStampedReference(經過引入一個 int 來累加來反映中間有沒有變過)
十一、Java Concurrency API 中的 Lock 接口(Lock interface) 是什麼?對比同步它有什麼優點?
Lock 接口比同步方法和同步塊提供了更具擴展性的鎖操做。
他們容許更靈活的結構,能夠具備徹底不一樣的性質,而且能夠支持多個相關類的條件對象。
它的優點有:
能夠使鎖更公平
能夠使線程在等待鎖的時候響應中斷
可讓線程嘗試獲取鎖,並在沒法獲取鎖的時候當即返回或者等待一段時間能夠在不一樣的範圍,以不一樣的順序獲取和釋放鎖
總體上來講 Lock 是 synchronized 的擴展版,Lock 提供了無條件的、可輪詢的
(tryLock 方法)、定時的(tryLock 帶參方法)、可中斷的(lockInterruptibly)、可多條件隊列的(newCondition 方法)鎖操做。另外 Lock 的實現類基本都支持非公平鎖(默認)和公平鎖,synchronized 只支持非公平鎖,固然,在大部分狀況下,非公平鎖是高效的選擇。
十二、什麼是 Executors 框架?
Executor 框架是一個根據一組執行策略調用,調度,執行和控制的異步任務的框架。
無限制的建立線程會引發應用程序內存溢出。因此建立一個線程池是個更好的的
解決方案,由於能夠限制線程的數量而且能夠回收再利用這些線程。利用
Executors 框架能夠很是方便的建立一個線程池。
1三、什麼是阻塞隊列?阻塞隊列的實現原理是什麼?如何使用阻塞隊列來實現生產者-消費者模型?
阻塞隊列(BlockingQueue)是一個支持兩個附加操做的隊列。
這兩個附加的操做是:在隊列爲空時,獲取元素的線程會等待隊列變爲非空。當隊列滿時,存儲元素的線程會等待隊列可用。
阻塞隊列經常使用於生產者和消費者的場景,生產者是往隊列裏添加元素的線程,消費者是從隊列裏拿元素的線程。阻塞隊列就是生產者存放元素的容器,而消費者也只從容器裏拿元素。
JDK7 提供了 7 個阻塞隊列。分別是:
ArrayBlockingQueue :一個由數組結構組成的有界阻塞隊列。
LinkedBlockingQueue :一個由鏈表結構組成的有界阻塞隊列。 PriorityBlockingQueue :一個支持優先級排序的無界阻塞隊列。
DelayQueue:一個使用優先級隊列實現的無界阻塞隊列。
SynchronousQueue:一個不存儲元素的阻塞隊列。
LinkedTransferQueue:一個由鏈表結構組成的無界阻塞隊列。 LinkedBlockingDeque:一個由鏈表結構組成的雙向阻塞隊列。
Java 5 以前實現同步存取時,能夠使用普通的一個集合,而後在使用線程的協做
和線程同步能夠實現生產者,消費者模式,主要的技術就是用好,
wait ,notify,notifyAll,sychronized 這些關鍵字。而在 java 5 以後,能夠使用阻塞隊列來實現,此方式大大簡少了代碼量,使得多線程編程更加容易,安全方面也有保障。
BlockingQueue 接口是 Queue 的子接口,它的主要用途並非做爲容器,而是做爲線程同步的的工具,所以他具備一個很明顯的特性,當生產者線程試圖向
BlockingQueue 放入元素時,若是隊列已滿,則線程被阻塞,當消費者線程試圖從中取出一個元素時,若是隊列爲空,則該線程會被阻塞,正是由於它所具備這個特性,因此在程序中多個線程交替向 BlockingQueue 中放入元素,取出元素,它能夠很好的控制線程之間的通訊。
阻塞隊列使用最經典的場景就是 socket 客戶端數據的讀取和解析,讀取數據的線程不斷將數據放入隊列,而後解析線程不斷從隊列取數據解析。
1四、 什麼是 Callable 和 Future?
Callable 接口相似於 Runnable,從名字就能夠看出來了,可是 Runnable 不會返回結果,而且沒法拋出返回結果的異常,而 Callable 功能更強大一些,被線程執行後,能夠返回值,這個返回值能夠被 Future 拿到,也就是說,Future 能夠拿到異步執行任務的返回值。
能夠認爲是帶有回調的 Runnable。
Future 接口表示異步任務,是尚未完成的任務給出的將來結果。因此說 Callable 用於產生結果,Future 用於獲取結果。
1五、 什麼是 FutureTask?使用 ExecutorService 啓動任務。
在 Java 併發程序中 FutureTask 表示一個能夠取消的異步運算。它有啓動和取消運算、查詢運算是否完成和取回運算結果等方法。只有當運算完成的時候結果才能取回,若是運算還沒有完成 get 方法將會阻塞。一個 FutureTask 對象能夠對調用了 Callable 和 Runnable 的對象進行包裝,因爲 FutureTask 也是調用了 Runnable 接口因此它能夠提交給 Executor 來執行。
1六、什麼是併發容器的實現?
何爲同步容器:能夠簡單地理解爲經過 synchronized 來實現同步的容器,若是有多個線程調用同步容器的方法,它們將會串行執行。好比 Vector,Hashtable,以及 Collections.synchronizedSet,synchronizedList 等方法返回的容器。
能夠經過查看 Vector,Hashtable 等這些同步容器的實現代碼,能夠看到這些容器實現線程安全的方式就是將它們的狀態封裝起來,並在須要同步的方法上加上關鍵字 synchronized。
併發容器使用了與同步容器徹底不一樣的加鎖策略來提供更高的併發性和伸縮性,例如在 ConcurrentHashMap 中採用了一種粒度更細的加鎖機制,能夠稱爲分段鎖,在這種鎖機制下,容許任意數量的讀線程併發地訪問 map,而且執行讀操做的線程和寫操做的線程也能夠併發的訪問 map,同時容許必定數量的寫操做線程併發地修改 map,因此它能夠在併發環境下實現更高的吞吐量。
1七、多線程同步和互斥有幾種實現方法,都是什麼?
線程同步是指線程之間所具備的一種制約關係,一個線程的執行依賴另外一個線程的消息,當它沒有獲得另外一個線程的消息時應等待,直到消息到達時才被喚醒。線程互斥是指對於共享的進程系統資源,在各單個線程訪問時的排它性。當有若干個線程都要使用某一共享資源時,任什麼時候刻最多隻容許一個線程去使用,其它要使用該資源的線程必須等待,直到佔用資源者釋放該資源。線程互斥能夠當作是一種特殊的線程同步。
線程間的同步方法大致可分爲兩類:用戶模式和內核模式。顧名思義,內核模式就是指利用系統內核對象的單一性來進行同步,使用時須要切換內核態與用戶態,而用戶模式就是不須要切換到內核態,只在用戶態完成操做。
用戶模式下的方法有:原子操做(例如一個單一的全局變量),臨界區。內核模式下的方法有:事件,信號量,互斥量。
1八、什麼是競爭條件?你怎樣發現和解決競爭?
當多個進程都企圖對共享數據進行某種處理,而最後的結果又取決於進程運行的順序時,則咱們認爲這發生了競爭條件(race condition)。
1九、你將如何使用 thread dump?你將如何分析 Thread dump?
新建狀態(New)
用 new 語句建立的線程處於新建狀態,此時它和其餘 Java 對象同樣,僅僅在堆區中被分配了內存。
就緒狀態(Runnable)
當一個線程對象建立後,其餘線程調用它的 start()方法,該線程就進入就緒狀態,
Java 虛擬機會爲它建立方法調用棧和程序計數器。處於這個狀態的線程位於可運行池中,等待得到 CPU 的使用權。
運行狀態(Running)
處於這個狀態的線程佔用 CPU,執行程序代碼。只有處於就緒狀態的線程纔有機會轉到運行狀態。
阻塞狀態(Blocked)
阻塞狀態是指線程由於某些緣由放棄 CPU,暫時中止運行。當線程處於阻塞狀態時,Java 虛擬機不會給線程分配 CPU。直到線程從新進入就緒狀態,它纔有機會轉到運行狀態。
阻塞狀態可分爲如下 3 種:
位於對象等待池中的阻塞狀態(Blocked in object’s wait pool):
當線程處於運行狀態時,若是執行了某個對象的 wait()方法,Java 虛擬機就會把線程放到這個對象的等待池中,這涉及到「線程通訊」的內容。
位於對象鎖池中的阻塞狀態(Blocked in object’s lock pool):
當線程處於運行狀態時,試圖得到某個對象的同步鎖時,若是該對象的同步鎖已經被其餘線程佔用,Java 虛擬機就會把這個線程放到這個對象的鎖池中,這涉及到「線程同步」的內容。
其餘阻塞狀態(Otherwise Blocked):
當前線程執行了 sleep()方法,或者調用了其餘線程的 join()方法,或者發出了 I/O 請求時,就會進入這個狀態。
死亡狀態(Dead)
當線程退出 run()方法時,就進入死亡狀態,該線程結束生命週期。
咱們運行以前的那個死鎖代碼 SimpleDeadLock.java,而後嘗試輸出信息(
/ 時間,jvm 信息
/
2017-11-01 17:36:28
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.144-b01 mixed mode):
/ 線程名稱:DestroyJavaVM
編號:#13 優先級:5 系統優先級:0
jvm 內部線程 id:0x0000000001c88800 對應系統線程 id(NativeThread ID):0x1c18
線程狀態: waiting on condition [0x0000000000000000] (等待某個條件線程詳細狀態:java.lang.Thread.State: RUNNABLE 及以後全部
/
"DestroyJavaVM" #13 prio=5 os_prio=0 tid=0x0000000001c88800 nid=0x1c18 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE
"Thread-1" #12 prio=5 os_prio=0 tid=0x0000000018d49000 nid=0x17b8 waiting for monitor entry [0x0000000019d7f000]
/ 線程狀態:阻塞(在對象同步上)代碼位置:at
com.leo.interview.SimpleDeadLock$B.run(SimpleDeadLock.java:56) 等待鎖:0x00000000d629b4d8 已經得到鎖:0x00000000d629b4e8*/
java.lang.Thread.State: BLOCKED (on object monitor)
at
com.leo.interview.SimpleDeadLock$B.run(SimpleDeadLock.java:56)
)
"Monitor Ctrl-Break" #6 daemon prio=5 os_prio=0
tid=0x0000000018bcc800 nid=0x1c24 runnable [0x00000000193ce000] java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method) at
java.net.SocketInputStream.socketRead(SocketInputStream.java:116) at java.net.SocketInputStream.read(SocketInputStream.java:171) at java.net.SocketInputStream.read(SocketInputStream.java:141) at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284) at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326) at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178) - locked <0x00000000d632b928> (a java.io.InputStreamReader) at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:161) at java.io.BufferedReader.readLine(BufferedReader.java:324) - locked <0x00000000d632b928> (a java.io.InputStreamReader) at java.io.BufferedReader.readLine(BufferedReader.java:389) at
com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:6 4)
"Attach Listener" #5 daemon prio=5 os_prio=2
tid=0x0000000017781800 nid=0x524 runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE
"Signal Dispatcher" #4 daemon prio=9 os_prio=2
tid=0x000000001778f800 nid=0x1b08 waiting on condition
[0x0000000000000000] java.lang.Thread.State: RUNNABLE
"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x000000001776a800 nid=0xdac in Object.wait() [0x0000000018b6f000] java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
=====
"Thread-1":
at
com.leo.interview.SimpleDeadLock$B.run(SimpleDeadLock.java:56)
}
private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[];
static {
// high value may be configured by property int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int,
ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1]; int j = low;
for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
簡單的說,若是整型字面量的值在-128 到 127 之間,那麼不會 new 新的 Integer 對象,而是直接引用常量池中的 Integer 對象,因此上面的面試題中 f1f4 的結果是 false。
提醒:越是貌似簡單的面試題其中的玄機就越多,須要面試者有至關深厚的功力。
八、&和&&的區別?
答:
&運算符有兩種用法:(1)按位與;(2)邏輯與。&&運算符是短路與運算。邏輯與
跟短路與的差異是很是巨大的,雖然兩者都要求運算符左右兩端的布爾值都是
true 整個表達式的值纔是 true。&&之因此稱爲短路運算是由於,若是&&左邊的表達式的值是 false,右邊的表達式會被直接短路掉,不會進行運算。不少時候咱們可能都須要用&&而不是&,例如在驗證用戶登陸時斷定用戶名不是 null 並且不是空字符串,應當寫爲:username != null &&!username.equals(「」),兩者的順序不能交換,更不能用&運算符,由於第一個條件若是不成立,根本不能進行字符串的 equals 比較,不然會產生 NullPointerException 異常。注意:邏輯或運算符(|)和短路或運算符(||)的差異也是如此。
補充:若是你熟悉 JavaScript,那你可能更能感覺到短路運算的強大,想成爲
JavaScript 的高手就先從玩轉短路運算開始吧。
九、解釋內存中的棧(stack)、堆(heap)和方法區(method area) 的用法。
答:
一般咱們定義一個基本數據類型的變量,一個對象的引用,還有就是函數調用的現場保存都使用 JVM 中的棧空間;而經過 new 關鍵字和構造器建立的對象則放在堆空間,堆是垃圾收集器管理的主要區域,因爲如今的垃圾收集器都採用分代收集算法,因此堆空間還能夠細分爲新生代和老生代,再具體一點能夠分爲 Eden、 Survivor(又可分爲 From Survivor 和 To Survivor)、Tenured;方法區和堆都是各個線程共享的內存區域,用於存儲已經被 JVM 加載的類信息、常量、靜態變量、JIT 編譯器編譯後的代碼等數據;程序中的字面量(literal)如直接書寫的 100、」 hello」和常量都是放在常量池中,常量池是方法區的一部分,。棧空間操做起來最快可是棧很小,一般大量的對象都是放在堆空間,棧和堆的大小均可以經過 JVM 的啓動參數來進行調整,棧空間用光了會引起 StackOverflowError,而堆和常量池空間不足則會引起 OutOfMemoryError。
String str = new String("hello");
上面的語句中變量 str 放在棧上,用 new 建立出來的字符串對象放在堆上,而」 hello」這個字面量是放在方法區的。
補充 1:較新版本的 Java(從 Java 6 的某個更新開始)中,因爲 JIT 編譯器的發展和」逃逸分析」技術的逐漸成熟,棧上分配、標量替換等優化技術使得對象必定分配在堆上這件事情已經變得不那麼絕對了。
補充 2:運行時常量池至關於 Class 文件常量池具備動態性,Java 語言並不要求常量必定只有編譯期間才能產生,運行期間也能夠將新的常量放入池中,String 類的 intern()方法就是這樣的。
看看下面代碼的執行結果是什麼而且比較一下 Java 7 之前和之後的運行結果是否一致。
String s1 = new StringBuilder("go")
.append("od").toString();
System.out.println(s1.intern() == s1);
String s2 = new StringBuilder("ja")
.append("va").toString();
System.out.println(s2.intern() == s2);
十、Math.round(11.5) 等於多少?Math.round(-11.5)等於多少?
答:
Math.round(11.5)的返回值是 12,Math.round(-11.5)的返回值是-11。四捨五入的原理是在參數上加 0.5 而後進行下取整。
十一、switch 是否能做用在 byte 上,是否能做用在 long 上,是否能做用在 String 上?
答:
在 Java 5 之前,switch(expr)中,expr 只能是 byte、short、char、int。從 Java
5 開始,Java 中引入了枚舉類型,expr 也能夠是 enum 類型,從 Java 7 開始, expr 還能夠是字符串(String),可是長整型(long)在目前全部的版本中都是不能夠的。
十二、用最有效率的方法計算 2 乘以 8?
答:
2 << 3(左移 3 位至關於乘以 2 的 3 次方,右移 3 位至關於除以 2 的 3 次方)。
補充:咱們爲編寫的類重寫 hashCode 方法時,可能會看到以下所示的代碼,其實咱們不太理解爲何要使用這樣的乘法運算來產生哈希碼(散列碼),並且爲何這個數是個素數,爲何一般選擇 31 這個數?前兩個問題的答案你能夠本身百度一下,選擇 31 是由於能夠用移位和減法運算來代替乘法,從而獲得更好的性能。說到這裏你可能已經想到了:31 * num 等價於(num << 5) - num,左移 5 位至關於乘以 2 的 5 次方再減去自身就至關於乘以 31,如今的 VM 都能自動完成這個優化。
public class PhoneNumber { private int areaCode; private String prefix; private String lineNumber;
@Override public int hashCode() { final int prime = 31; int result = 1;
result = prime * result + areaCode; result = prime * result
/ public class Poker { private static String[] suites = {"黑桃", "紅桃", "草花", "方塊"}; private static int[] faces = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}; private Card[] cards;
/*
/ public Poker() { cards = new Card[52];
for(int i = 0; i < suites.length; i++) { for(int j = 0; j < faces.length; j++) { cards[i * 13 + j] = new Card(suites[i], faces[j]);
}
}
}
/*
*/ public void shuffle() { for(int i = 0, len = cards.length; i < len; i++) { int index = (int) (Math.random() * len); Card temp = cards[index]; cards[index] = cards[i]; cards[i] = temp;
}
}
/**
/ public Card deal(int index) { return cards[index];
}
/*
*/ public class Card { private String suite; // 花色 private int face; // 點數
public Card(String suite, int face) { this.suite = suite; this.face = face;
}
@Override
public String toString() { String faceStr = ""; switch(face) {
case 1: faceStr = "A"; break;
case 11: faceStr = "J"; break; case 12: faceStr = "Q"; break; case 13: faceStr = "K"; break;
default: faceStr = String.valueOf(face);
}
return suite + faceStr;
}
}
}
測試代碼:
class PokerTest {
public static void main(String[] args) { Poker poker = new Poker();
poker.shuffle(); // 洗牌
Poker.Card c1 = poker.deal(0); // 發第一張牌
// 對於非靜態內部類 Card
// 只有經過其外部類 Poker 對象才能建立 Card 對象
Poker.Card c2 = poker.new Card("紅心", 1); // 本身建立一張牌
System.out.println(c1); // 洗牌後的第一張
System.out.println(c2); // 打印: 紅心 A
}
}
面試題 - 下面的代碼哪些地方會產生編譯錯誤?
class Outer {
class Inner {} public static void foo() { new Inner(); } public void bar() { new Inner(); }
public static void main(String[] args) { new Inner();
}
}
注意:Java 中非靜態內部類對象的建立要依賴其外部類對象,上面的面試題中 foo 和 main 方法都是靜態方法,靜態方法中沒有 this,也就是說沒有所謂的外部類對象,所以沒法建立內部類對象,若是要在靜態方法中建立內部類對象,能夠這樣作:
new Outer().new Inner();
2五、Java 中會存在內存泄漏嗎,請簡單描述。
答:
理論上 Java 由於有垃圾回收機制(GC)不會存在內存泄露問題(這也是 Java 被普遍使用於服務器端編程的一個重要緣由);然而在實際開發中,可能會存在無用但可達的對象,這些對象不能被 GC 回收,所以也會致使內存泄露的發生。例如 Hibernate 的 Session(一級緩存)中的對象屬於持久態,垃圾回收器是不會回收這些對象的,然而這些對象中可能存在無用的垃圾對象,若是不及時關閉(close)或清空(flush)一級緩存就可能致使內存泄露。下面例子中的代碼也會致使內存泄露。
import java.util.Arrays;
import java.util.EmptyStackException;
public class MyStack
public MyStack() { elements = (T[]) new Object[INIT_CAPACITY];
}
public void push(T elem) { ensureCapacity(); elements[size++] = elem;
}
public T pop() { if(size == 0) throw new EmptyStackException();
return elements[--size];
}
private void ensureCapacity() { if(elements.length == size) { elements = Arrays.copyOf(elements, 2 * size + 1);
}
}
}
上面的代碼實現了一個棧(先進後出(FILO))結構,乍看之下彷佛沒有什麼明顯的問題,它甚至能夠經過你編寫的各類單元測試。然而其中的 pop 方法卻存在內存泄露的問題,當咱們用 pop 方法彈出棧中的對象時,該對象不會被看成垃圾回收,即便使用棧的程序再也不引用這些對象,由於棧內部維護着對這些對象的過
期引用(obsolete reference)。在支持垃圾回收的語言中,內存泄露是很隱蔽的,這種內存泄露其實就是無心識的對象保持。若是一個對象引用被無心識的保留起來了,那麼垃圾回收器不會處理這個對象,也不會處理該對象引用的其餘對象,
即便這樣的對象只有少數幾個,也可能會致使不少的對象被排除在垃圾回收以外,從而對性能形成重大影響,極端狀況下會引起 Disk Paging(物理內存與硬盤的虛擬內存交換數據),甚至形成 OutOfMemoryError。
2六、抽象的(abstract)方法是否可同時是靜態的(static), 是否可同時是本地方法(native),是否可同時被 synchronized 修飾?
答:
都不能。抽象方法須要子類重寫,而靜態的方法是沒法被重寫的,所以兩者是矛盾的。本地方法是由本地代碼(如 C 代碼)實現的方法,而抽象方法是沒有實現的,也是矛盾的。synchronized 和方法的實現細節有關,抽象方法不涉及實現細節,所以也是相互矛盾的。
2七、 闡述靜態變量和實例變量的區別。
答:
靜態變量是被 static 修飾符修飾的變量,也稱爲類變量,它屬於類,不屬於類的任何一個對象,一個類無論建立多少個對象,靜態變量在內存中有且僅有一個拷貝;實例變量必須依存於某一實例,須要先建立對象而後經過對象才能訪問到它。
靜態變量能夠實現讓多個對象共享內存。
補充:在 Java 開發中,上下文類和工具類中一般會有大量的靜態成員。
2八、 是否能夠從一個靜態(static)方法內部發出對非靜態
(non-static)方法的調用?
答:
不能夠,靜態方法只能訪問靜態成員,由於非靜態方法的調用要先建立對象,在調用靜態方法時可能對象並無被初始化。
2九、如何實現對象克隆?
答:
有兩種方式:
1). 實現 Cloneable 接口並重寫 Object 類中的 clone()方法;
2). 實現 Serializable 接口,經過對象的序列化和反序列化實現克隆,能夠實現真正的深度克隆,代碼以下。
import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream;
import java.io.Serializable; public class MyUtil {
private MyUtil() { throw new AssertionError();
}
@SuppressWarnings("unchecked")
public static
Exception {
ByteArrayOutputStream bout = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bout); oos.writeObject(obj);
ByteArrayInputStream bin = new
ByteArrayInputStream(bout.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bin); return (T) ois.readObject();
// 說明:調用 ByteArrayInputStream 或 ByteArrayOutputStream
對象的 close 方法沒有任何意義
// 這兩個基於內存的流只要垃圾回收器清理對象就可以釋放資源,這一點不一樣於對外部資源(如文件流)的釋放
}
}
下面是測試代碼:
import java.io.Serializable;
/**
*/ class Person implements Serializable { private static final long serialVersionUID = -9102017020286042305L;
private String name; // 姓名 private int age; // 年齡 private Car car; // 座駕
public Person(String name, int age, Car car) { this.name = name; this.age = age; this.car = car;
}
public String getName() { return name;
}
public void setName(String name) { this.name = name;
}
public int getAge() { return age;
}
public void setAge(int age) {
this.age = age;
}
public Car getCar() { return car;
}
public void setCar(Car car) { this.car = car;
}
@Override public String toString() {
return "Person [name=" + name + ", age=" + age + ", car=" +
car + "]";
}
}
/**
*/ class Car implements Serializable { private static final long serialVersionUID = -5713945027627603702L;
private String brand; // 品牌 private int maxSpeed; // 最高時速
public Car(String brand, int maxSpeed) {
this.brand = brand; this.maxSpeed = maxSpeed;
}
public String getBrand() { return brand;
}
public void setBrand(String brand) { this.brand = brand;
}
public int getMaxSpeed() { return maxSpeed;
}
public void setMaxSpeed(int maxSpeed) { this.maxSpeed = maxSpeed;
}
@Override
public String toString() {
return "Car [brand=" + brand + ", maxSpeed=" + maxSpeed +
"]";
}
}
class CloneTest { public static void main(String[] args) {
try {
Person p1 = new Person("Hao LUO", 33, new Car("Benz",
300));
Person p2 = MyUtil.clone(p1); // 深度克隆
p2.getCar().setBrand("BYD");
// 修改克隆的 Person 對象 p2 關聯的汽車對象的品牌屬性
// 原來的 Person 對象 p1 關聯的汽車不會受到任何影響
// 由於在克隆 Person 對象時其關聯的汽車對象也被克隆了
System.out.println(p1);
} catch (Exception e) {
e.printStackTrace();
}
}
}
注意:基於序列化和反序列化實現的克隆不只僅是深度克隆,更重要的是經過泛型限定,能夠檢查出要克隆的對象是否支持序列化,這項檢查是編譯器完成的,不是在運行時拋出異常,這種是方案明顯優於使用 Object 類的 clone 方法克隆對象。讓問題在編譯的時候暴露出來老是好過把問題留到運行時。
30、GC 是什麼?爲何要有 GC?
答:
GC 是垃圾收集的意思,內存處理是編程人員容易出現問題的地方,忘記或者錯誤的內存回收會致使程序或系統的不穩定甚至崩潰,Java 提供的 GC 功能能夠自動監測對象是否超過做用域從而達到自動回收內存的目的,Java 語言沒有提供釋放已分配內存的顯示操做方法。Java 程序員不用擔憂內存管理,由於垃圾收集器會
自動進行管理。要請求垃圾收集,能夠調用下面的方法之一:System.gc() 或
Runtime.getRuntime().gc() ,但 JVM 能夠屏蔽掉顯示的垃圾回收調用。垃圾回收能夠有效的防止內存泄露,有效的使用能夠使用的內存。垃圾回收器一般是做爲一個單獨的低優先級的線程運行,不可預知的狀況下對內存堆中已經死亡的或者長時間沒有使用的對象進行清除和回收,程序員不能實時的調用垃圾回收器對某個對象或全部對象進行垃圾回收。在 Java 誕生初期,垃圾回收是 Java 最大的亮點之一,由於服務器端的編程須要有效的防止內存泄露問題,然而時過境遷,現在 Java 的垃圾回收機制已經成爲被詬病的東西。移動智能終端用戶一般以爲 iOS 的系統比 Android 系統有更好的用戶體驗,其中一個深層次的緣由就在於 Android 系統中垃圾回收的不可預知性。
補充:垃圾回收機制有不少種,包括:分代複製垃圾回收、標記垃圾回收、增量垃圾回收等方式。標準的 Java 進程既有棧又有堆。棧保存了原始型局部變量,堆保存了要建立的對象。Java 平臺對堆內存回收和再利用的基本算法被稱爲標記和清除,可是 Java 對其進行了改進,採用「分代式垃圾收集」。這種方法會跟 Java 對象的生命週期將堆內存劃分爲不一樣的區域,在垃圾收集過程當中,可能會將對象移動到不一樣區域:
• 伊甸園(Eden):這是對象最初誕生的區域,而且對大多數對象來講,這裏是它們惟一存在過的區域。
• 倖存者樂園(Survivor):從伊甸園倖存下來的對象會被挪到這裏。
• 終身頤養園(Tenured):這是足夠老的倖存對象的歸宿。年輕代收集
(Minor-GC)過程是不會觸及這個地方的。當年輕代收集不能把對象放進終身頤養園時,就會觸發一次徹底收集(Major-GC),這裏可能還會牽扯到壓縮,以便爲大對象騰出足夠的空間。
與垃圾回收相關的 JVM 參數:
• -Xms / -Xmx — 堆的初始大小 / 堆的最大大小
• -Xmn — 堆中年輕代的大小
• -XX:-DisableExplicitGC — 讓 System.gc()不產生任何做用
• -XX:+PrintGCDetails — 打印 GC 的細節
• -XX:+PrintGCDateStamps — 打印 GC 操做的時間戳
• -XX:NewSize / XX:MaxNewSize — 設置新生代大小/新生代最大大小 • -XX:NewRatio — 能夠設置老生代和新生代的比例
• -XX:PrintTenuringDistribution — 設置每次新生代 GC 後輸出倖存者樂園中對象年齡的分佈
• -XX:InitialTenuringThreshold / -XX:MaxTenuringThreshold:設置老年代閥值的初始值和最大值
• -XX:TargetSurvivorRatio:設置倖存區的目標使用率
3一、String s = new String(「xyz」);建立了幾個字符串對象?
答:
兩個對象,一個是靜態區的」xyz」,一個是用 new 建立在堆上的對象。
3二、接口是否可繼承(extends)接口?抽象類是否可實現
(implements)接口?抽象類是否可繼承具體類(concrete class)?
答:
接口能夠繼承接口,並且支持多重繼承。抽象類能夠實現(implements)接口,抽象類可繼承具體類也能夠繼承抽象類。
3三、一個」.java」源文件中是否能夠包含多個類(不是內部類)?有什麼限制?
答:
能夠,但一個源文件中最多隻能有一個公開類(public class)並且文件名必須和公開類的類名徹底保持一致。
3四、Anonymous Inner Class(匿名內部類)是否能夠繼承其它類?是否能夠實現接口?
答:
能夠繼承其餘類或實現其餘接口,在 Swing 編程和 Android 開發中經常使用此方式來實現事件監聽和回調。
3五、內部類能夠引用它的包含類(外部類)的成員嗎?有沒有
什麼限制?
答:
一個內部類對象能夠訪問建立它的外部類對象的成員,包括私有成員。
3六、Java 中的 final 關鍵字有哪些用法?
答:
(1)修飾類:表示該類不能被繼承;(2)修飾方法:表示方法不能被重寫;(3)修飾變量:表示變量只能一次賦值之後值不能被修改(常量)。
3七、指出下面程序的運行結果
class A {
static {
System.out.print("1");
}
public A() {
System.out.print("2");
}
}
class B extends A{
static {
System.out.print("a");
}
public B() {
System.out.print("b");
}
}
public class Hello {
public static void main(String[] args) { A ab = new B(); ab = new B();
}
}
答:
執行結果:1a2b2b。建立對象時構造器的調用順序是:先初始化靜態成員,而後調用父類構造器,再初始化非靜態成員,最後調用自身構造器。
提示:若是不能給出此題的正確答案,說明以前第 21 題 Java 類加載機制尚未徹底理解,趕忙再看看吧。
3八、數據類型之間的轉換:
• 如何將字符串轉換爲基本數據類型? • 如何將基本數據類型轉換爲字符串?答:
• 調用基本數據類型對應的包裝類中的方法 parseXXX(String)或 valueOf(String)便可返回相應基本類型;
• 一種方法是將基本數據類型與空字符串(」「)鏈接(+)便可得到其所對應的字符串;另外一種方法是調用 String 類中的 valueOf()方法返回相應字符串
3九、如何實現字符串的反轉及替換?
答:
方法不少,能夠本身寫實現也能夠使用 String 或 StringBuffer/StringBuilder 中的方法。有一道很常見的面試題是用遞歸實現字符串反轉,代碼以下所示:
public static String reverse(String originStr) { if(originStr == null || originStr.length() <= 1) return originStr;
return reverse(originStr.substring(1)) + originStr.charAt(0);
}
40、怎樣將 GB2312 編碼的字符串轉換爲 ISO-8859-1 編碼的字符串?
答:
代碼以下所示:
String s1 = "你好";
String s2 = new String(s1.getBytes("GB2312"), "ISO-8859-1");
4一、日期和時間:
• 如何取得年月日、小時分鐘秒?
• 如何取得從 1970 年 1 月 1 日 0 時 0 分 0 秒到如今的毫秒數?
• 如何取得某月的最後一天?
• 如何格式化日期?
答:
問題 1:建立 java.util.Calendar 實例,調用其 get()方法傳入不一樣的參數便可得到參數所對應的值。Java 8 中能夠使用 java.time.LocalDateTimel 來獲取,代碼以下所示。
public class DateTimeTest { public static void main(String[] args) {
Calendar cal = Calendar.getInstance();
System.out.println(cal.get(Calendar.YEAR));
System.out.println(cal.get(Calendar.MONTH)); // 0 - 11
System.out.println(cal.get(Calendar.DATE));
System.out.println(cal.get(Calendar.HOUR_OF_DAY));
System.out.println(cal.get(Calendar.MINUTE));
System.out.println(cal.get(Calendar.SECOND));
// Java 8
LocalDateTime dt = LocalDateTime.now();
System.out.println(dt.getYear());
System.out.println(dt.getMonthValue()); // 1 - 12
System.out.println(dt.getDayOfMonth());
System.out.println(dt.getHour());
System.out.println(dt.getMinute());
System.out.println(dt.getSecond());
}
}
問題 2:如下方法都可得到該毫秒數。
Calendar.getInstance().getTimeInMillis();
System.currentTimeMillis();
Clock.systemDefaultZone().millis(); // Java 8
問題 3:代碼以下所示。
Calendar time = Calendar.getInstance(); time.getActualMaximum(Calendar.DAY_OF_MONTH);
問題 4:利用 java.text.DataFormat 的子類(如 SimpleDateFormat 類)中的 format(Date)方法可將日期格式化。Java 8 中能夠用 java.time.format.DateTimeFormatter 來格式化時間日期,代碼以下所示。
import java.text.SimpleDateFormat; import java.time.LocalDate;
import java.time.format.DateTimeFormatter; import java.util.Date; class DateFormatTest {
public static void main(String[] args) {
SimpleDateFormat oldFormatter = new
SimpleDateFormat("yyyy/MM/dd");
Date date1 = new Date();
System.out.println(oldFormatter.format(date1));
// Java 8
DateTimeFormatter newFormatter =
DateTimeFormatter.ofPattern("yyyy/MM/dd");
LocalDate date2 = LocalDate.now();
System.out.println(date2.format(newFormatter));
}
}
補充:Java 的時間日期 API 一直以來都是被詬病的東西,爲了解決這一問題,Java
8 中引入了新的時間日期 API,其中包括 LocalDate、LocalTime、LocalDateTime、
Clock、Instant 等類,這些的類的設計都使用了不變模式,所以是線程安全的設計。若是不理解這些內容,能夠參考個人另外一篇文章《關於 Java 併發編程的總結和思考》。
4二、 打印昨天的當前時刻。
答:
import java.util.Calendar;
class YesterdayCurrent { public static void main(String[] args){ Calendar cal = Calendar.getInstance(); cal.add(Calendar.DATE, -1);
System.out.println(cal.getTime());
}
}
在 Java 8 中,能夠用下面的代碼實現相同的功能。
import java.time.LocalDateTime; class YesterdayCurrent {
public static void main(String[] args) {
LocalDateTime today = LocalDateTime.now();
LocalDateTime yesterday = today.minusDays(1);
System.out.println(yesterday);
}
}
4三、 比較一下 Java 和 JavaSciprt。
答:
JavaScript 與 Java 是兩個公司開發的不一樣的兩個產品。Java 是原 Sun
Microsystems 公司推出的面向對象的程序設計語言,特別適合於互聯網應用程序開發;而 JavaScript 是 Netscape 公司的產品,爲了擴展 Netscape 瀏覽器的功能而開發的一種能夠嵌入 Web 頁面中運行的基於對象和事件驅動的解釋性語言。
JavaScript 的前身是 LiveScript;而 Java 的前身是 Oak 語言。
下面對兩種語言間的異同做以下比較:
• 基於對象和麪向對象:Java 是一種真正的面向對象的語言,即便是開發簡單的程序,必須設計對象;JavaScript 是種腳本語言,它能夠用來製做與網絡無關的,與用戶交互做用的複雜軟件。它是一種基於對象(Object-Based)和事件驅動(Event-Driven)的編程語言,於是它自己提供了很是豐富的內部對象供設計人員使用。
• 解釋和編譯:Java 的源代碼在執行以前,必須通過編譯。JavaScript 是一種解釋性編程語言,其源代碼不需通過編譯,由瀏覽器解釋執行。(目前的瀏覽器幾乎都使用了 JIT(即時編譯)技術來提高 JavaScript 的運行效率)
• 強類型變量和類型弱變量:Java 採用強類型變量檢查,即全部變量在編譯以前必須做聲明;JavaScript 中變量是弱類型的,甚至在使用變量前能夠不做聲明,JavaScript 的解釋器在運行時檢查推斷其數據類型。
• 代碼格式不同。
補充:上面列出的四點是網上流傳的所謂的標準答案。其實 Java 和 JavaScript 最重要的區別是一個是靜態語言,一個是動態語言。目前的編程語言的發展趨勢是函數式語言和動態語言。在 Java 中類(class)是一等公民,而 JavaScript 中函數(function)是一等公民,所以 JavaScript 支持函數式編程,能夠使用 Lambda 函數和閉包(closure),固然 Java 8 也開始支持函數式編程,提供了對 Lambda 表達式以及函數式接口的支持。對於這類問題,在面試的時候最好仍是用本身的語言回答會更加靠譜,不要背網上所謂的標準答案。
4四、何時用斷言(assert)?
答:
斷言在軟件開發中是一種經常使用的調試方式,不少開發語言中都支持這種機制。通常來講,斷言用於保證程序最基本、關鍵的正確性。斷言檢查一般在開發和測試時開啓。爲了保證程序的執行效率,在軟件發佈後斷言檢查一般是關閉的。斷言是一個包含布爾表達式的語句,在執行這個語句時假定該表達式爲 true;若是表達式的值爲 false,那麼系統會報告一個 AssertionError。斷言的使用以下面的代碼所示:
assert(a > 0); // throws an AssertionError if a <= 0
斷言能夠有兩種形式:
assert Expression1; assert Expression1 : Expression2 ;
Expression1 應該老是產生一個布爾值。
Expression2 能夠是得出一個值的任意表達式;這個值用於生成顯示更多調試信息的字符串消息。
要在運行時啓用斷言,能夠在啓動 JVM 時使用-enableassertions 或者-ea 標記。要在運行時選擇禁用斷言,能夠在啓動 JVM 時使用-da 或者-disableassertions 標記。要在系統類中啓用或禁用斷言,可以使用-esa 或-dsa 標記。還能夠在包的基礎上啓用或者禁用斷言。
注意:斷言不該該以任何方式改變程序的狀態。簡單的說,若是但願在不知足某些條件時阻止代碼的執行,就能夠考慮用斷言來阻止它。 4五、Error 和 Exception 有什麼區別?
答:
Error 表示系統級的錯誤和程序沒必要處理的異常,是恢復不是不可能但很困難的狀況下的一種嚴重問題;好比內存溢出,不可能期望程序能處理這樣的狀況; Exception 表示須要捕捉或者須要程序進行處理的異常,是一種設計或實現問題;也就是說,它表示若是程序運行正常,從不會發生的狀況。
面試題:2005 年摩托羅拉的面試中曾經問過這麼一個問題「If a process reports a stack overflow run-time error, what’s the most possible cause?」,給了四個選項 a. lack of memory; b. write on an invalid memory space; c.
recursive function calling; d. array index out of boundary. Java 程序在運行時也可能會遭遇 StackOverflowError,這是一個沒法恢復的錯誤,只能從新修改代碼了,這個面試題的答案是 c。若是寫了不能迅速收斂的遞歸,則頗有可能引起棧溢出的錯誤,以下所示:
class StackOverflowErrorTest {
public static void main(String[] args) { main(null);
}
}
提示:用遞歸編寫程序時必定要牢記兩點:1. 遞歸公式;2. 收斂條件(何時就再也不繼續遞歸)。
4六、try{}裏有一個 return 語句,那麼緊跟在這個 try 後的
finally{}裏的代碼會不會被執行,何時被執行,在 return 前仍是後?
答:
會執行,在方法返回調用者前執行。
注意:在 finally 中改變返回值的作法是很差的,由於若是存在 finally 代碼塊,try 中的 return 語句不會立馬返回調用者,而是記錄下返回值待 finally 代碼塊執行完畢以後再向調用者返回其值,而後若是在 finally 中修改了返回值,就會返回修改後的值。顯然,在 finally 中返回或者修改返回值會對程序形成很大的困擾,C#中直接用編譯錯誤的方式來阻止程序員幹這種齷齪的事情,Java 中也能夠經過提高編譯器的語法檢查級別來產生警告或錯誤,Eclipse 中能夠在如圖所示的地方進行設置,強烈建議將此項設置爲編譯錯誤。
4七、Java 語言如何進行異常處理,關鍵字:throws、throw、 try、catch、finally 分別如何使用?
答:
Java 經過面向對象的方法進行異常處理,把各類不一樣的異常進行分類,並提供了良好的接口。在 Java 中,每一個異常都是一個對象,它是 Throwable 類或其子類的實例。當一個方法出現異常後便拋出一個異常對象,該對象中包含有異常信息,
調用這個對象的方法能夠捕獲到這個異常並能夠對其進行處理。Java 的異常處理是經過 5 個關鍵詞來實現的:try、catch、throw、throws 和 finally。通常狀況下是用 try 來執行一段程序,若是系統會拋出(throw)一個異常對象,能夠經過它的類型來捕獲(catch)它,或經過老是執行代碼塊(finally)來處理;try 用來指定一塊預防全部異常的程序;catch 子句緊跟在 try 塊後面,用來指定你想要捕獲的異常的類型;throw 語句用來明確地拋出一個異常;throws 用來聲明一個方法可能拋出的各類異常(固然聲明異常時容許無病呻吟);finally 爲確保一段代碼無論發生什麼異常情況都要被執行;try 語句能夠嵌套,每當遇到一個 try 語句,異常的結構就會被放入異常棧中,直到全部的 try 語句都完成。若是下一級的 try 語句沒有對某種異常進行處理,異常棧就會執行出棧操做,直到遇到有處理這種異常的 try 語句或者最終將異常拋給 JVM。
4八、運行時異常與受檢異常有何異同?
答:
異常表示程序運行過程當中可能出現的非正常狀態,運行時異常表示虛擬機的一般操做中可能遇到的異常,是一種常見運行錯誤,只要程序設計得沒有問題一般就不會發生。受檢異常跟程序運行的上下文環境有關,即便程序設計無誤,仍然可能因使用的問題而引起。Java 編譯器要求方法必須聲明拋出可能發生的受檢異常,
可是並不要求必須聲明拋出未被捕獲的運行時異常。異常和繼承同樣,是面向對象程序設計中常常被濫用的東西,在 EffectiveJava中對異常的使用給出瞭如下指導原則:
• 不要將異常處理用於正常的控制流(設計良好的 API 不該該強迫它的調用者爲了正常的控制流而使用異常)
• 對能夠恢復的狀況使用受檢異常,對編程錯誤使用運行時異常
• 避免沒必要要的使用受檢異常(能夠經過一些狀態檢測手段來避免異常的發生)
• 優先使用標準的異常
• 每一個方法拋出的異常都要有文檔
• 保持異常的原子性
• 不要在 catch 中忽略掉捕獲到的異常
4九、列出一些你常見的運行時異常?
答:
• ArithmeticException(算術異常)
• ClassCastException (類轉換異常)
• IllegalArgumentException (非法參數異常)
• IndexOutOfBoundsException (下標越界異常)
• NullPointerException (空指針異常)
• SecurityException (安全異常)
50、 闡述 final、finally、finalize 的區別。
答:
• final:修飾符(關鍵字)有三種用法:若是一個類被聲明爲 final,意味着它不能再派生出新的子類,即不能被繼承,所以它和 abstract 是反義詞。將變量聲明爲 final,能夠保證它們在使用中不被改變,被聲明爲 final 的變量必須在聲明時給定初值,而在之後的引用中只能讀取不可修改。被聲明爲 final 的方法也一樣只能使用,不能在子類中被重寫。
• finally:一般放在 try…catch…的後面構造老是執行代碼塊,這就意味着程序不管正常執行仍是發生異常,這裏的代碼只要 JVM 不關閉都能執行,能夠將釋放外部資源的代碼寫在 finally 塊中。
• finalize:Object 類中定義的方法,Java 中容許使用 finalize()方法在垃圾收集器將對象從內存中清除出去以前作必要的清理工做。這個方法是由垃圾收集器在銷燬對象時調用的,經過重寫 finalize()方法能夠整理系統資源或者執行其餘清理工做。
5一、 類 ExampleA 繼承 Exception,類 ExampleB 繼承
ExampleA。有以下代碼片段:
try { throw new ExampleB("b")
} catch(ExampleA e){
System.out.println("ExampleA");
} catch(Exception e){
System.out.println("Exception");
}
請問執行此段代碼的輸出是什麼?
答:
輸出:ExampleA。(根據里氏代換原則[能使用父類型的地方必定能使用子類型],
抓取 ExampleA 類型異常的 catch 塊可以抓住 try 塊中拋出的 ExampleB 類型的異常)
面試題 - 說出下面代碼的運行結果。(此題的出處是《Java 編程思想》一書)
class Annoyance extends Exception {} class Sneeze extends Annoyance {} class Human {
public static void main(String[] args) throws Exception {
try { try { throw new Sneeze();
}
catch ( Annoyance a ) {
System.out.println("Caught Annoyance"); throw a;
}
}
catch ( Sneeze s ) {
System.out.println("Caught Sneeze"); return ;
}
finally {
System.out.println("Hello World!");
}
}
}
5二、List、Set、Map 是否繼承自 Collection 接口?
答:
List、Set 是,Map 不是。Map 是鍵值對映射容器,與 List 和 Set 有明顯的區別,而 Set 存儲的零散的元素且不容許有重複元素(數學中的集合也是如此),List 是線性結構的容器,適用於按數值索引訪問元素的情形。
5三、闡述 ArrayList、Vector、LinkedList 的存儲性能和特性。
答:
ArrayList 和 Vector 都是使用數組方式存儲數據,此數組元素數大於實際存儲的數據以便增長和插入元素,它們都容許直接按序號索引元素,可是插入元素要涉及數組元素移動等內存操做,因此索引數據快而插入數據慢,Vector 中的方法因爲添加了 synchronized 修飾,所以 Vector 是線程安全的容器,但性能上較
ArrayList 差,所以已是 Java 中的遺留容器。LinkedList 使用雙向鏈表實現存儲(將內存中零散的內存單元經過附加的引用關聯起來,造成一個能夠按序號索引的線性結構,這種鏈式存儲方式與數組的連續存儲方式相比,內存的利用率更高),按序號索引數據須要進行前向或後向遍歷,可是插入數據時只須要記錄本項的先後項便可,因此插入速度較快。Vector 屬於遺留容器(Java 早期的版本中提供的容器,除此以外,Hashtable、Dictionary、BitSet、Stack、Properties 都是遺留容器),已經不推薦使用,可是因爲 ArrayList 和 LinkedListed 都是非線程安全的,若是遇到多個線程操做同一個容器的場景,則能夠經過工具類
Collections 中的 synchronizedList 方法將其轉換成線程安全的容器後再使用(這是對裝潢模式的應用,將已有對象傳入另外一個類的構造器中建立新的對象來加強實現)。
補充:遺留容器中的 Properties 類和 Stack 類在設計上有嚴重的問題,Properties 是一個鍵和值都是字符串的特殊的鍵值對映射,在設計上應該是關聯一個 Hashtable 並將其兩個泛型參數設置爲 String 類型,可是 Java API 中的
Properties 直接繼承了 Hashtable,這很明顯是對繼承的濫用。這裏複用代碼的方式應該是 Has-A 關係而不是 Is-A 關係,另外一方面容器都屬於工具類,繼承工具
類自己就是一個錯誤的作法,使用工具類最好的方式是 Has-A 關係(關聯)或
Use-A 關係(依賴)。同理,Stack 類繼承 Vector 也是不正確的。Sun 公司的工程師們也會犯這種低級錯誤,讓人唏噓不已。
5四、Collection 和 Collections 的區別?
答:
Collection 是一個接口,它是 Set、List 等容器的父接口;Collections 是個一個工具類,提供了一系列的靜態方法來輔助容器操做,這些方法包括對容器的搜索、排序、線程安全化等等。
5五、List、Map、Set 三個接口存取元素時,各有什麼特色?
答:
List 以特定索引來存取元素,能夠有重複元素。Set 不能存放重複元素(用對象的 equals()方法來區分元素是否重複)。Map 保存鍵值對(key-value pair)映射,映射關係能夠是一對一或多對一。Set 和 Map 容器都有基於哈希存儲和排序樹的兩種實現版本,基於哈希存儲的版本理論存取時間複雜度爲 O(1),而基於排序樹版本的實如今插入或刪除元素時會按照元素或元素的鍵(key)構成排序樹從而達到排序和去重的效果。
5六、TreeMap 和 TreeSet 在排序時如何比較元素?
Collections 工具類中的 sort()方法如何比較元素?
答:
TreeSet 要求存放的對象所屬的類必須實現 Comparable 接口,該接口提供了比較元素的 compareTo()方法,當插入元素時會回調該方法比較元素的大小。
TreeMap 要求存放的鍵值對映射的鍵必須實現 Comparable 接口從而根據鍵對元素進行排序。Collections 工具類的 sort 方法有兩種重載的形式,第一種要求傳入的待排序容器中存放的對象比較實現 Comparable 接口以實現元素的比較;第二種不強制性的要求容器中的元素必須可比較,可是要求傳入第二個參數,參數是
Comparator 接口的子類型(須要重寫 compare 方法實現元素的比較),至關於一個臨時定義的排序規則,其實就是經過接口注入比較元素大小的算法,也是對回調模式的應用(Java 中對函數式編程的支持)。
例子 1:
public class Student implements Comparable
public Student(String name, int age) { this.name = name; this.age = age;
}
@Override
public String toString() { return "Student [name=" + name + ", age=" + age + "]";
}
@Override
public int compareTo(Student o) { return this.age - o.age; // 比較年齡(年齡的升序)
}
}
import java.util.Set; import java.util.TreeSet; class Test01 {
public static void main(String[] args) {
Set
(構造器後面的尖括號中不須要寫類型)
set.add(new Student("Hao LUO", 33)); set.add(new Student("XJ WANG", 32)); set.add(new Student("Bruce LEE", 60)); set.add(new Student("Bob YANG", 22));
for(Student stu : set) {
System.out.println(stu);
} // Java 7 的鑽石語法
// 輸出結果:
// Student [name=Bob YANG, age=22]
// Student [name=XJ WANG, age=32]
// Student [name=Hao LUO, age=33]
// Student [name=Bruce LEE, age=60]
} }
例子 2:
public class Student { private String name; // 姓名
private int age; // 年齡
public Student(String name, int age) { this.name = name; this.age = age;
}
/
import java.util.List; class Test02 {
public static void main(String[] args) {
List
(構造器後面的尖括號中不須要寫類型)
list.add(new Student("Hao LUO", 33)); list.add(new Student("XJ WANG", 32)); list.add(new Student("Bruce LEE", 60)); list.add(new Student("Bob YANG", 22));
// 經過 sort 方法的第二個參數傳入一個 Comparator 接口對象
// 至關因而傳入一個比較對象大小的算法到 sort 方法中
// 因爲 Java 中沒有函數指針、仿函數、委託這樣的概念
// 所以要將一個算法傳入一個方法中惟一的選擇就是經過接口回調
Collections.sort(list, new Comparator
@Override
public int compare(Student o1, Student o2) { return o1.getName().compareTo(o2.getName()); //
比較學生姓名
}
});
for(Student stu : list) {
System.out.println(stu);
}
// 輸出結果:
// Student [name=Bob YANG, age=22]
// Student [name=Bruce LEE, age=60]
// Student [name=Hao LUO, age=33]
//
}
} Student [name=XJ WANG, age=32]
5七、Thread 類的 sleep()方法和對象的 wait()方法均可以讓線程暫停執行,它們有什麼區別?
答:
sleep()方法(休眠)是線程類(Thread)的靜態方法,調用此方法會讓當前線程暫停執行指定的時間,將執行機會(CPU)讓給其餘線程,可是對象的鎖依然保持,所以休眠時間結束後會自動恢復(線程回到就緒狀態,請參考第 66 題中的線程狀態轉換圖)。wait()是 Object 類的方法,調用對象的 wait()方法致使當前線程放棄對象的鎖(線程暫停執行),進入對象的等待池(wait pool),只有調用對象的 notify()方法(或 notifyAll()方法)時才能喚醒等待池中的線程進入等鎖池
(lock pool),若是線程從新得到對象的鎖就能夠進入就緒狀態。
補充:可能很多人對什麼是進程,什麼是線程還比較模糊,對於爲何須要多線程編程也不是特別理解。簡單的說:進程是具備必定獨立功能的程序關於某個數據集合上的一次運行活動,是操做系統進行資源分配和調度的一個獨立單位;線程是進程的一個實體,是 CPU 調度和分派的基本單位,是比進程更小的能獨立運行的基本單位。線程的劃分尺度小於進程,這使得多線程程序的併發性高;進程在執行時一般擁有獨立的內存單元,而線程之間能夠共享內存。使用多線程的編程一般可以帶來更好的性能和用戶體驗,可是多線程的程序對於其餘程序是不友好的,由於它可能佔用了更多的 CPU 資源。固然,也不是線程越多,程序的性能就越好,由於線程之間的調度和切換也會浪費 CPU 時間。時下很時髦的 Node.js 就採用了單線程異步 I/O 的工做模式。
5八、線程的 sleep()方法和 yield()方法有什麼區別?
答:
① sleep()方法給其餘線程運行機會時不考慮線程的優先級,所以會給低優先級的線程以運行的機會;yield()方法只會給相同優先級或更高優先級的線程以運行的機會;
② 線程執行 sleep()方法後轉入阻塞(blocked)狀態,而執行 yield()方法後轉入就緒(ready)狀態;
③ sleep()方法聲明拋出 InterruptedException,而 yield()方法沒有聲明任何異常;
④ sleep()方法比 yield()方法(跟操做系統 CPU 調度相關)具備更好的可移植性。
5九、當一個線程進入一個對象的 synchronized 方法 A 以後,其它線程是否可進入此對象的 synchronized 方法 B?
答:
不能。其它線程只能訪問該對象的非同步方法,同步方法則不能進入。由於非靜態方法上的 synchronized 修飾符要求執行方法時要得到對象的鎖,若是已經進入 A 方法說明對象鎖已經被取走,那麼試圖進入 B 方法的線程就只能在等鎖池(注意不是等待池哦)中等待對象的鎖。
60、請說出與線程同步以及線程調度相關的方法。
答:
• wait():使一個線程處於等待(阻塞)狀態,而且釋放所持有的對象的鎖;
• sleep():使一個正在運行的線程處於睡眠狀態,是一個靜態方法,調用此方法要處理 InterruptedException 異常;
• notify():喚醒一個處於等待狀態的線程,固然在調用此方法的時候,並不能確切的喚醒某一個等待狀態的線程,而是由 JVM 肯定喚醒哪一個線程,並且與優先級無關;
• notityAll():喚醒全部處於等待狀態的線程,該方法並非將對象的鎖給全部線程,而是讓它們競爭,只有得到鎖的線程才能進入就緒狀態;
提示:關於 Java 多線程和併發編程的問題,建議你們看個人另外一篇文章《關於 Java 併發編程的總結和思考》。
補充:Java 5 經過 Lock 接口提供了顯式的鎖機制(explicit lock),加強了靈活性以及對線程的協調。Lock 接口中定義了加鎖(lock())和解鎖(unlock())的方法,同時還提供了 newCondition()方法來產生用於線程之間通訊的 Condition 對象;此外,Java 5 還提供了信號量機制(semaphore),信號量能夠用來限制對某個共享資源進行訪問的線程的數量。在對資源進行訪問以前,線程必須獲得信
號量的許可(調用 Semaphore 對象的 acquire()方法);在完成對資源的訪問後,線程必須向信號量歸還許可(調用 Semaphore 對象的 release()方法)。
下面的例子演示了 100 個線程同時向一個銀行帳戶中存入 1 元錢,在沒有使用同步機制和使用同步機制狀況下的執行狀況。
• 銀行帳戶類:
/**
/
public class Account {
private double balance; // 帳戶餘額
/*
存款
@param money 存入金額
/
public void deposit(double money) { double newBalance = balance + money; try {
Thread.sleep(10); // 模擬此業務須要一段處理時間
}
catch(InterruptedException ex) { ex.printStackTrace();
}
balance = newBalance;
}
/*
得到帳戶餘額
/ public double getBalance() { return balance;
}
}
• 存錢線程類:
/*
存錢線程
@author 駱昊
/
public class AddMoneyThread implements Runnable { private Account account; // 存入帳戶 private double money; // 存入金額
public AddMoneyThread(Account account, double money) { this.account = account; this.money = money;
}
@Override public void run() { account.deposit(money);
}
}
• 測試類:
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Test01 {
public static void main(String[] args) {
Account account = new Account();
ExecutorService service = Executors.newFixedThreadPool(100);
for(int i = 1; i <= 100; i++) {
service.execute(new AddMoneyThread(account, 1));
}
service.shutdown(); while(!service.isTerminated()) {}
System.out.println("帳戶餘額: " + account.getBalance());
}
}
在沒有同步的狀況下,執行結果一般是顯示帳戶餘額在 10 元如下,出現這種情況的緣由是,當一個線程 A 試圖存入 1 元的時候,另一個線程 B 也可以進入存款的方法中,線程 B 讀取到的帳戶餘額仍然是線程 A 存入 1 元錢以前的帳戶餘額,所以也是在原來的餘額 0 上面作了加 1 元的操做,同理線程 C 也會作相似的事情,因此最後 100 個線程執行結束時,原本指望帳戶餘額爲 100 元,但實際獲得的一般在 10 元如下(極可能是 1 元哦)。解決這個問題的辦法就是同步,當一個線程對銀行帳戶存錢時,須要將此帳戶鎖定,待其操做完成後才容許其餘的線程進行操做,代碼有以下幾種調整方案:
• 在銀行帳戶的存款(deposit)方法上同步(synchronized)關鍵字
/*
/ public class Account { private double balance; // 帳戶餘額
/*
/
public class AddMoneyThread implements Runnable {
private Account account; // 存入帳戶 private double money; // 存入金額
public AddMoneyThread(Account account, double money) { this.account = account; this.money = money;
}
@Override public void run() { synchronized (account) { account.deposit(money);
}
}
}
• 經過 Java 5 顯示的鎖機制,爲每一個銀行帳戶建立一個鎖對象,在存款操做進行加鎖和解鎖的操做
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock;
/*
/ public class Account { private Lock accountLock = new ReentrantLock();
private double balance; // 帳戶餘額
/*
private int upperBounds;
public MyTask(int upperBounds) { this.upperBounds = upperBounds;
}
@Override
public Integer call() throws Exception { int sum = 0;
for(int i = 1; i <= upperBounds; i++) { sum += i;
}
return sum;
}
}
class Test {
public static void main(String[] args) throws Exception {
List<Future
ExecutorService service = Executors.newFixedThreadPool(10); for(int i = 0; i < 10; i++) { list.add(service.submit(new MyTask((int) (Math.random() * 100))));
}
int sum = 0;
for(Future
}
System.out.println(sum);
}
}
6二、synchronized 關鍵字的用法?
答:
synchronized 關鍵字能夠將對象或者方法標記爲同步,以實現對對象和方法的互斥訪問,能夠用 synchronized(對象) { … }定義同步代碼塊,或者在聲明方法時
將 synchronized 做爲方法的修飾符。在第 60 題的例子中已經展現了 synchronized 關鍵字的用法。
6三、舉例說明同步和異步。
答:
若是系統中存在臨界資源(資源數量少於競爭資源的線程數量的資源),例如正在寫的數據之後可能被另外一個線程讀到,或者正在讀的數據可能已經被另外一個線程寫過了,那麼這些數據就必須進行同步存取(數據庫操做中的排他鎖就是最好的例子)。當應用程序在對象上調用了一個須要花費很長時間來執行的方法,而且不但願讓程序等待方法的返回時,就應該使用異步編程,在不少狀況下采用異步途徑每每更有效率。事實上,所謂的同步就是指阻塞式操做,而異步就是非阻塞式操做。
6四、啓動一個線程是調用 run()仍是 start()方法?
答:
啓動一個線程是調用 start()方法,使線程所表明的虛擬處理機處於可運行狀態,這意味着它能夠由 JVM 調度並執行,這並不意味着線程就會當即運行。run()方法是線程啓動後要進行回調(callback)的方法。
6五、什麼是線程池(thread pool)?
答:
在面向對象編程中,建立和銷燬對象是很費時間的,由於建立一個對象要獲取內存資源或者其它更多資源。在 Java 中更是如此,虛擬機將試圖跟蹤每個對象,以便可以在對象銷燬後進行垃圾回收。因此提升服務程序效率的一個手段就是儘量減小建立和銷燬對象的次數,特別是一些很耗資源的對象建立和銷燬,這就是」池化資源」技術產生的緣由。線程池顧名思義就是事先建立若干個可執行的線程放入一個池(容器)中,須要的時候從池中獲取線程不用自行建立,使用完
畢不須要銷燬線程而是放回池中,從而減小建立和銷燬線程對象的開銷。
Java 5+中的 Executor 接口定義一個執行線程的工具。它的子類型即線程池接口是 ExecutorService。要配置一個線程池是比較複雜的,尤爲是對於線程池的原理不是很清楚的狀況下,所以在工具類 Executors 面提供了一些靜態工廠方法,生成一些經常使用的線程池,以下所示:
• newSingleThreadExecutor:建立一個單線程的線程池。這個線程池只有一個線程在工做,也就是至關於單線程串行執行全部任務。若是這個惟一的線程由於異常結束,那麼會有一個新的線程來替代它。此線程池保證全部任務的執行順序按照任務的提交順序執行。
• newFixedThreadPool:建立固定大小的線程池。每次提交一個任務就建立一個線程,直到線程達到線程池的最大大小。線程池的大小一旦達到最大值就會保持不變,若是某個線程由於執行異常而結束,那麼線程池會補充一個新線程。
• newCachedThreadPool:建立一個可緩存的線程池。若是線程池的大小超過了處理任務所須要的線程,那麼就會回收部分空閒(60 秒不執行任務)的線程,當任務數增長時,此線程池又能夠智能的添加新線程來處理任務。此線程池不會對線程池大小作限制,線程池大小徹底依賴於操做系統(或者說 JVM)可以建立的最大線程大小。
• newScheduledThreadPool:建立一個大小無限的線程池。此線程池支持定時以及週期性執行任務的需求。
• newSingleThreadExecutor:建立一個單線程的線程池。此線程池支持定時以及週期性執行任務的需求。
第 60 題的例子中演示了經過 Executors 工具類建立線程池並使用線程池執行線程的代碼。若是但願在服務器上使用線程池,強烈建議使用 newFixedThreadPool 方法來建立線程池,這樣能得到更好的性能。
6六、線程的基本狀態以及狀態之間的關係?
答:
說明:其中 Running 表示運行狀態,Runnable 表示就緒狀態(萬事俱備,只欠 CPU),Blocked 表示阻塞狀態,阻塞狀態又有多種狀況,多是由於調用 wait() 方法進入等待池,也多是執行同步方法或同步代碼塊進入等鎖池,或者是調用
了 sleep()方法或 join()方法等待休眠或其餘線程結束,或是由於發生了 I/O 中斷。
6七、簡述 synchronized 和 java.util.concurrent.locks.Lock 的異同?
答:
Lock 是 Java 5 之後引入的新的 API,和關鍵字 synchronized 相比主要相同點:
Lock 能完成 synchronized 所實現的全部功能;主要不一樣點:Lock 有比
synchronized 更精確的線程語義和更好的性能,並且不強制性的要求必定要得到鎖。synchronized 會自動釋放鎖,而 Lock 必定要求程序員手工釋放,而且最好在 finally 塊中釋放(這是釋放外部資源的最好的地方)。
6八、Java 中如何實現序列化,有什麼意義?
答:
序列化就是一種用來處理對象流的機制,所謂對象流也就是將對象的內容進行流化。能夠對流化後的對象進行讀寫操做,也可將流化後的對象傳輸於網絡之間。序列化是爲了解決對象流讀寫操做時可能引起的問題(若是不進行序列化可能會存在數據亂序的問題)。
要實現序列化,須要讓一個類實現 Serializable 接口,該接口是一個標識性接口,
標註該類對象是可被序列化的,而後使用一個輸出流來構造一個對象輸出流並經過 writeObject(Object)方法就能夠將實現對象寫出(即保存其狀態);若是須要反序列化則能夠用一個輸入流創建對象輸入流,而後經過 readObject 方法從流中讀取對象。序列化除了可以實現對象的持久化以外,還可以用於對象的深度克隆
(能夠參考第 29 題)。
6九、Java 中有幾種類型的流?
答:
字節流和字符流。字節流繼承於 InputStream、OutputStream,字符流繼承於 Reader、Writer。在 java.io 包中還有許多其餘的流,主要是爲了提升性能和使用方便。關於 Java 的 I/O 須要注意的有兩點:一是兩種對稱性(輸入和輸出的對稱性,字節和字符的對稱性);二是兩種設計模式(適配器模式和裝潢模式)。
另外 Java 中的流不一樣於 C#的是它只有一個維度一個方向。
面試題 - 編程實現文件拷貝。(這個題目在筆試的時候常常出現,下面的代碼給出了兩種實現方案)
import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; public final class MyUtil {
private MyUtil() { throw new AssertionError();
}
public static void fileCopy(String source, String target) throws
IOException { try (InputStream in = new FileInputStream(source)) { try (OutputStream out = new FileOutputStream(target)) { byte[] buffer = new byte[4096]; int bytesToRead;
while((bytesToRead = in.read(buffer)) != -1) { out.write(buffer, 0, bytesToRead);
}
}
}
}
public static void fileCopyNIO(String source, String target) throws
IOException { try (FileInputStream in = new FileInputStream(source)) { try (FileOutputStream out = new FileOutputStream(target)) {
FileChannel inChannel = in.getChannel();
FileChannel outChannel = out.getChannel(); ByteBuffer buffer = ByteBuffer.allocate(4096); while(inChannel.read(buffer) != -1) {
buffer.flip(); outChannel.write(buffer);
buffer.clear();
}
}
}
}
}
注意:上面用到 Java 7 的 TWR,使用 TWR 後能夠不用在 finally 中釋放外部資源 ,從而讓代碼更加優雅。
70、寫一個方法,輸入一個文件名和一個字符串,統計這個字符串在這個文件中出現的次數。
答:
代碼以下:
import java.io.BufferedReader; import java.io.FileReader; public final class MyUtil {
// 工具類中的方法都是靜態方式訪問的所以將構造器私有不容許建立對象 (絕對好習慣)
private MyUtil() { throw new AssertionError();
}
/**
}
7一、如何用 Java 代碼列出一個目錄下全部的文件?
答:
import java.io.File; class Test12 {
public static void main(String[] args) { showDirectory(new File("/Users/Hao/Downloads"));
若是隻要求列出當前文件夾下的文件,代碼以下所示:
import java.io.File; class Test12 {
public static void main(String[] args) {
File f = new File("/Users/Hao/Downloads"); for(File temp : f.listFiles()) { if(temp.isFile()) {
System.out.println(temp.getName());
}
}
}
}
若是須要對文件夾繼續展開,代碼以下所示:
}
public static void showDirectory(File f) { _walkDirectory(f, 0);
}
private static void _walkDirectory(File f, int level) { if(f.isDirectory()) { for(File temp : f.listFiles()) {
_walkDirectory(temp, level + 1);
}
}
else { for(int i = 0; i < level - 1; i++) {
System.out.print("\t");
}
System.out.println(f.getName());
}
}
}
在 Java 7 中能夠使用 NIO.2 的 API 來作一樣的事情,代碼以下所示:
class ShowFileTest {
public static void main(String[] args) throws IOException {
Path initPath = Paths.get("/Users/Hao/Downloads");
Files.walkFileTree(initPath, new SimpleFileVisitor
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes
attrs)
throws IOException {
System.out.println(file.getFileName().toString()); return FileVisitResult.CONTINUE;
}
});
}
}
7二、用 Java 的套接字編程實現一個多線程的回顯(echo)服務器。
答:
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader;
import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class EchoServer { private static final int ECHO_SERVER_PORT = 6789; public static void main(String[] args) {
try(ServerSocket server = new
ServerSocket(ECHO_SERVER_PORT)) {
System.out.println("服務器已經啓動..."); while(true) {
Socket client = server.accept();
new Thread(new ClientHandler(client)).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static class ClientHandler implements Runnable { private Socket client;
public ClientHandler(Socket client) { this.client = client;
}
@Override public void run() { try(BufferedReader br = new BufferedReader(new
InputStreamReader(client.getInputStream())); PrintWriter pw = new
PrintWriter(client.getOutputStream())) {
String msg = br.readLine();
System.out.println("收到" + client.getInetAddress() + "
發送的: " + msg);
pw.println(msg); pw.flush();
} catch(Exception ex) {
ex.printStackTrace();
} finally { try { client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
注意:上面的代碼使用了 Java 7 的 TWR 語法,因爲不少外部資源類都間接的實現了 AutoCloseable 接口(單方法回調接口),所以能夠利用 TWR 語法在 try 結束的時候經過回調的方式自動調用外部資源類的 close()方法,避免書寫冗長的 finally 代碼塊。此外,上面的代碼用一個靜態內部類實現線程的功能,使用多線程能夠避免一個用戶 I/O 操做所產生的中斷影響其餘用戶對服務器的訪問,簡單的說就是一個用戶的輸入操做不會形成其餘用戶的阻塞。固然,上面的代碼使用線程池能夠得到更好的性能,由於頻繁的建立和銷燬線程所形成的開銷也是不可忽視的。
下面是一段回顯客戶端測試代碼:
import java.io.BufferedReader; import java.io.InputStreamReader;
import java.io.PrintWriter; import java.net.Socket; import java.util.Scanner; public class EchoClient {
public static void main(String[] args) throws Exception {
Socket client = new Socket("localhost", 6789);
Scanner sc = new Scanner(System.in);
System.out.print("請輸入內容: "); String msg = sc.nextLine();
sc.close();
PrintWriter pw = new PrintWriter(client.getOutputStream()); pw.println(msg); pw.flush();
BufferedReader br = new BufferedReader(new
InputStreamReader(client.getInputStream())); System.out.println(br.readLine());
client.close();
}
}
若是但願用 NIO 的多路複用套接字實現服務器,代碼以下所示。NIO 的操做雖然帶來了更好的性能,可是有些操做是比較底層的,對於初學者來講仍是有些難於理解。
import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.Iterator;
public class EchoServerNIO {
private static final int ECHO_SERVER_PORT = 6789; private static final int ECHO_SERVER_TIMEOUT = 5000; private static final int BUFFER_SIZE = 1024;
private static ServerSocketChannel serverChannel = null; private static Selector selector = null; // 多路複用選擇器 private static ByteBuffer buffer = null; // 緩衝區
public static void main(String[] args) {
init(); listen();
}
private static void init() { try { serverChannel = ServerSocketChannel.open(); buffer = ByteBuffer.allocate(BUFFER_SIZE); serverChannel.socket().bind(new
InetSocketAddress(ECHO_SERVER_PORT)); serverChannel.configureBlocking(false); selector = Selector.open();
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
} catch (Exception e) { throw new RuntimeException(e);
}
}
private static void listen() { while (true) {
try { if (selector.select(ECHO_SERVER_TIMEOUT) != 0) { Iterator
selector.selectedKeys().iterator(); while (it.hasNext()) {
SelectionKey key = it.next();
it.remove(); handleKey(key);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
private static void handleKey(SelectionKey key) throws IOException { SocketChannel channel = null;
try { if (key.isAcceptable()) {
ServerSocketChannel serverChannel =
(ServerSocketChannel) key.channel(); channel = serverChannel.accept(); channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) { channel = (SocketChannel) key.channel(); buffer.clear();
if (channel.read(buffer) > 0) {
buffer.flip();
CharBuffer charBuffer =
CharsetHelper.decode(buffer);
String msg = charBuffer.toString(); System.out.println("收到" +
channel.getRemoteAddress() + "的消息:" + msg);
channel.write(CharsetHelper.encode(CharBuffer.wrap(msg))); } else { channel.close();
}
}
} catch (Exception e) {
e.printStackTrace(); if (channel != null) { channel.close();
}
}
}
}
import java.nio.ByteBuffer; import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder;
public final class CharsetHelper { private static final String UTF_8 = "UTF-8";
private static CharsetEncoder encoder =
Charset.forName(UTF_8).newEncoder(); private static CharsetDecoder decoder = Charset.forName(UTF_8).newDecoder();
private CharsetHelper() {
}
public static ByteBuffer encode(CharBuffer in) throws
CharacterCodingException{
return encoder.encode(in);
}
public static CharBuffer decode(ByteBuffer in) throws
CharacterCodingException{
return decoder.decode(in);
}
}
7三、XML 文檔定義有幾種形式?它們之間有何本質區別?解析
XML 文檔有哪幾種方式?
答:
XML 文檔定義分爲 DTD 和 Schema 兩種形式,兩者都是對 XML 語法的約束,其本質區別在於 Schema 自己也是一個 XML 文件,能夠被 XML 解析器解析,並且能夠爲 XML 承載的數據定義類型,約束能力較之 DTD 更強大。對 XML 的解析主要有 DOM(文檔對象模型,Document Object Model)、SAX(Simple API for
XML)和 StAX(Java 6 中引入的新的解析 XML 的方式,Streaming API for XML),其中 DOM 處理大型文件時其性能降低的很是厲害,這個問題是由 DOM 樹結構佔用的內存較多形成的,並且 DOM 解析方式必須在解析文件以前把整個文檔裝入內存,適合對 XML 的隨機訪問(典型的用空間換取時間的策略);SAX 是事件驅動型的 XML 解析方式,它順序讀取 XML 文件,不須要一次所有裝載整個文件。當遇到像文件開頭,文檔結束,或者標籤開頭與標籤結束時,它會觸發一個事件,用戶經過事件回調代碼來處理 XML 文件,適合對 XML 的順序訪問;顧名思義, StAX 把重點放在流上,實際上 StAX 與其餘解析方式的本質區別就在於應用程序可以把 XML 做爲一個事件流來處理。將 XML 做爲一組事件來處理的想法並不新穎(SAX 就是這樣作的),但不一樣之處在於 StAX 容許應用程序代碼把這些事件逐個拉出來,而不用提供在解析器方便時從解析器中接收事件的處理程序。
7四、你在項目中哪些地方用到了 XML?
答:
XML 的主要做用有兩個方面:數據交換和信息配置。在作數據交換時,XML 將數據用標籤組裝成起來,而後壓縮打包加密後經過網絡傳送給接收者,接收解密與解壓縮後再從 XML 文件中還原相關信息進行處理,XML 曾經是異構系統間交換數據的事實標準,但此項功能幾乎已經被 JSON(JavaScript Object Notation)取而代之。固然,目前不少軟件仍然使用 XML 來存儲配置信息,咱們在不少項目中一般也會將做爲配置信息的硬代碼寫在 XML 文件中,Java 的不少框架也是這麼作的,並且這些框架都選擇了 dom4j 做爲處理 XML 的工具,由於 Sun 公司的官方
API 實在不怎麼好用。
補充:如今有不少時髦的軟件(如 Sublime)已經開始將配置文件書寫成 JSON 格式,咱們已經強烈的感覺到 XML 的另外一項功能也將逐漸被業界拋棄。
7五、闡述 JDBC 操做數據庫的步驟。
答:
下面的代碼以鏈接本機的 Oracle 數據庫爲例,演示 JDBC 操做數據庫的步驟。
• 加載驅動。
Class.forName("oracle.jdbc.driver.OracleDriver");
• 建立鏈接。
Connection con =
DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl", "scott", "tiger");
• 建立語句。
PreparedStatement ps = con.prepareStatement("select * from emp where sal between ? and ?");
ps.setInt(1, 1000); ps.setInt(2, 3000);
• 執行語句。
ResultSet rs = ps.executeQuery();
• 處理結果。
while(rs.next()) {
System.out.println(rs.getInt("empno") + " - " + rs.getString("ename"));
}
• 關閉資源。
finally { if(con != null) { try { con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
提示:關閉外部資源的順序應該和打開的順序相反,也就是說先關閉 ResultSet、再關閉 Statement、在關閉 Connection。上面的代碼只關閉了 Connection(鏈接),雖然一般狀況下在關閉鏈接時,鏈接上建立的語句和打開的遊標也會關閉,但不能保證老是如此,所以應該按照剛纔說的順序分別關閉。此外,第一步加載驅動在 JDBC 4.0 中是能夠省略的(自動從類路徑中加載驅動),可是咱們建議保留。
7六、Statement 和 PreparedStatement 有什麼區別?哪一個性能更好?
答:
與 Statement 相比,①PreparedStatement 接口表明預編譯的語句,它主要的優點在於能夠減小 SQL 的編譯錯誤並增長 SQL 的安全性(減小 SQL 注射攻擊的可能性);②PreparedStatement 中的 SQL 語句是能夠帶參數的,避免了用字符串鏈接拼接 SQL 語句的麻煩和不安全;③當批量處理 SQL 或頻繁執行相同的查詢時,
PreparedStatement 有明顯的性能上的優點,因爲數據庫能夠將編譯優化後的
SQL 語句緩存起來,下次執行相同結構的語句時就會很快(不用再次編譯和生成執行計劃)。
補充:爲了提供對存儲過程的調用,JDBC API 中還提供了 CallableStatement 接口。存儲過程(Stored Procedure)是數據庫中一組爲了完成特定功能的 SQL 語句的集合,經編譯後存儲在數據庫中,用戶經過指定存儲過程的名字並給出參數(若是該存儲過程帶有參數)來執行它。雖然調用存儲過程會在網絡開銷、安全性、性能上得到不少好處,可是存在若是底層數據庫發生遷移時就會有不少麻煩,由於每種數據庫的存儲過程在書寫上存在很多的差異。
7七、使用 JDBC 操做數據庫時,如何提高讀取數據的性能?如何提高更新數據的性能?
答:
要提高讀取數據的性能,能夠指定經過結果集(ResultSet)對象的 setFetchSize() 方法指定每次抓取的記錄數(典型的空間換時間策略);要提高更新數據的性能能夠使用 PreparedStatement 語句構建批處理,將若干 SQL 語句置於一個批處理中執行。
7八、在進行數據庫編程時,鏈接池有什麼做用?
答:
因爲建立鏈接和釋放鏈接都有很大的開銷(尤爲是數據庫服務器不在本地時,每次創建鏈接都須要進行 TCP 的三次握手,釋放鏈接須要進行 TCP 四次握手,形成的開銷是不可忽視的),爲了提高系統訪問數據庫的性能,能夠事先建立若干鏈接置於鏈接池中,須要時直接從鏈接池獲取,使用結束時歸還鏈接池而沒必要關閉鏈接,從而避免頻繁建立和釋放鏈接所形成的開銷,這是典型的用空間換取時間的策略(浪費了空間存儲鏈接,但節省了建立和釋放鏈接的時間)。池化技術在
Java 開發中是很常見的,在使用線程時建立線程池的道理與此相同。基於 Java 的開源數據庫鏈接池主要有:C3P0、Proxool、DBCP、BoneCP、Druid 等。
補充:在計算機系統中時間和空間是不可調和的矛盾,理解這一點對設計知足性能要求的算法是相當重要的。大型網站性能優化的一個關鍵就是使用緩存,而緩存跟上面講的鏈接池道理很是相似,也是使用空間換時間的策略。能夠將熱點數據置於緩存中,當用戶查詢這些數據時能夠直接從緩存中獲得,這不管如何也快過去數據庫中查詢。固然,緩存的置換策略等也會對系統性能產生重要影響,對於這個問題的討論已經超出了這裏要闡述的範圍。
7九、什麼是 DAO 模式?
答:
DAO(Data Access Object)顧名思義是一個爲數據庫或其餘持久化機制提供了抽象接口的對象,在不暴露底層持久化方案實現細節的前提下提供了各類數據訪問操做。在實際的開發中,應該將全部對數據源的訪問操做進行抽象化後封裝在一個公共 API 中。用程序設計語言來講,就是創建一個接口,接口中定義了此應用程序中將會用到的全部事務方法。在這個應用程序中,當須要和數據源進行交互的時候則使用這個接口,而且編寫一個單獨的類來實現這個接口,在邏輯上該
類對應一個特定的數據存儲。DAO 模式實際上包含了兩個模式,一是 Data
Accessor(數據訪問器),二是 Data Object(數據對象),前者要解決如何訪問數據的問題,然後者要解決的是如何用對象封裝數據。
80、事務的 ACID 是指什麼?
答:
• 原子性(Atomic):事務中各項操做,要麼全作要麼全不作,任何一項操做的失敗都會致使整個事務的失敗;
• 一致性(Consistent):事務結束後系統狀態是一致的;
• 隔離性(Isolated):併發執行的事務彼此沒法看到對方的中間狀態;
• 持久性(Durable):事務完成後所作的改動都會被持久化,即便發生災難性的失敗。經過日誌和同步備份能夠在故障發生後重建數據。
補充:關於事務,在面試中被問到的機率是很高的,能夠問的問題也是不少的。首先須要知道的是,只有存在併發數據訪問時才須要事務。當多個事務訪問同一數據時,可能會存在 5 類問題,包括 3 類數據讀取問題(髒讀、不可重複讀和幻讀)和 2 類數據更新問題(第 1 類丟失更新和第 2 類丟失更新)。
髒讀(Dirty Read):A 事務讀取 B 事務還沒有提交的數據並在此基礎上操做,而 B 事務執行回滾,那麼 A 讀取到的數據就是髒數據。
時間 轉帳事務 A 取款事務 B
T1 開始事務
T2 開始事務
T3 查詢帳戶餘額爲 1000 元
T4 取出 500 元餘額修改成 500 元
T5 查詢帳戶餘額爲 500 元(髒讀)
T6 撤銷事務餘額恢復爲 1000 元
T7 匯入 100 元把餘額修改成 600 元
T8 提交事務
不可重複讀(Unrepeatable Read):事務 A 從新讀取前面讀取過的數據,發現該數據已經被另外一個已提交的事務 B 修改過了。
時間 轉帳事務 A 取款事務 B
T1 開始事務
T2 開始事務
T3 查詢帳戶餘額爲 1000 元
T4 查詢帳戶餘額爲 1000 元
T5 取出 100 元修改餘額爲 900 元
T6 提交事務
T7 查詢帳戶餘額爲 900 元(不可重複讀)
幻讀(Phantom Read):事務 A 從新執行一個查詢,返回一系列符合查詢條件的行,發現其中插入了被事務 B 提交的行。
時間 統計金額事務 A 轉帳事務 B
T1 開始事務
T2 開始事務
T3 統計總存款爲 10000 元
T4 新增一個存款帳戶存入 100 元
T5 提交事務
T6 再次統計總存款爲 10100 元(幻讀)
第 1 類丟失更新:事務 A 撤銷時,把已經提交的事務 B 的更新數據覆蓋了。
時間 取款事務 A 轉帳事務 B
T1 開始事務
T2 開始事務
T3 查詢帳戶餘額爲 1000 元
T4 查詢帳戶餘額爲 1000 元
T5 匯入 100 元修改餘額爲 1100 元
T6 提交事務
T7 取出 100 元將餘額修改成 900 元
T8 撤銷事務
T9 餘額恢復爲 1000 元(丟失更新)
第 2 類丟失更新:事務 A 覆蓋事務 B 已經提交的數據,形成事務 B 所作的操做丟失。
時間 轉帳事務 A 取款事務 B
T1 開始事務
T2 開始事務
T3 查詢帳戶餘額爲 1000 元
T4 查詢帳戶餘額爲 1000 元
T5 取出 100 元將餘額修改成 900 元
T6 提交事務
T7 匯入 100 元將餘額修改成 1100 元
T8 提交事務
T9 查詢帳戶餘額爲 1100 元(丟失更新)
數據併發訪問所產生的問題,在有些場景下多是容許的,可是有些場景下可能就是致命的,數據庫一般會經過鎖機制來解決數據併發訪問問題,按鎖定對象不一樣能夠分爲表級鎖和行級鎖;按併發事務鎖定關係能夠分爲共享鎖和獨佔鎖,具體的內容你們能夠自行查閱資料進行了解。
直接使用鎖是很是麻煩的,爲此數據庫爲用戶提供了自動鎖機制,只要用戶指定會話的事務隔離級別,數據庫就會經過分析 SQL 語句而後爲事務訪問的資源加上合適的鎖,此外,數據庫還會維護這些鎖經過各類手段提升系統的性能,這些對用戶來講都是透明的(就是說你不用理解,事實上我確實也不知道)。ANSI/ISO
SQL 92 標準定義了 4 個等級的事務隔離級別,以下表所示:
隔離級別 髒讀 不可重複讀 幻讀 第一類丟失更新 第二類丟失更新
READ
UNCOMMITED 容許 容許 容許 不容許 容許
READ
COMMITTED 不容許 容許 容許 不容許 容許
REPEATABLE
READ 不容許 不容許 容許 不容許 不容許
SERIALIZABLE 不容許 不容許 不容許 不容許 不容許
須要說明的是,事務隔離級別和數據訪問的併發性是對立的,事務隔離級別越高併發性就越差。因此要根據具體的應用來肯定合適的事務隔離級別,這個地方沒有萬能的原則。
**8一、JDBC 中如何進行事務處理?
答:
Connection 提供了事務處理的方法,經過調用 setAutoCommit(false)能夠設置手動提交事務;當事務完成後用 commit()顯式提交事務;若是在事務處理過程當中發生異常則經過 rollback()進行事務回滾。除此以外,從 JDBC 3.0 中還引入了
Savepoint(保存點)的概念,容許經過代碼設置保存點並讓事務回滾到指定的保存點。
8二、JDBC 可否處理 Blob 和 Clob?
答:
Blob 是指二進制大對象(Binary Large Object),而 Clob 是指大字符對象(Character Large Objec),所以其中 Blob 是爲存儲大的二進制數據而設計的,而 Clob 是爲存儲大的文本數據而設計的。JDBC 的 PreparedStatement 和 ResultSet 都提供了相應的方法來支持 Blob 和 Clob 操做。下面的代碼展現瞭如何使用 JDBC 操做 LOB:下面以 MySQL 數據庫爲例,建立一個張有三個字段的用戶表,包括編號(id)、姓名(name)和照片(photo),建表語句以下:
create table tb_user
(
id int primary key auto_increment, name varchar(20) unique not null,
photo longblob
);
下面的 Java 代碼向數據庫中插入一條記錄:
import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; class JdbcLobTest {
public static void main(String[] args) { Connection con = null; try {
// 1. 加載驅動(Java6 以上版本能夠省略)
Class.forName("com.mysql.jdbc.Driver");
// 2. 創建鏈接 con =
DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "123456");
// 3. 建立語句對象
PreparedStatement ps = con.prepareStatement("insert into
tb_user values (default, ?, ?)");
ps.setString(1, "駱昊"); // 將 SQL 語句中第一個
佔位符換成字符串
try (InputStream in = new FileInputStream("test.jpg"))
{ // Java 7 的 TWR ps.setBinaryStream(2, in); // 將 SQL語句中第二個佔
位符換成二進制流
// 4. 發出 SQL 語句得到受影響行數
System.out.println(ps.executeUpdate() == 1 ? "插入成功
" : "插入失敗");
} catch(IOException e) {
System.out.println("讀取照片失敗!");
}
} catch (ClassNotFoundException | SQLException e) { // Java
7 的多異常捕獲
e.printStackTrace();
} finally { // 釋放外部資源的代碼都應當放在 finally 中保證其可以得
到執行
try {
if(con != null && !con.isClosed()) {
con.close(); // 5. 釋放數據庫鏈接 con = null; // 指示垃圾回收器能夠回收該對象
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
8三、簡述正則表達式及其用途。
答:
在編寫處理字符串的程序時,常常會有查找符合某些複雜規則的字符串的須要。正則表達式就是用於描述這些規則的工具。換句話說,正則表達式就是記錄文本規則的代碼。
說明:計算機誕生初期處理的信息幾乎都是數值,可是時過境遷,今天咱們使用計算機處理的信息更多的時候不是數值而是字符串,正則表達式就是在進行字符串匹配和處理的時候最爲強大的工具,絕大多數語言都提供了對正則表達式的支持。
8四、Java 中是如何支持正則表達式操做的?
答:
Java 中的 String 類提供了支持正則表達式操做的方法,包括:matches()、
replaceAll()、replaceFirst()、split()。此外,Java 中能夠用 Pattern 類表示正則表達式對象,它提供了豐富的 API 進行各類正則表達式操做,請參考下面面試題的代碼。
面試題: - 若是要從字符串中截取第一個英文左括號以前的字符串,例如:北京市(朝陽區)(西城區)(海淀區),截取結果爲:北京市,那麼正則表達式怎麼寫?
import java.util.regex.Matcher; import java.util.regex.Pattern; class RegExpTest {
public static void main(String[] args) {
String str = "北京市(朝陽區)(西城區)(海淀區)";
Pattern p = Pattern.compile(".*?(?=\()"); Matcher m = p.matcher(str);
if(m.find()) {
System.out.println(m.group());
}
}
}
說明:上面的正則表達式中使用了懶惰匹配和前瞻,若是不清楚這些內容,推薦讀一下網上頗有名的《正則表達式 30 分鐘入門教程》。
8五、得到一個類的類對象有哪些方式?
答:
• 方法 1:類型.class,例如:String.class
• 方法 2:對象.getClass(),例如:」hello」.getClass()
• 方法 3:Class.forName(),例如:Class.forName(「java.lang.String」)
**8六、如何經過反射建立對象?
答:
• 方法 1:經過類對象調用 newInstance()方法,例如:
String.class.newInstance()
• 方法 2:經過類對象的 getConstructor()或 getDeclaredConstructor() 方法得到構造器(Constructor)對象並調用其 newInstance()方法建立對象,
例如:String.class.getConstructor(String.class).newInstance(「Hello」);
**8七、如何經過反射獲取和設置對象私有字段的值?
答:
能夠經過類對象的 getDeclaredField()方法字段(Field)對象,而後再經過字段對象的 setAccessible(true)將其設置爲能夠訪問,接下來就能夠經過 get/set 方法來獲取/設置字段的值了。下面的代碼實現了一個反射的工具類,其中的兩個靜態方法分別用於獲取和設置私有字段的值,字段能夠是基本類型也能夠是對象類
型且支持多級對象操做,例如 ReflectionUtil.get(dog, 「owner.car.engine.id」); 能夠得到 dog 對象的主人的汽車的引擎的 ID 號。
import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList;
import java.util.List;
/**
/ public class ReflectionUtil {
private ReflectionUtil() { throw new AssertionError();
}
/*
Field f = clazz.getDeclaredField(fs[fs.length - 1]); f.setAccessible(true); return f.get(target);
}
catch (Exception e) { throw new RuntimeException(e);
}
}
/**
90、簡述一下你瞭解的設計模式。
答:
所謂設計模式,就是一套被反覆使用的代碼設計經驗的總結(情境中一個問題通過證明的一個解決方案)。使用設計模式是爲了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。設計模式令人們能夠更加簡單方便的複用成功的設計和體系結構。將已證明的技術表述成設計模式也會使新系統開發者更加容易理解其設計思路。
在 GoF 的《Design Patterns: Elements of Reusable Object-Oriented
Software》中給出了三類(建立型[對類的實例化過程的抽象化]、結構型[描述如何將類或對象結合在一塊兒造成更大的結構]、行爲型[對在不一樣的對象之間劃分責任
和算法的抽象化])共 23 種設計模式,包括:Abstract Factory(抽象工廠模式),
Builder(建造者模式),Factory Method(工廠方法模式),Prototype(原始模型模式),Singleton(單例模式);Facade(門面模式),Adapter(適配器模式),Bridge(橋樑模式),Composite(合成模式),Decorator(裝飾模
式),Flyweight(享元模式),Proxy(代理模式);Command(命令模式),
Interpreter(解釋器模式),Visitor(訪問者模式),Iterator(迭代子模式), Mediator(調停者模式),Memento(備忘錄模式),Observer(觀察者模式), State(狀態模式),Strategy(策略模式),Template Method(模板方法模式),
Chain Of Responsibility(責任鏈模式)。
面試被問到關於設計模式的知識時,能夠揀最經常使用的做答,例如:
• 工廠模式:工廠類能夠根據條件生成不一樣的子類實例,這些子類有一個公共的抽象父類而且實現了相同的方法,可是這些方法針對不一樣的數據進行了不一樣的操做(多態方法)。當獲得子類的實例後,開發人員能夠調用基類中的方法而沒必要考慮到底返回的是哪個子類的實例。
• 代理模式:給一個對象提供一個代理對象,並由代理對象控制原對象的引用。實際開發中,按照使用目的的不一樣,代理能夠分爲:遠程代理、虛擬代理、保護代理、Cache 代理、防火牆代理、同步化代理、智能引用代理。
• 適配器模式:把一個類的接口變換成客戶端所期待的另外一種接口,從而使本來因接口不匹配而沒法在一塊兒使用的類可以一塊兒工做。
• 模板方法模式:提供一個抽象類,將部分邏輯以具體方法或構造器的形式實現,而後聲明一些抽象方法來迫使子類實現剩餘的邏輯。不一樣的子類能夠以不一樣的方式實現這些抽象方法(多態實現),從而實現不一樣的業務邏輯。
除此以外,還能夠講講上面提到的門面模式、橋樑模式、單例模式、裝潢模式
(Collections 工具類和 I/O 系統中都使用裝潢模式)等,反正基本原則就是揀本身最熟悉的、用得最多的做答,以避免言多必失。
9一、用 Java 寫一個單例類。
答:
• 餓漢式單例
public class Singleton { private Singleton(){}
private static Singleton instance = new Singleton(); public static Singleton getInstance(){ return instance;
}
}
• 懶漢式單例
public class Singleton { private static Singleton instance = null; private Singleton() {} public static synchronized Singleton getInstance(){ if (instance == null) instance = new Singleton(); return instance;
}
}
注意:實現一個單例有兩點注意事項,①將構造器私有,不容許外界經過構造器建立對象;②經過公開的靜態方法向外界返回類的惟一實例。這裏有一個問題能夠思考:Spring 的 IoC 容器能夠爲普通的類建立單例,它是怎麼作到的呢?
9二、什麼是 UML?
答:
UML 是統一建模語言(Unified Modeling Language)的縮寫,它發表於 1997 年,綜合了當時已經存在的面向對象的建模語言、方法和過程,是一個支持模型化和軟件系統開發的圖形化語言,爲軟件開發的全部階段提供模型化和可視化支持。使用 UML 能夠幫助溝通與交流,輔助應用設計和文檔的生成,還可以闡釋系統的結構和行爲。
9三、UML 中有哪些經常使用的圖?
答:
UML 定義了多種圖形化的符號來描述軟件系統部分或所有的靜態結構和動態結
構,包括:用例圖(use case diagram)、類圖(class diagram)、時序圖(sequence diagram)、協做圖(collaboration diagram)、狀態圖(statechart diagram)、活動圖(activity diagram)、構件圖(component diagram)、部署圖(deployment diagram)等。在這些圖形化符號中,有三種圖最爲重要,分別是:用例圖(用來捕獲需求,描述系統的功能,經過該圖能夠迅速的瞭解系統的功能模塊及其關係)、類圖(描述類以及類與類之間的關係,經過該圖能夠快速瞭解系統)、時序圖(描述執行特定任務時對象之間的交互關係以及執行順序,經過該圖能夠了解對象能接收的消息也就是說對象可以向外界提供的服務)。
用例圖:
類圖:
時序圖:
9四、用 Java 寫一個冒泡排序。
答:
冒泡排序幾乎是個程序員都寫得出來,可是面試的時候如何寫一個逼格高的冒泡排序卻不是每一個人都能作到,下面提供一個參考代碼:
import java.util.Comparator;
/
/ public interface Sorter {
/*
排序
@param list 待排序的數組
/ public <T extends Comparable
/
排序
@param list 待排序的數組
@param comp 比較兩個對象的比較器
/ public
}
import java.util.Comparator;
/
冒泡排序
@author 駱昊
*/ public class BubbleSorter implements Sorter {
@Override
public <T extends Comparable
for (int i = 1, len = list.length; i < len && swapped; ++i) { swapped = false; for (int j = 0; j < len - i; ++j) { if (list[j].compareTo(list[j + 1]) > 0) { T temp = list[j]; list[j] = list[j + 1];
list[j + 1] = temp; swapped = true;
}
}
}
}
@Override public
for (int i = 1, len = list.length; i < len && swapped; ++i) { swapped = false; for (int j = 0; j < len - i; ++j) { if (comp.compare(list[j], list[j + 1]) > 0) { T temp = list[j]; list[j] = list[j + 1]; list[j + 1] = temp; swapped = true;
}
}
}
}
}
9五、用 Java 寫一個折半查找。
答:
折半查找,也稱二分查找、二分搜索,是一種在有序數組中查找某一特定元素的搜索算法。搜素過程從數組的中間元素開始,若是中間元素正好是要查找的元素,則搜素過程結束;若是某一特定元素大於或者小於中間元素,則在數組大於或小於中間元素的那一半中查找,並且跟開始同樣從中間元素開始比較。若是在某一步驟數組已經爲空,則表示找不到指定的元素。這種搜索算法每一次比較都使搜索範圍縮小一半,其時間複雜度是 O(logN)。
import java.util.Comparator; public class MyUtil {
public static <T extends Comparable
key) { return binarySearch(x, 0, x.length- 1, key);
}
// 使用循環實現的二分查找
public static
{
int low = 0; int high = x.length - 1; while (low <= high) { int mid = (low + high) >>> 1; int cmp = comp.compare(x[mid], key);
if (cmp < 0) {
low= mid + 1;
}
else if (cmp > 0) {
high= mid - 1;
}
else { return mid;
}
}
return -1;
}
// 使用遞歸實現的二分查找
private static<T extends Comparable
low, int high, T key) { if(low <= high) {
int mid = low + ((high -low) >> 1); if(key.compareTo(x[mid])== 0) { return mid;
}
else if(key.compareTo(x[mid])< 0) { return binarySearch(x,low, mid - 1, key);
}
else { return binarySearch(x,mid + 1, high, key);
}
}
return -1;
}
}
說明:上面的代碼中給出了折半查找的兩個版本,一個用遞歸實現,一個用循環實現。須要注意的是計算中間位置時不該該使用(high+ low) / 2 的方式,由於加法運算可能致使整數越界,這裏應該使用如下三種方式之一:low + (high - low) / 2 或 low + (high – low) >> 1 或(low + high) >>> 1(>>>是邏輯右移,是不帶符號位的右移)
Java 面試題(二)
下面列出這份 Java 面試問題列表包含的主題
• 多線程,併發及線程基礎
• 數據類型轉換的基本原則
• 垃圾回收(GC)
• Java 集合框架
• 數組
• 字符串
• GOF 設計模式
• SOLID
• 抽象類與接口
• Java 基礎,如 equals 和 hashcode
• 泛型與枚舉
• Java IO 與 NIO
• 經常使用網絡協議
• Java 中的數據結構和算法
• 正則表達式
• JVM 底層
• Java 最佳實踐
• JDBC
• Date, Time 與 Calendar
• Java 處理 XML
• JUnit • 編程
如今是時候給你展現我近 5 年從各類面試中收集來的 133 個問題了。我肯定你在本身的面試中見過不少這些問題,不少問題你也能正確回答。
多線程、併發及線程的基礎問題
一、Java 中能建立 volatile 數組嗎?
能,Java 中能夠建立 volatile 類型數組,不過只是一個指向數組的引用,而不是整個數組。個人意思是,若是改變引用指向的數組,將會受到 volatile 的保護,可是若是多個線程同時改變數組的元素,volatile 標示符就不能起到以前的保護做用了。
二、volatile 能使得一個非原子操做變成原子操做嗎?
一個典型的例子是在類中有一個 long 類型的成員變量。若是你知道該成員變量會被多個線程訪問,如計數器、價格等,你最好是將其設置爲 volatile。爲何?由於 Java 中讀取 long 類型變量不是原子的,須要分紅兩步,若是一個線程正在修改該 long 變量的值,另外一個線程可能只能看到該值的一半(前 32 位)。
可是對一個 volatile 型的 long 或 double 變量的讀寫是原子。
三、volatile 修飾符的有過什麼實踐?
一種實踐是用 volatile 修飾 long 和 double 變量,使其能按原子類型來讀寫。 double 和 long 都是 64 位寬,所以對這兩種類型的讀是分爲兩部分的,第一次讀取第一個 32 位,而後再讀剩下的 32 位,這個過程不是原子的,但 Java 中 volatile 型的 long 或 double 變量的讀寫是原子的。volatile 修復符的另外一個做用是提供內存屏障(memory barrier),例如在分佈式框架中的應用。簡單的說,就是當你寫一個 volatile 變量以前,Java 內存模型會插入一個寫屏障(write barrier),讀一個 volatile 變量以前,會插入一個讀屏障(read barrier)。意思就是說,在你寫一個 volatile 域時,能保證任何線程都能看到你寫的值,同時,在寫以前,也能保證任何數值的更新對全部線程是可見的,由於內存屏障會將其餘全部寫的值更新到緩存。
四、volatile 類型變量提供什麼保證?
volatile 變量提供順序和可見性保證,例如,JVM 或者 JIT 爲了得到更好的性能會對語句重排序,可是 volatile 類型變量即便在沒有同步塊的狀況下賦值也不會與其餘語句重排序。 volatile 提供 happens-before 的保證,確保一個線程的修改能對其餘線程是可見的。某些狀況下,volatile 還能提供原子性,如讀 64 位數據類型,像 long 和 double 都不是原子的,但 volatile 類型的 double 和 long 就是原子的。
五、10 個線程和 2 個線程的同步代碼,哪一個更容易寫?
從寫代碼的角度來講,二者的複雜度是相同的,由於同步代碼與線程數量是相互獨立的。可是同步策略的選擇依賴於線程的數量,由於越多的線程意味着更大的競爭,因此你須要利用同步技術,如鎖分離,這要求更復雜的代碼和專業知識。
六、你是如何調用 wait()方法的?使用 if 塊仍是循環?爲何?
wait() 方法應該在循環調用,由於當線程獲取到 CPU 開始執行的時候,其餘條件可能尚未知足,因此在處理前,循環檢測條件是否知足會更好。下面是一段標準的使用 wait 和 notify 方法的代碼:
// The standard idiom for using the wait method synchronized (obj) {
while (condition does not hold) obj.wait(); // (Releases lock, and reacquires on wakeup)
... // Perform action appropriate to condition
}
參見 [Effective Java]第 69 條,獲取更多關於爲何應該在循環中來調用 wait 方法的內容。
僞共享是多線程系統(每一個處理器有本身的局部緩存)中一個衆所周知的性能問題。僞共享發生在不一樣處理器的上的線程對變量的修改依賴於相同的緩存行,以下圖所示:
有經驗程序員的 Java 面試題
僞共享問題很難被發現,由於線程可能訪問徹底不一樣的全局變量,內存中卻碰巧在很相近的位置上。如其餘諸多的併發問題,避免僞共享的最基本方式是仔細審查代碼,根據緩存行來調整你的數據結構。
八、什麼是 Busy spin?咱們爲何要使用它?
Busy spin 是一種在不釋放 CPU 的基礎上等待事件的技術。它常常用於避免丟失 CPU 緩存中的數據(若是線程先暫停,以後在其餘 CPU 上運行就會丟失)。因此,若是你的工做要求低延遲,而且你的線程目前沒有任何順序,這樣你就能夠經過循環檢測隊列中的新消息來代替調用 sleep() 或 wait() 方法。它惟一的好處就是你只需等待很短的時間,如幾微秒或幾納秒。LMAX 分佈式框架是一個高性能線程間通訊的庫,該庫有一個 BusySpinWaitStrategy 類就是基於這個概念實現的,使用 busy spin 循環 EventProcessors 等待屏障。
九、Java 中怎麼獲取一份線程 dump 文件?
在 Linux 下,你能夠經過命令 kill -3 PID (Java 進程的進程 ID)來獲取 Java 應用的 dump 文件。在 Windows 下,你能夠按下 Ctrl + Break 來獲取。這樣 JVM 就會將線程的 dump 文件打印到標準輸出或錯誤文件中,它可能打印在控制檯或者日誌文件中,具體位置依賴應用的配置。若是你使用 Tomcat。
十、Swing 是線程安全的?
不是,Swing 不是線程安全的。你不能經過任何線程來更新 Swing 組件,如
JTable、JList 或 JPanel,事實上,它們只能經過 GUI 或 AWT 線程來更新。這就是爲何 Swing 提供 invokeAndWait() 和 invokeLater() 方法來獲取其餘線程的 GUI 更新請求。這些方法將更新請求放入 AWT 的線程隊列中,能夠一直等待,也能夠經過異步更新直接返回結果。你也能夠在參考答案中查看和學習到更詳細的內容。
十一、什麼是線程局部變量?
線程局部變量是侷限於線程內部的變量,屬於線程自身全部,不在多個線程間共享。Java 提供 ThreadLocal 類來支持線程局部變量,是一種實現線程安全的方式。可是在管理環境下(如 web 服務器)使用線程局部變量的時候要特別當心,在這種狀況下,工做線程的生命週期比任何應用變量的生命週期都要長。任何線程局部變量一旦在工做完成後沒有釋放,Java 應用就存在內存泄露的風險。
十二、用 wait-notify 寫一段代碼來解決生產者-消費者問題?
答案
http://java67.blogspot.sg/2012/12/producer-consumer-problem-with-wai t-and-notify-example.html
請參考答案中的示例代碼。只要記住在同步塊中調用 wait() 和 notify()方法,若是阻塞,經過循環來測試等待條件。
1三、用 Java 寫一個線程安全的單例模式(Singleton)?
答案
http://javarevisited.blogspot.in/2012/12/how-to-create-thread-safe-singl eton-in-java-example.html
請參考答案中的示例代碼,這裏面一步一步教你建立一個線程安全的 Java 單例類。當咱們說線程安全時,意思是即便初始化是在多線程環境中,仍然能保證單個實例。Java 中,使用枚舉做爲單例類是最簡單的方式來建立線程安全單例模式的方式。
1四、Java 中 sleep 方法和 wait 方法的區別?
雖然二者都是用來暫停當前運行的線程,可是 sleep() 實際上只是短暫停頓,由於它不會釋放鎖,而 wait() 意味着條件等待,這就是爲何該方法要釋放鎖,由於只有這樣,其餘等待的線程才能在知足條件時獲取到該鎖。
1五、什麼是不可變對象(immutable object)?Java 中怎麼建立一個不可變對象?
不可變對象指對象一旦被建立,狀態就不能再改變。任何修改都會建立一個新的對象,如 String、Integer 及其它包裝類。詳情參見答案,一步一步指導你在 Java 中建立一個不可變的類。
1六、咱們能建立一個包含可變對象的不可變對象嗎?
是的,咱們是能夠建立一個包含可變對象的不可變對象的,你只須要謹慎一點,不要共享可變對象的引用就能夠了,若是須要變化時,就返回原對象的一個拷貝。
最多見的例子就是對象中包含一個日期對象的引用。
數據類型和 Java 基礎面試問題
1七、Java 中應該使用什麼數據類型來表明價格?
若是不是特別關心內存和性能的話,使用 BigDecimal,不然使用預約義精度的 double 類型。
1八、怎麼將 byte 轉換爲 String?
能夠使用 String 接收 byte[] 參數的構造器來進行轉換,須要注意的點是要使用的正確的編碼,不然會使用平臺默認編碼,這個編碼可能跟原來的編碼相同,也可能不一樣。
1九、 Java 中怎樣將 bytes 轉換爲 long 類型?
這個問題你來回答 😃
20、 咱們能將 int 強制轉換爲 byte 類型的變量嗎?若是該值
大於 byte 類型的範圍,將會出現什麼現象?
是的,咱們能夠作強制轉換,可是 Java 中 int 是 32 位的,而 byte 是 8 位的,因此,若是強制轉化是,int 類型的高 24 位將會被丟棄,byte 類型的範圍是從 -128 到 128。
2一、存在兩個類,B 繼承 A,C 繼承 B,咱們能將 B 轉換爲 C 麼?如 C = (C) B;
答案
http://javarevisited.blogspot.sg/2012/12/what-is-type-casting-in-java-cla ss-interface-example.html
2二、哪一個類包含 clone 方法?是 Cloneable 仍是 Object?
java.lang.Cloneable 是一個標示性接口,不包含任何方法,clone 方法在 object 類中定義。而且須要知道 clone() 方法是一個本地方法,這意味着它是由 c 或 c++ 或 其餘本地語言實現的。
2三、Java 中 ++ 操做符是線程安全的嗎?
答案:不是線程安全的操做。它涉及到多個指令,如讀取變量值,增長,而後存儲回內存,這個過程可能會出現多個線程交差。
2三、不是線程安全的操做。它涉及到多個指令,如讀取變量值,增長,而後存儲回內存,這個過程可能會出現多個線程交差。
2四、a = a + b 與 a += b 的區別
+= 隱式的將加操做的結果類型強制轉換爲持有結果的類型。若是兩這個整型相加,如 byte、short 或者 int,首先會將它們提高到 int 類型,而後在執行加法操做。若是加法操做的結果比 a 的最大值要大,則 a+b 會出現編譯錯誤,可是 a += b 沒問題,以下:
byte a = 127; byte b = 127;
b = a + b; // error : cannot convert from int to byte b += a; // ok
(譯者注:這個地方應該表述的有誤,其實不管 a+b 的值爲多少,編譯器都會報錯,由於 a+b 操做會將 a、b 提高爲 int 類型,因此將 int 類型賦值給 byte 就會編譯出錯)
2五、我能在不進行強制轉換的狀況下將一個 double 值賦值給
long 類型的變量嗎?
不行,你不能在沒有強制類型轉換的前提下將一個 double 值賦值給 long 類型的變量,由於 double 類型的範圍比 long 類型更廣,因此必需要進行強制轉換。
2六、30.1 == 0.3 將會返回什麼?true 仍是 false?
false,由於有些浮點數不能徹底精確的表示出來。
2七、int 和 Integer 哪一個會佔用更多的內存?
Integer 對象會佔用更多的內存。Integer 是一個對象,須要存儲對象的元數據。
可是 int 是一個原始類型的數據,因此佔用的空間更少。
2八、爲何 Java 中的 String 是不可變的(Immutable)?
Java 中的 String 不可變是由於 Java 的設計者認爲字符串使用很是頻繁,將字符串設置爲不可變能夠容許多個客戶端之間共享相同的字符串。
2九、 咱們能在 Switch 中使用 String 嗎?
從 Java 7 開始,咱們能夠在 switch case 中使用字符串,但這僅僅是一個語法糖。內部實如今 switch 中使用字符串的 hash code。
30、 Java 中的構造器鏈是什麼?
當你從一個構造器中調用另外一個構造器,就是 Java 中的構造器鏈。這種狀況只在重載了類的構造器的時候纔會出現。
JVM 底層 與 GC(Garbage Collection) 的面試問題
3一、64 位 JVM 中,int 的長度是多數?
Java 中,int 類型變量的長度是一個固定值,與平臺無關,都是 32 位。意思就是說,在 32 位 和 64 位 的 Java 虛擬機中,int 類型的長度是相同的。
3二、Serial 與 Parallel GC 之間的不一樣之處?
Serial 與 Parallel 在 GC 執行的時候都會引發 stop-the-world。它們之間主要不一樣 serial 收集器是默認的複製收集器,執行 GC 的時候只有一個線程,而 parallel 收集器使用多個 GC 線程來執行。
3三、32 位和 64 位的 JVM,int 類型變量的長度是多數?
32 位和 64 位的 JVM 中,int 類型變量的長度是相同的,都是 32 位或者 4 個字節。
3四、Java 中 WeakReference 與 SoftReference 的區別?
雖然 WeakReference 與 SoftReference 都有利於提升 GC 和 內存的效率,可是 WeakReference ,一旦失去最後一個強引用,就會被 GC 回收,而軟引用雖然不能阻止被回收,可是能夠延遲到 JVM 內存不足的時候。
3五、WeakHashMap 是怎麼工做的?
WeakHashMap 的工做與正常的 HashMap 相似,可是使用弱引用做爲 key,意思就是當 key 對象沒有任何引用時,key/value 將會被回收。
3六、JVM 選項 -XX:+UseCompressedOops 有什麼做用?爲何要使用?
當你將你的應用從 32 位的 JVM 遷移到 64 位的 JVM 時,因爲對象的指針從 32 位增長到了 64 位,所以堆內存會忽然增長,差很少要翻倍。這也會對 CPU 緩存(容量比內存小不少)的數據產生不利的影響。由於,遷移到 64 位的 JVM 主要動機在於能夠指定最大堆大小,經過壓縮 OOP 能夠節省必定的內存。經過 -XX:+UseCompressedOops 選項,JVM 會使用 32 位的 OOP,而不是 64 位的 OOP。
3七、怎樣經過 Java 程序來判斷 JVM 是 32 位 仍是 64 位?
你能夠檢查某些系統屬性如 sun.arch.data.model 或 os.arch 來獲取該信息。
3八、32 位 JVM 和 64 位 JVM 的最大堆內存分別是多數?
理論上說上 32 位的 JVM 堆內存能夠到達 2^32,即 4GB,但實際上會比這個小不少。不一樣操做系統之間不一樣,如 Windows 系統大約 1.5 GB,Solaris 大約 3GB。64 位 JVM 容許指定最大的堆內存,理論上能夠達到 2^64,這是一個很是大的數字,實際上你能夠指定堆內存大小到 100GB。甚至有的 JVM,如 Azul,堆內存到 1000G 都是可能的。
3九、JRE、JDK、JVM 及 JIT 之間有什麼不一樣?
JRE 表明 Java 運行時(Java run-time),是運行 Java 引用所必須的。JDK 表明 Java 開發工具(Java development kit),是 Java 程序的開發工具,如 Java 編譯器,它也包含 JRE。JVM 表明 Java 虛擬機(Java virtual machine),它的責任是運行 Java 應用。JIT 表明即時編譯(Just In Time compilation),當代碼執行的次數超過必定的閾值時,會將 Java 字節碼轉換爲本地代碼,如,主要的熱點代碼會被準換爲本地代碼,這樣有利大幅度提升 Java 應用的性能。
3 年工做經驗的 Java 面試題
40、解釋 Java 堆空間及 GC?
當經過 Java 命令啓動 Java 進程的時候,會爲它分配內存。內存的一部分用於建立堆空間,當程序中建立對象的時候,就從對空間中分配內存。GC 是 JVM 內部的一個進程,回收無效對象的內存用於未來的分配。
JVM 底層面試題及答案
4一、你能保證 GC 執行嗎?
不能,雖然你能夠調用 System.gc() 或者 Runtime.gc(),可是沒有辦法保證 GC 的執行。
4二、怎麼獲取 Java 程序使用的內存?堆使用的百分比?
能夠經過 java.lang.Runtime 類中與內存相關方法來獲取剩餘的內存,總內存及最大堆內存。經過這些方法你也能夠獲取到堆使用的百分比及堆內存的剩餘空間。
Runtime.freeMemory() 方法返回剩餘空間的字節數,Runtime.totalMemory() 方法總內存的字節數,Runtime.maxMemory() 返回最大內存的字節數。
4三、Java 中堆和棧有什麼區別?
JVM 中堆和棧屬於不一樣的內存區域,使用目的也不一樣。棧經常使用於保存方法幀和局部變量,而對象老是在堆上分配。棧一般都比堆小,也不會在多個線程之間共享,而堆被整個 JVM 的全部線程共享。關於內存的的面試問題和答案
Java 基本概念面試題
4四、「ab」和」a.equals(b)」有什麼區別?
若是 a 和 b 都是對象,則 ab 是比較兩個對象的引用,只有當 a 和 b 指向的是堆中的同一個對象纔會返回 true,而 a.equals(b) 是進行邏輯比較,因此一般須要重寫該方法來提供邏輯一致性的比較。例如,String 類重寫 equals() 方法,因此能夠用於兩個不一樣對象,可是包含的字母相同的比較。
4五、a.hashCode() 有什麼用?與 a.equals(b) 有什麼關係?
hashCode() 方法是相應對象整型的 hash 值。它經常使用於基於 hash 的集合類,如 Hashtable、HashMap、LinkedHashMap 等等。它與 equals() 方法關係特別緊密。根據 Java 規範,兩個使用 equal() 方法來判斷相等的對象,必須具備相同的 hash code。
4六、final、finalize 和 finally 的不一樣之處?
final 是一個修飾符,能夠修飾變量、方法和類。若是 final 修飾變量,意味着該變量的值在初始化後不能被改變。finalize 方法是在對象被回收以前調用的方法,給對象本身最後一個復活的機會,可是何時調用 finalize 沒有保證。finally 是一個關鍵字,與 try 和 catch 一塊兒用於異常的處理。finally 塊必定會被執行,不管在 try 塊中是否有發生異常。
4七、Java 中的編譯期常量是什麼?使用它又什麼風險?
公共靜態不可變(public static final )變量也就是咱們所說的編譯期常量,這裏的 public 可選的。實際上這些變量在編譯時會被替換掉,由於編譯器知道這些變量的值,而且知道這些變量在運行時不能改變。這種方式存在的一個問題是你使用了一個內部的或第三方庫中的公有編譯時常量,可是這個值後面被其餘人改變了,可是你的客戶端仍然在使用老的值,甚至你已經部署了一個新的 jar。爲了不這種狀況,當你在更新依賴 JAR 文件時,確保從新編譯你的程序。
Java 集合框架的面試題
這部分也包含數據結構、算法及數組的面試問題
4八、List、Set、Map 和 Queue 之間的區別(答案)
List 是一個有序集合,容許元素重複。它的某些實現能夠提供基於下標值的常量訪問時間,可是這不是 List 接口保證的。Set 是一個無序集合。
4九、poll() 方法和 remove() 方法的區別?
poll() 和 remove() 都是從隊列中取出一個元素,可是 poll() 在獲取元素失敗的時候會返回空,可是 remove() 失敗的時候會拋出異常。
50、Java 中 LinkedHashMap 和 PriorityQueue 的區別是什麼?
PriorityQueue 保證最高或者最低優先級的的元素老是在隊列頭部,可是
LinkedHashMap 維持的順序是元素插入的順序。當遍歷一個 PriorityQueue
時,沒有任何順序保證,可是 LinkedHashMap 課保證遍歷順序是元素插入的順序。
5一、ArrayList 與 LinkedList 的不區別?
最明顯的區別是 ArrrayList 底層的數據結構是數組,支持隨機訪問,而
LinkedList 的底層數據結構書鏈表,不支持隨機訪問。使用下標訪問一個元素, ArrayList 的時間複雜度是 O(1),而 LinkedList 是 O(n)。更多細節的討論參見答案。
5二、用哪兩種方式來實現集合的排序?
你能夠使用有序集合,如 TreeSet 或 TreeMap,你也能夠使用有順序的的集合,如 list,而後經過 Collections.sort() 來排序。
5三、Java 中怎麼打印數組?
你能夠使用 Arrays.toString() 和 Arrays.deepToString() 方法來打印數組。因爲數組沒有實現 toString() 方法,因此若是將數組傳遞給 System.out.println() 方法,將沒法打印出數組的內容,可是 Arrays.toString() 能夠打印每一個元素。
5四、Java 中的 LinkedList 是單向鏈表仍是雙向鏈表?
是雙向鏈表,你能夠檢查 JDK 的源碼。在 Eclipse,你能夠使用快捷鍵 Ctrl + T,直接在編輯器中打開該類。
5五、Java 中的 TreeMap 是採用什麼樹實現的?(答案)
Java 中的 TreeMap 是使用紅黑樹實現的。
5六、Hashtable 與 HashMap 有什麼不一樣之處?
這兩個類有許多不一樣的地方,下面列出了一部分:
a) Hashtable 是 JDK 1 遺留下來的類,而 HashMap 是後來增長的。
b)Hashtable 是同步的,比較慢,但 HashMap 沒有同步策略,因此會更快。 c)Hashtable 不容許有個空的 key,可是 HashMap 容許出現一個 null key。
更多的不一樣之處參見答案。
5七、Java 中的 HashSet,內部是如何工做的?
HashSet 的內部採用 HashMap 來實現。因爲 Map 須要 key 和 value,因此全部 key 的都有一個默認 value。相似於 HashMap,HashSet 不容許重複的 key,只容許有一個 null key,意思就是 HashSet 中只容許存儲一個 null 對象。
5八、寫一段代碼在遍歷 ArrayList 時移除一個元素?
該問題的關鍵在於面試者使用的是 ArrayList 的 remove() 仍是 Iterator 的 remove()方法。這有一段示例代碼,是使用正確的方式來實如今遍歷的過程當中移除元素,而不會出現 ConcurrentModificationException 異常的示例代碼。
5九、咱們能本身寫一個容器類,而後使用 for-each 循環碼?
能夠,你能夠寫一個本身的容器類。若是你想使用 Java 中加強的循環來遍歷,你只須要實現 Iterable 接口。若是你實現 Collection 接口,默認就具備該屬性。 60、ArrayList 和 HashMap 的默認大小是多數?
在 Java 7 中,ArrayList 的默認大小是 10 個元素,HashMap 的默認大小是 16 個元素(必須是 2 的冪)。這就是 Java 7 中 ArrayList 和 HashMap 類的代碼片斷:
// from ArrayList.java JDK 1.7 private static final int DEFAULT_CAPACITY = 10;
//from HashMap.java JDK 7
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
6一、有沒有可能兩個不相等的對象有有相同的 hashcode?
有可能,兩個不相等的對象可能會有相同的 hashcode 值,這就是爲何在 hashmap 中會有衝突。相等 hashcode 值的規定只是說若是兩個對象相等,必須有相同的 hashcode 值,可是沒有關於不相等對象的任何規定。 6二、兩個相同的對象會有不一樣的的 hash code 嗎?
不能,根據 hash code 的規定,這是不可能的。
6三、咱們能夠在 hashcode() 中使用隨機數字嗎?
答案
http://javarevisited.blogspot.sg/2011/10/override-hashcode-in-java-exam ple.html
不行,由於對象的 hashcode 值必須是相同的。參見答案獲取更多關於 Java 中重寫 hashCode() 方法的知識。
6四、Java 中,Comparator 與 Comparable 有什麼不一樣?
Comparable 接口用於定義對象的天然順序,而 comparator 一般用於定義用戶定製的順序。Comparable 老是隻有一個,可是能夠有多個 comparator 來定義對象的順序。
65)爲何在重寫 equals 方法的時候須要重寫 hashCode 方法?(答案) 由於有強制的規範指定須要同時重寫 hashcode 與 equal 是方法,許多容器類,如 HashMap、HashSet 都依賴於 hashcode 與 equals 的規定。
Java IO 和 NIO 的面試題
IO 是 Java 面試中一個很是重要的點。你應該很好掌握 Java IO,NIO,NIO2 以及與操做系統,磁盤 IO 相關的基礎知識。下面是 Java IO 中常常問的問題。
6六、在我 Java 程序中,我有三個 socket,我須要多少個線程來處理?
6七、Java 中怎麼建立 ByteBuffer?
byte[] bytes = new byte[10];
ByteBuffer buf = ByteBuffer.wrap(bytes);
6八、 Java 中,怎麼讀寫 ByteBuffer ?
6九、 Java 採用的是大端仍是小端?
70、 ByteBuffer 中的字節序是什麼?
7一、Java 中,直接緩衝區與非直接緩衝器有什麼區別?
答案
http://javarevisited.blogspot.sg/2015/08/difference-between-direct-nondirect-mapped-bytebuffer-nio-java.html
7二、Java 中的內存映射緩存區是什麼?
答案
http://javarevisited.blogspot.sg/2012/01/memorymapped-file-and-io-in-j ava.html
7三、socket 選項 TCP NO DELAY 是指什麼?
7四、TCP 協議與 UDP 協議有什麼區別?
答案
http://javarevisited.blogspot.com/2014/07/9-difference-between-tcp-and -udp-protocol.html
7五、Java 中,ByteBuffer 與 StringBuffer 有什麼區別?(答
案)
Java 最佳實踐的面試問題
包含 Java 中各個部分的最佳實踐,如集合,字符串,IO,多線程,錯誤和異常處理,設計模式等等。
7六、Java 中,編寫多線程程序的時候你會遵循哪些最佳實踐?
這是我在寫 Java 併發程序的時候遵循的一些最佳實踐: a)給線程命名,這樣能夠幫助調試。
b) 最小化同步的範圍,而不是將整個方法同步,只對關鍵部分作同步。
c) 若是能夠,更偏向於使用 volatile 而不是 synchronized。
d) 使用更高層次的併發工具,而不是使用 wait() 和 notify() 來實現線程間通訊,如 BlockingQueue,CountDownLatch 及 Semeaphore。
e) 優先使用併發集合,而不是對集合進行同步。併發集合提供更好的可擴展性。
7七、說出幾點 Java 中使用 Collections 的最佳實踐
這是我在使用 Java 中 Collectionc 類的一些最佳實踐:
a) 使用正確的集合類,例如,若是不須要同步列表,使用 ArrayList 而不是
Vector。
b) 優先使用併發集合,而不是對集合進行同步。併發集合提供更好的可擴展性。
c) 使用接口表明和訪問集合,如使用 List 存儲 ArrayList,使用 Map 存儲
HashMap 等等。
d) 使用迭代器來循環集合。
e) 使用集合的時候使用泛型。
7八、說出至少 5 點在 Java 中使用線程的最佳實踐。
答案
http://java67.blogspot.com/2014/01/10-points-about-thread-and-javalan gthread-in-java.html
這個問題與以前的問題相似,你能夠使用上面的答案。對線程來講,你應該: a)對線程命名 b)將線程和任務分離,使用線程池執行器來執行 Runnable 或 Callable。 c)使用線程池
7九、說出 5 條 IO 的最佳實踐(答案)
IO 對 Java 應用的性能很是重要。理想狀況下,你不該該在你應用的關鍵路徑上避免 IO 操做。下面是一些你應該遵循的 Java IO 最佳實踐: a)使用有緩衝區的 IO 類,而不要單獨讀取字節或字符。
b)使用 NIO 和 NIO2 c)在 finally 塊中關閉流,或者使用 try-with-resource 語句。 d)使用內存映射文件獲取更快的 IO。
80、列出 5 個應該遵循的 JDBC 最佳實踐
答案
http://javarevisited.blogspot.sg/2012/08/top-10-jdbc-best-practices-for-j ava.html))
有不少的最佳實踐,你能夠根據你的喜愛來例舉。下面是一些更通用的原則: a)使用批量的操做來插入和更新數據
b) 使用 PreparedStatement 來避免 SQL 異常,並提升性能。
c) 使用數據庫鏈接池
d) 經過列名來獲取結果集,不要使用列的下標來獲取。
8一、說出幾條 Java 中方法重載的最佳實踐?
下面有幾條能夠遵循的方法重載的最佳實踐來避免形成自動裝箱的混亂。
a) 不要重載這樣的方法:一個方法接收 int 參數,而另個方法接收 Integer 參數。
b) 不要重載參數數量一致,而只是參數順序不一樣的方法。c)若是重載的方法參數個數多於 5 個,採用可變參數。
Date、Time 及 Calendar 的面試題
8二、在多線程環境下,SimpleDateFormat 是線程安全的嗎?
不是,很是不幸,DateFormat 的全部實現,包括 SimpleDateFormat 都不是線程安全的,所以你不該該在多線程序中使用,除非是在對外線程安全的環境中使用,如 將 SimpleDateFormat 限制在 ThreadLocal 中。若是你不這麼作,在解析或者格式化日期的時候,可能會獲取到一個不正確的結果。所以,從日期、時間處理的全部實踐來講,我強力推薦 joda-time 庫。
8三、Java 中如何格式化一個日期?如格式化爲 ddMMyyyy 的形式?
答案
http://javarevisited.blogspot.com/2011/09/convert-date-to-string-simple dateformat.html
Java 中,能夠使用 SimpleDateFormat 類或者 joda-time 庫來格式日期。 DateFormat 類容許你使用多種流行的格式來格式化日期。參見答案中的示例代碼,代碼中演示了將日期格式化成不一樣的格式,如 dd-MM-yyyy 或 ddMMyyyy。
8四、Java 中,怎麼在格式化的日期中顯示時區?
答案
http://java67.blogspot.sg/2013/01/how-to-format-date-in-java-simpledat eformat-example.html
8五、Java 中 java.util.Date 與 java.sql.Date 有什麼區別?
答案
http://java67.blogspot.sg/2014/02/how-to-convert-javautildate-to-javasq ldate-example.html
8六、Java 中,如何計算兩個日期之間的差距?
程序
http://javarevisited.blogspot.sg/2015/07/how-to-find-number-of-days-be tween-two-dates-in-java.html
8七、Java 中,如何將字符串 YYYYMMDD 轉換爲日期?
答案
http://java67.blogspot.sg/2014/12/string-to-date-example-in-java-multit hreading.html
單元測試 JUnit 面試題
8九、如何測試靜態方法?(答案)
能夠使用 PowerMock 庫來測試靜態方法。
90、怎麼利用 JUnit 來測試一個方法的異常?
答案
http://javarevisited.blogspot.sg/2013/04/JUnit-tutorial-example-test-exce ption-thrown-by-java-method.html
9一、你使用過哪一個單元測試庫來測試你的 Java 程序?
9二、@Before 和 @BeforeClass 有什麼區別?
答案 http://javarevisited.blogspot.sg/2013/04/JUnit-tutorial-example-test-exce ption-thrown-by-java-method.html
編程和代碼相關的面試題
9三、怎麼檢查一個字符串只包含數字?解決方案
http://java67.blogspot.com/2014/01/java-regular-expression-to-check-nu mbers-in-String.html
9四、Java 中如何利用泛型寫一個 LRU 緩存?
9五、寫一段 Java 程序將 byte 轉換爲 long?
9五、在不使用 StringBuffer 的前提下,怎麼反轉一個字符串?
解決方案
http://java67.blogspot.com/2012/12/how-to-reverse-string-in-java-string buffer-stringbuilder.htm
9七、Java 中,怎麼獲取一個文件中單詞出現的最高頻率?
解決方案 http://java67.blogspot.com/2015/10/java-program-to-find-repeated-wor ds-and-count.html
9八、如何檢查出兩個給定的字符串是反序的?
解決方案
http://javarevisited.blogspot.sg/2013/03/Anagram-how-to-check-if-two-s tring-are-anagrams-example-tutorial.html
9九、Java 中,怎麼打印出一個字符串的全部排列?
解決方案
http://javarevisited.blogspot.com/2015/08/how-to-find-all-permutationsof-string-java-example.html
100、Java 中,怎樣才能打印出數組中的重複元素?
解決方案
http://javarevisited.blogspot.com/2015/06/3-ways-to-find-duplicate-elem ents-in-array-java.html
10一、Java 中如何將字符串轉換爲整數?
String s="123"; int i;
第一種方法:i=Integer.parseInt(s);
第二種方法:i=Integer.valueOf(s).intValue();
10二、在沒有使用臨時變量的狀況如何交換兩個整數變量的值?
解決方案
https://blog.csdn.net/zidane_2014/article/details/34180223 關於 OOP 和設計模式的面試題
這部分包含 Java 面試過程當中關於 SOLID 的設計原則,OOP 基礎,如類,對象,接口,繼承,多態,封裝,抽象以及更高級的一些概念,如組合、聚合及關聯。
也包含了 GOF 設計模式的問題。
10三、接口是什麼?爲何要使用接口而不是直接使用具體類?
接口用於定義 API。它定義了類必須得遵循的規則。同時,它提供了一種抽象,由於客戶端只使用接口,這樣能夠有多重實現,如 List 接口,你能夠使用可隨機訪問的 ArrayList,也能夠使用方便插入和刪除的 LinkedList。接口中不容許寫代碼,以此來保證抽象,可是 Java 8 中你能夠在接口聲明靜態的默認方法,這種方法是具體的。
10四、Java 中,抽象類與接口之間有什麼不一樣?
Java 中,抽象類和接口有不少不一樣之處,可是最重要的一個是 Java 中限制一個類只能繼承一個類,可是能夠實現多個接口。抽象類能夠很好的定義一個家族類的默認行爲,而接口能更好的定義類型,有助於後面實現多態機制。
10五、除了單例模式,你在生產環境中還用過什麼設計模式?
這須要根據你的經驗來回答。通常狀況下,你能夠說依賴注入,工廠模式,裝飾模式或者觀察者模式,隨意選擇你使用過的一種便可。不過你要準備回答接下的基於你選擇的模式的問題。
10六、你能解釋一下里氏替換原則嗎?
答案
https://blog.csdn.net/pu_xubo565599455/article/details/51488323
107) 什麼狀況下會違反迪米特法則?爲何會有這個問題?
迪米特法則建議「只和朋友說話,不要陌生人說話」,以此來減小類之間的耦合。
10八、適配器模式是什麼?何時使用?
適配器模式提供對接口的轉換。若是你的客戶端使用某些接口,可是你有另一些接口,你就能夠寫一個適配去來鏈接這些接口。
10九、什麼是「依賴注入」和「控制反轉」?爲何有人使用?
控制反轉(IOC)是 Spring 框架的核心思想,用我本身的話說,就是你要作一件事,別本身可勁 new 了,你就說你要幹啥,而後外包出去就好~
依賴注入(DI) 在我淺薄的想法中,就是經過接口的引用和構造方法的表達,將一些事情整好了反過來傳給須要用到的地方~
1十、抽象類是什麼?它與接口有什麼區別?你爲何要使用過抽象類?
接口用於規範,抽象類用於共性.
聲明方法的存在而不去實現它的類被叫作抽象類
接口(interface)是抽象類的變體。在接口中,全部方法都是抽象的。
1十一、構造器注入和 setter 依賴注入,那種方式更好?
每種方式都有它的缺點和優勢。構造器注入保證全部的注入都被初始化,可是 setter 注入提供更好的靈活性來設置可選依賴。若是使用 XML 來描述依賴,
Setter 注入的可讀寫會更強。經驗法則是強制依賴使用構造器注入,可選依賴使用 setter 注入。
1十二、依賴注入和工程模式之間有什麼不一樣?
雖然兩種模式都是將對象的建立從應用的邏輯中分離,可是依賴注入比工程模式更清晰。經過依賴注入,你的類就是 POJO,它只知道依賴而不關心它們怎麼獲取。使用工廠模式,你的類須要經過工廠來獲取依賴。所以,使用 DI 會比使用工廠模式更容易測試。
11三、適配器模式和裝飾器模式有什麼區別?
雖然適配器模式和裝飾器模式的結構相似,可是每種模式的出現意圖不一樣。適配器模式被用於橋接兩個接口,而裝飾模式的目的是在不修改類的狀況下給類增長新的功能。
11四、適配器模式和代理模式以前有什麼不一樣?
這個問題與前面的相似,適配器模式和代理模式的區別在於他們的意圖不一樣。因爲適配器模式和代理模式都是封裝真正執行動做的類,所以結構是一致的,可是適配器模式用於接口之間的轉換,而代理模式則是增長一個額外的中間層,以便支持分配、控制或智能訪問。
11五、什麼是模板方法模式?
模板方法提供算法的框架,你能夠本身去配置或定義步驟。例如,你能夠將排序算法看作是一個模板。它定義了排序的步驟,可是具體的比較,能夠使用
Comparable 或者其語言中相似東西,具體策略由你去配置。列出算法概要的方法就是衆所周知的模板方法。
11六、何時使用訪問者模式?
訪問者模式用於解決在類的繼承層次上增長操做,可是不直接與之關聯。這種模式採用雙派發的形式來增長中間層。
11七、何時使用組合模式?
組合模式使用樹結構來展現部分與總體繼承關係。它容許客戶端採用統一的形式來對待單個對象和對象容器。當你想要展現對象這種部分與總體的繼承關係時採用組合模式。
11八、繼承和組合之間有什麼不一樣?
雖然兩種均可以實現代碼複用,可是組合比繼承共靈活,由於組合容許你在運行時選擇不一樣的實現。用組合實現的代碼也比繼承測試起來更加簡單。
11九、描述 Java 中的重載和重寫?
重載和重寫都容許你用相同的名稱來實現不一樣的功能,可是重載是編譯時活動,而重寫是運行時活動。你能夠在同一個類中重載方法,可是隻能在子類中重寫方法。重寫必需要有繼承。
120、Java 中,嵌套公共靜態類與頂級類有什麼不一樣?
類的內部能夠有多個嵌套公共靜態類,可是一個 Java 源文件只能有一個頂級公共類,而且頂級公共類的名稱與源文件名稱必須一致。
12一、 OOP 中的 組合、聚合和關聯有什麼區別?
若是兩個對象彼此有關係,就說他們是彼此相關聯的。組合和聚合是面向對象中的兩種形式的關聯。組合是一種比聚合更強力的關聯。組合中,一個對象是另外一個的擁有者,而聚合則是指一個對象使用另外一個對象。若是對象 A 是由對象 B 組合的,則 A 不存在的話,B 必定不存在,可是若是 A 對象聚合了一個對象 B,則即便 A 不存在了,B 也能夠單獨存在。
12二、給我一個符合開閉原則的設計模式的例子?
開閉原則要求你的代碼對擴展開放,對修改關閉。這個意思就是說,若是你想增長一個新的功能,你能夠很容易的在不改變已測試過的代碼的前提下增長新的代碼。有好幾個設計模式是基於開閉原則的,如策略模式,若是你須要一個新的策略,只須要實現接口,增長配置,不須要改變核心邏輯。一個正在工做的例子是
Collections.sort() 方法,這就是基於策略模式,遵循開閉原則的,你不需爲新的對象修改 sort() 方法,你須要作的僅僅是實現你本身的 Comparator 接口。
12三、抽象工廠模式和原型模式之間的區別?
抽象工廠模式:一般由工廠方法模式來實現。但一個工廠中每每含有多個工廠方法生成一系列的產品。這個模式強調的是客戶代碼一次保證只使用一個系列的產品。當要切換爲另外一個系列的產品,換一個工廠類便可。
原型模式:工廠方法的最大缺點就是,對應一個繼承體系的產品類,要有一個一樣複雜的工廠類的繼承體系。咱們能夠把工廠類中的工廠方法放到產品類自身之中嗎?若是這樣的話,就能夠將兩個繼承體系爲一個。這也就是原型模式的思想,原型模式中的工廠方法爲 clone,它會返回一個拷貝(能夠是淺拷貝,也能夠是深拷貝,由設計者決定)。爲了保證用戶代碼中到時能夠經過指針調用 clone 來動態綁定地生成所需的具體的類。這些原型對象必須事先構造好。
原型模式想對工廠方法模式的另外一個好處是,拷貝的效率通常對構造的效率要高。
12四、何時使用享元模式?享元模式經過共享對象來避免建立太多的對象。爲了使用享元模式,你須要確保你的對象是不可變的,這樣你才能安全的共享。JDK 中 String 池、Integer 池以及 Long 池都是很好的使用了享元模式的例子。
Java 面試中其餘各式各樣的問題
這部分包含 Java 中關於 XML 的面試題,正則表達式面試題,Java 錯誤和異常及序列化面試題
12五、嵌套靜態類與頂級類有什麼區別?
一個公共的頂級類的源文件名稱與類名相同,而嵌套靜態類沒有這個要求。一個
嵌套類位於頂級類內部,須要使用頂級類的名稱來引用嵌套靜態類,如
HashMap.Entry 是一個嵌套靜態類,HashMap 是一個頂級類,Entry 是一個嵌套靜態類。
12六、你能寫出一個正則表達式來判斷一個字符串是不是一個數字嗎?
一個數字字符串,只能包含數字,如 0 到 9 以及 +、- 開頭,經過這個信息,你能夠下一個以下的正則表達式來判斷給定的字符串是否是數字。
首先要 import java.util.regex.Pattern 和 java.util.regex.Matcher public boolean isNumeric(String str){
Pattern pattern = Pattern.compile("[0-9]"); Matcher isNum = pattern.matcher(str); if( !isNum.matches() ){
return false;
}
return true;
}
12七、Java 中,受檢查異常 和 不受檢查異常的區別?
受檢查異常編譯器在編譯期間檢查。對於這種異常,方法強制處理或者經過 throws 子句聲明。其中一種狀況是 Exception 的子類但不是
RuntimeException 的子類。非受檢查是 RuntimeException 的子類,在編譯階段不受編譯器的檢查。
12八、Java 中,throw 和 throws 有什麼區別
throw 用於拋出 java.lang.Throwable 類的一個實例化對象,意思是說你能夠經過關鍵字 throw 拋出一個 Error 或者 一個 Exception,如:
throw new IllegalArgumentException(「size must be multiple of 2″)
而 throws 的做用是做爲方法聲明和簽名的一部分,方法被拋出相應的異常以便調用者能處理。Java 中,任何未處理的受檢查異常強制在 throws 子句中聲明。
12九、Java 中,Serializable 與 Externalizable 的區別?
Serializable 接口是一個序列化 Java 類的接口,以便於它們能夠在網絡上傳輸
或者能夠將它們的狀態保存在磁盤上,是 JVM 內嵌的默認序列化方式,成本高、脆弱並且不安全。Externalizable 容許你控制整個序列化過程,指定特定的二進制格式,增長安全機制。
130、Java 中,DOM 和 SAX 解析器有什麼不一樣?
DOM 解析器將整個 XML 文檔加載到內存來建立一棵 DOM 模型樹,這樣能夠更快的查找節點和修改 XML 結構,而 SAX 解析器是一個基於事件的解析器,不會將整個 XML 文檔加載到內存。因爲這個緣由,DOM 比 SAX 更快,也要求更多的內存,不適合於解析大 XML 文件。
13一、說出 JDK 1.7 中的三個新特性?
雖然 JDK 1.7 不像 JDK 5 和 8 同樣的大版本,可是,仍是有不少新的特性,如 try-with-resource 語句,這樣你在使用流或者資源的時候,就不須要手動關閉,Java 會自動關閉。Fork-Join 池某種程度上實現 Java 版的 Map-reduce。
容許 Switch 中有 String 變量和文本。菱形操做符(<>)用於類型推斷,再也不須要在變量聲明的右邊申明泛型,所以能夠寫出可讀寫更強、更簡潔的代碼。另外一個值得一提的特性是改善異常處理,如容許在同一個 catch 塊中捕獲多個異常。
13二、說出 5 個 JDK 1.8 引入的新特性?
Java 8 在 Java 歷史上是一個開創新的版本,下面 JDK 8 中 5 個主要的特性:
Lambda 表達式,容許像對象同樣傳遞匿名函數
Stream API,充分利用現代多核 CPU,能夠寫出很簡潔的代碼
Date 與 Time API,最終,有一個穩定、簡單的日期和時間庫可供你使用擴展方法,如今,接口中能夠有靜態、默認方法。
重複註解,如今你能夠將相同的註解在同一類型上使用屢次。
13三、Java 中,Maven 和 ANT 有什麼區別?
雖然二者都是構建工具,都用於建立 Java 應用,可是 Maven 作的事情更多,在基於「約定優於配置」的概念下,提供標準的 Java 項目結構,同時能爲應用自動管理依賴(應用中所依賴的 JAR 文件),Maven 與 ANT 工具更多的不一樣之處請參見答案。
這就是全部的面試題,如此之多,是否是?我能夠保證,若是你能回答列表中的全部問題,你就能夠很輕鬆的應付任何核心 Java 或者高級 Java 面試。雖然,這裏沒有涵蓋 Servlet、JSP、JSF、JPA,JMS,EJB 及其它 Java EE 技術,也沒有包含主流的框架如 Spring MVC,Struts 2.0,Hibernate,也沒有包含 SOAP 和 RESTful web service,可是這份列表對作 Java 開發的、準備應聘 Java web 開發職位的人仍是一樣有用的,由於全部的 Java 面試,開始的問題都是 Java 基礎和 JDK API 相關的。若是你認爲我這裏有任何應該在這份列表中而被我遺漏了的 Java 流行的問題,你能夠自由的給我建議。個人目的是從最近的面試中建立一份最新的、最優的 Java 面試問題列表。
Spring 面試題(一)
一、通常問題
1.一、不一樣版本的 Spring Framework 有哪些主要功能?
Version Feature
Spring 2.5 發佈於 2007 年。這是第一個支持註解的版本。
Spring 3.0 發佈於 2009 年。它徹底利用了 Java5 中的改進,併爲 JEE6 提供了支持。
Spring 4.0 發佈於 2013 年。這是第一個徹底支持 JAVA8 的版本。
1.二、什麼是 Spring Framework?
Spring 是一個開源應用框架,旨在下降應用程序開發的複雜度。它是輕量級、鬆散耦合的。它具備分層體系結構,容許用戶選擇組件,同時還爲 J2EE 應用程序
開發提供了一個有凝聚力的框架。它能夠集成其餘框架,如 Structs、Hibernate、
EJB 等,因此又稱爲框架的框架。
1.三、列舉 Spring Framework 的優勢。
因爲 Spring Frameworks 的分層架構,用戶能夠自由選擇本身須要的組件。
Spring Framework 支持 POJO(Plain Old Java Object) 編程,從而具有持續集成和可測試性。因爲依賴注入和控制反轉,JDBC 得以簡化。它是開源免費的。
1.四、Spring Framework 有哪些不一樣的功能?
輕量級 - Spring 在代碼量和透明度方面都很輕便。IOC - 控制反轉 AOP - 面向切面編程能夠將應用業務邏輯和系統服務分離,以實現高內聚。容器 - Spring 負責建立和管理對象(Bean)的生命週期和配置。MVC - 對 web 應用提供了高度可配置性,其餘框架的集成也十分方便。事務管理 - 提供了用於事務管理的通用抽象層。Spring 的事務支持也可用於容器較少的環境。JDBC 異常 - Spring 的 JDBC 抽象層提供了一個異常層次結構,簡化了錯誤處理策略。
1.五、Spring Framework 中有多少個模塊,它們分別是什麼?
Spring 核心容器 – 該層基本上是 Spring Framework 的核心。它包含如下模塊:
• Spring Core
• Spring Bean
• SpEL (Spring Expression Language)
• Spring Context
數據訪問/集成 – 該層提供與數據庫交互的支持。它包含如下模塊:
• JDBC (Java DataBase Connectivity)
• ORM (Object Relational Mapping)
• OXM (Object XML Mappers)
• JMS (Java Messaging Service)
• Transaction
Web – 該層提供了建立 Web 應用程序的支持。它包含如下模塊:
• Web
• Web – Servlet • Web – Socket
• Web – Portlet
AOP
• 該層支持面向切面編程
Instrumentation
• 該層爲類檢測和類加載器實現提供支持。
Test
• 該層爲使用 JUnit 和 TestNG 進行測試提供支持。幾個雜項模塊:
Messaging – 該模塊爲 STOMP 提供支持。它還支持註解編程模型,該模型用於從 WebSocket 客戶端路由和處理 STOMP 消息。
Aspects – 該模塊爲與 AspectJ 的集成提供支持。
1.六、什麼是 Spring 配置文件?
Spring 配置文件是 XML 文件。該文件主要包含類信息。它描述了這些類是如何配置以及相互引入的。可是,XML 配置文件冗長且更加乾淨。若是沒有正確規劃和編寫,那麼在大項目中管理變得很是困難。
1.七、Spring 應用程序有哪些不一樣組件?
Spring 應用通常有如下組件:
• 接口 - 定義功能。
• Bean 類 - 它包含屬性,setter 和 getter 方法,函數等。
• Spring 面向切面編程(AOP) - 提供面向切面編程的功能。
• Bean 配置文件 - 包含類的信息以及如何配置它們。
• 用戶程序 - 它使用接口。
1.八、使用 Spring 有哪些方式?
使用 Spring 有如下方式:
• 做爲一個成熟的 Spring Web 應用程序。
• 做爲第三方 Web 框架,使用 Spring Frameworks 中間層。
• 用於遠程使用。
• 做爲企業級 Java Bean,它能夠包裝現有的 POJO(Plain Old Java
Objects)。
二、依賴注入(Ioc)
2.一、什麼是 Spring IOC 容器?
Spring 框架的核心是 Spring 容器。容器建立對象,將它們裝配在一塊兒,配置它們並管理它們的完整生命週期。Spring 容器使用依賴注入來管理組成應用程序的組件。容器經過讀取提供的配置元數據來接收對象進行實例化,配置和組裝的指令。該元數據能夠經過 XML,Java 註解或 Java 代碼提供。
2.二、什麼是依賴注入?
在依賴注入中,您沒必要建立對象,但必須描述如何建立它們。您不是直接在代碼中將組件和服務鏈接在一塊兒,而是描述配置文件中哪些組件須要哪些服務。由 IoC 容器將它們裝配在一塊兒。
2.三、能夠經過多少種方式完成依賴注入?
一般,依賴注入能夠經過三種方式完成,即:
• 構造函數注入
• setter 注入
• 接口注入
在 Spring Framework 中,僅使用構造函數和 setter 注入。
2.四、區分構造函數注入和 setter 注入。
構造函數注入 setter 注入
沒有部分注入 有部分注入
不會覆蓋 setter 屬性 會覆蓋 setter 屬性
任意修改都會建立一個新實例 任意修改不會建立一個新實例
適用於設置不少屬性 適用於設置少許屬性
2.五、spring 中有多少種 IOC 容器?
BeanFactory - BeanFactory 就像一個包含 bean 集合的工廠類。它會在客戶端要求時實例化 bean。
ApplicationContext - ApplicationContext 接口擴展了 BeanFactory 接口。它在 BeanFactory 基礎上提供了一些額外的功能。
2.六、區分 BeanFactory 和 ApplicationContext。
BeanFactory ApplicationContext
它使用懶加載 它使用即時加載
它使用語法顯式提供資源對象 它本身建立和管理資源對象
不支持國際化 支持國際化
不支持基於依賴的註解 支持基於依賴的註解
2.七、列舉 IoC 的一些好處。
IoC 的一些好處是:
• 它將最小化應用程序中的代碼量。
• 它將使您的應用程序易於測試,由於它不須要單元測試用例中的任何單例或 JNDI 查找機制。
• 它以最小的影響和最少的侵入機制促進鬆耦合。
• 它支持即時的實例化和延遲加載服務。
2.八、Spring IoC 的實現機制。
Spring 中的 IoC 的實現原理就是工廠模式加反射機制。
示例:
interface Fruit { public abstract void eat();
}
class Apple implements Fruit { public void eat(){
System.out.println("Apple");
}
}
class Orange implements Fruit { public void eat(){
System.out.println("Orange");
}
}
class Factory { public static Fruit getInstance(String ClassName) { Fruit f=null; try { f=(Fruit)Class.forName(ClassName).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return f;
}
}
class Client { public static void main(String[] a) {
Fruit f=Factory.getInstance("io.github.dunwu.spring.Apple"); if(f!=null){
f.eat();
}
}
}
三、Beans
3.一、什麼是 spring bean?
• 它們是構成用戶應用程序主幹的對象。
• Bean 由 Spring IoC 容器管理。
• 它們由 Spring IoC 容器實例化,配置,裝配和管理。
• Bean 是基於用戶提供給容器的配置元數據建立。
3.二、spring 提供了哪些配置方式?
基於 xml 配置
bean 所需的依賴項和服務在 XML 格式的配置文件中指定。這些配置文件一般包含許多 bean 定義和特定於應用程序的配置選項。它們一般以 bean 標籤開頭。例如:
基於註解配置
您能夠經過在相關的類,方法或字段聲明上使用註解,將 bean 配置爲組件類自己,而不是使用 XML 來描述 bean 裝配。默認狀況下,Spring 容器中未打開註解裝配。所以,您須要在使用它以前在 Spring 配置文件中啓用它。例如:
context:annotation-config/
3.五、什麼是 spring 的內部 bean?
只有將 bean 用做另外一個 bean 的屬性時,才能將 bean 聲明爲內部 bean。爲了定義 bean,Spring 的基於 XML 的配置元數據在
例如,假設咱們有一個 Student 類,其中引用了 Person 類。這裏咱們將只建立一個 Person 類實例並在 Student 中使用它。
Student.java
public class Student { private Person person; //Setters and Getters
}
public class Person { private String name; private String address;
//Setters and Getters
}
bean.xml
<bean id=「StudentBean" class="com.edureka.Student">
5.三、spring JDBC API 中存在哪些類?
• JdbcTemplate
• SimpleJdbcTemplate
• NamedParameterJdbcTemplate
• SimpleJdbcInsert
• SimpleJdbcCall
5.四、使用 Spring 訪問 Hibernate 的方法有哪些?
咱們能夠經過兩種方式使用 Spring 訪問 Hibernate:
一、 使用 Hibernate 模板和回調進行控制反轉
二、 擴展 HibernateDAOSupport 並應用 AOP 攔截器節點
5.五、列舉 spring 支持的事務管理類型
Spring 支持兩種類型的事務管理:
一、 程序化事務管理:在此過程當中,在編程的幫助下管理事務。它爲您提供極大的靈活性,但維護起來很是困難。
二、 聲明式事務管理:在此,事務管理與業務代碼分離。僅使用註解或基於 XML 的配置來管理事務。
5.六、spring 支持哪些 ORM 框架
• Hibernate
• iBatis
• JPA
• JDO
• OJB
六、AOP
6.一、什麼是 AOP?
AOP(Aspect-Oriented Programming), 即 面向切面編程, 它與
OOP( Object-Oriented Programming, 面向對象編程) 相輔相成, 提供了與
OOP 不一樣的抽象軟件結構的視角. 在 OOP 中, 咱們以類(class)做爲咱們的基本單元, 而 AOP 中的基本單元是 Aspect(切面)
6.二、什麼是 Aspect?
aspect 由 pointcount 和 advice 組成, 它既包含了橫切邏輯的定義, 也包括了鏈接點的定義. Spring AOP 就是負責實施切面的框架, 它將切面所定義的橫切邏輯編織到切面所指定的鏈接點中. AOP 的工做重心在於如何將加強編織目標對象的鏈接點上, 這裏包含兩個工做:
一、如何經過 pointcut 和 advice 定位到特定的 joinpoint 上 二、如何在 advice 中編寫切面代碼.
能夠簡單地認爲, 使用 @Aspect 註解的類就是切面.
6.三、什麼是切點(JoinPoint)
程序運行中的一些時間點, 例如一個方法的執行, 或者是一個異常的處理.
在 Spring AOP 中, join point 老是方法的執行點。
6.四、什麼是通知(Advice)?
特定 JoinPoint 處的 Aspect 所採起的動做稱爲 Advice。Spring AOP 使用一個 Advice 做爲攔截器,在 JoinPoint 「周圍」維護一系列的攔截器。
6.五、有哪些類型的通知(Advice)?
• Before - 這些類型的 Advice 在 joinpoint 方法以前執行,並使用
@Before 註解標記進行配置。
• After Returning - 這些類型的 Advice 在鏈接點方法正常執行後執行,並使用@AfterReturning 註解標記進行配置。
• After Throwing - 這些類型的 Advice 僅在 joinpoint 方法經過拋出異常退出並使用 @AfterThrowing 註解標記配置時執行。
• After (finally) - 這些類型的 Advice 在鏈接點方法以後執行,不管方法退出是正常仍是異常返回,並使用 @After 註解標記進行配置。
• Around - 這些類型的 Advice 在鏈接點以前和以後執行,並使用
@Around 註解標記進行配置。
6.六、 指出在 spring aop 中 concern 和 cross-cutting concern 的不一樣之處。
concern 是咱們想要在應用程序的特定模塊中定義的行爲。它能夠定義爲咱們想要實現的功能。
cross-cutting concern 是一個適用於整個應用的行爲,這會影響整個應用程序。例如,日誌記錄,安全性和數據傳輸是應用程序幾乎每一個模塊都須要關注的問題,所以它們是跨領域的問題。
6.七、 AOP 有哪些實現方式?實現 AOP 的技術,主要分爲兩大類:靜態代理
指使用 AOP 框架提供的命令進行編譯,從而在編譯階段就可生成 AOP 代理類,所以也稱爲編譯時加強;
• 編譯時編織(特殊編譯器實現)
• 類加載時編織(特殊的類加載器實現)。
動態代理
在運行時在內存中「臨時」生成 AOP 動態代理類,所以也被稱爲運行時加強。
• JDK 動態代理
• CGLIB
6.八、Spring AOP and AspectJ AOP 有什麼區別?
Spring AOP 基於動態代理方式實現;AspectJ 基於靜態代理方式實現。Spring AOP 僅支持方法級別的 PointCut;提供了徹底的 AOP 支持,它還支持屬性級別的 PointCut。
6.九、如何理解 Spring 中的代理?
將 Advice 應用於目標對象後建立的對象稱爲代理。在客戶端對象的狀況下,目標對象和代理對象是相同的。
Advice + Target Object = Proxy
6.十、什麼是編織(Weaving)?
爲了建立一個 advice 對象而連接一個 aspect 和其它應用類型或對象,稱爲編織(Weaving)。在 Spring AOP 中,編織在運行時執行。請參考下圖:
七、MVC
7.一、Spring MVC 框架有什麼用?
Spring Web MVC 框架提供 模型-視圖-控制器 架構和隨時可用的組件,用於開發靈活且鬆散耦合的 Web 應用程序。MVC 模式有助於分離應用程序的不一樣方面,如輸入邏輯,業務邏輯和 UI 邏輯,同時在全部這些元素之間提供鬆散耦合。
7.二、描述一下 DispatcherServlet 的工做流程
DispatcherServlet 的工做流程能夠用一幅圖來講明:
一、 向服務器發送 HTTP 請求,請求被前端控制器 DispatcherServlet 捕獲。
二、 DispatcherServlet 根據 -servlet.xml 中的配置對請求的 URL 進行解析,獲得請求資源標識符(URI)。而後根據該 URI,調用 HandlerMapping 得到該 Handler 配置的全部相關的對象(包括 Handler 對象以及 Handler 對象對應的攔截器),最後以 HandlerExecutionChain 對象的形式返回。
三、 DispatcherServlet 根據得到的 Handler,選擇一個合適的 HandlerAdapter。(附註:若是成功得到 HandlerAdapter 後,此時將開始執行攔截器的 preHandler(...)方法)。
四、 提取 Request 中的模型數據,填充 Handler 入參,開始執行 Handler ( Controller)。在填充 Handler 的入參過程當中,根據你的配置,Spring 將
幫你作一些額外的工做:
• HttpMessageConveter:將請求消息(如 Json、xml 等數據)轉換成一個對象,將對象轉換爲指定的響應信息。
• 數據轉換:對請求消息進行數據轉換。如 String 轉換成 Integer、
Double 等。
• 數據根式化:對請求消息進行數據格式化。如將字符串轉換成格式化數字或格式化日期等。
• 數據驗證:驗證數據的有效性(長度、格式等),驗證結果存儲到
BindingResult 或 Error 中。
五、 Handler(Controller)執行完成後,向 DispatcherServlet 返回一個 ModelAndView 對象;
六、 根據返回的 ModelAndView,選擇一個適合的 ViewResolver(必須是已經註冊到 Spring 容器中的 ViewResolver)返回給 DispatcherServlet。
七、 ViewResolver 結合 Model 和 View,來渲染視圖。
八、 視圖負責將渲染結果返回給客戶端。
7.三、介紹一下 WebApplicationContext
WebApplicationContext 是 ApplicationContext 的擴展。它具備 Web 應用程序所需的一些額外功能。它與普通的 ApplicationContext 在解析主題和決定與哪一個 servlet 關聯的能力方面有所不一樣。
英文原文連接:
https://www.edureka.co/blog/interview-questions/spring-interview-questi ons/
Spring 面試題(二)
一、什麼是 spring?
Spring 是個 java 企業級應用的開源開發框架。Spring 主要用來開發 Java 應用,
可是有些擴展是針對構建 J2EE 平臺的 web 應用。Spring 框架目標是簡化 Java 企業級應用開發,並經過 POJO 爲基礎的編程模型促進良好的編程習慣。
二、使用 Spring 框架的好處是什麼?
• 輕量:Spring 是輕量的,基本的版本大約 2MB。
• 控制反轉:Spring 經過控制反轉實現了鬆散耦合,對象們給出它們的依賴,而不是建立或查找依賴的對象們。
• 面向切面的編程(AOP):Spring 支持面向切面的編程,而且把應用業務邏輯和系統服務分開。
• 容器:Spring 包含並管理應用中對象的生命週期和配置。
• MVC 框架:Spring 的 WEB 框架是個精心設計的框架,是 Web 框架的一個很好的替代品。
• 事務管理:Spring 提供一個持續的事務管理接口,能夠擴展到上至本地事務下至全局事務(JTA)。
• 異常處理:Spring 提供方便的API把具體技術相關的異常(好比由JDBC,
Hibernate or JDO 拋出的)轉化爲一致的 unchecked 異常。
三、 Spring 由哪些模塊組成?
如下是 Spring 框架的基本模塊:
• Core module
• Bean module
• Context module
• Expression Language module
• JDBC module • ORM module • OXM module
• Java Messaging Service(JMS) module
• Transaction module
• Web module
• Web-Servlet module
• Web-Struts module
• Web-Portlet module
四、 核心容器(應用上下文) 模塊。
這是基本的 Spring 模塊,提供 spring 框架的基礎功能,BeanFactory 是 任何以 spring 爲基礎的應用的核心。Spring 框架創建在此模塊之上,它使 Spring 成爲一個容器。
五、 BeanFactory – BeanFactory 實現舉例。
Bean 工廠是工廠模式的一個實現,提供了控制反轉功能,用來把應用的配置和依賴從正真的應用代碼中分離。
最經常使用的 BeanFactory 實現是 XmlBeanFactory 類。
六、XMLBeanFactory
最經常使用的就是 org.springframework.beans.factory.xml.XmlBeanFactory ,它根據 XML 文件中的定義加載 beans。該容器從 XML 文件讀取配置元數據並用它去建立一個徹底配置的系統或應用。
七、解釋 AOP 模塊
AOP 模塊用於發給咱們的 Spring 應用作面向切面的開發, 不少支持由 AOP 聯盟提供,這樣就確保了 Spring 和其餘 AOP 框架的共通性。這個模塊將元數據編程引入 Spring。
八、 解釋 JDBC 抽象和 DAO 模塊。
經過使用 JDBC 抽象和 DAO 模塊,保證數據庫代碼的簡潔,並能避免數據庫資源錯誤關閉致使的問題,它在各類不一樣的數據庫的錯誤信息之上,提供了一個統一的異常訪問層。它還利用 Spring 的 AOP 模塊給 Spring 應用中的對象提供事務管理服務。
九、 解釋對象/關係映射集成模塊。
Spring 經過提供 ORM 模塊,支持咱們在直接 JDBC 之上使用一個對象/關係映射映射(ORM)工具,Spring 支持集成主流的 ORM 框架,如 Hiberate,JDO 和 iBATIS
SQL Maps。Spring 的事務管理一樣支持以上全部 ORM 框架及 JDBC。
十、 解釋 WEB 模塊。
Spring 的 WEB 模塊是構建在 application context 模塊基礎之上,提供一個適合 web 應用的上下文。這個模塊也包括支持多種面向 web 的任務,如透明地處理
多個文件上傳請求和程序級請求參數的綁定到你的業務對象。它也有對 Jakarta
Struts 的支持。
十二、Spring 配置文件
Spring 配置文件是個 XML 文件,這個文件包含了類信息,描述瞭如何配置它們,以及如何相互調用。
1三、什麼是 Spring IOC 容器?
Spring IOC 負責建立對象,管理對象(經過依賴注入(DI),裝配對象,配置對象,而且管理這些對象的整個生命週期。
1四、IOC 的優勢是什麼?
IOC 或 依賴注入把應用的代碼量降到最低。它使應用容易測試,單元測試再也不須要單例和 JNDI 查找機制。最小的代價和最小的侵入性使鬆散耦合得以實現。IOC 容器支持加載服務時的餓漢式初始化和懶加載。
1五、ApplicationContext 一般的實現是什麼?
• FileSystemXmlApplicationContext :此容器從一個 XML 文件中加載 beans 的定義,XML Bean 配置文件的全路徑名必須提供給它的構造函數。
• ClassPathXmlApplicationContext:此容器也從一個 XML 文件中加載 beans 的定義,這裏,你須要正確設置 classpath 由於這個容器將在 classpath 裏找 bean 配置。
• WebXmlApplicationContext:此容器加載一個 XML 文件,此文件定義了一個 WEB 應用的全部 bean。
1六、Bean 工廠和 Application contexts 有什麼區別?
Application contexts 提供一種方法處理文本消息,一個一般的作法是加載文件資源(好比鏡像),它們能夠向註冊爲監聽器的 bean 發佈事件。另外,在容器或容器內的對象上執行的那些不得不禁 bean 工廠以程序化方式處理的操做,能夠在
Application contexts 中以聲明的方式處理。Application contexts 實現了
MessageSource 接口,該接口的實現以可插拔的方式提供獲取本地化消息的方法。
1七、一個 Spring 的應用看起來象什麼?
• 一個定義了一些功能的接口。
• 這實現包括屬性,它的 Setter , getter 方法和函數等。
• Spring AOP。
• Spring 的 XML 配置文件。 • 使用以上功能的客戶端程序。
依賴注入
1八、什麼是 Spring 的依賴注入?
依賴注入,是 IOC 的一個方面,是個一般的概念,它有多種解釋。這概念是說你不用建立對象,而只須要描述它如何被建立。你不在代碼裏直接組裝你的組件和服務,可是要在配置文件裏描述哪些組件須要哪些服務,以後一個容器(IOC 容器)負責把他們組裝起來。
1九、有哪些不一樣類型的 IOC(依賴注入)方式?
• 構造器依賴注入:構造器依賴注入經過容器觸發一個類的構造器來實現的,該類有一系列參數,每一個參數表明一個對其餘類的依賴。
• Setter 方法注入:Setter 方法注入是容器經過調用無參構造器或無參 static 工廠 方法實例化 bean 以後,調用該 bean 的 setter 方法,即實現了基於 setter 的依賴注入。
20、哪一種依賴注入方式你建議使用,構造器注入,仍是 Setter 方法注入?
你兩種依賴方式均可以使用,構造器注入和 Setter 方法注入。最好的解決方案是用構造器參數實現強制依賴,setter 方法實現可選依賴。
Spring Beans
21.什麼是 Spring beans?
Spring beans 是那些造成 Spring 應用的主幹的 java 對象。它們被 Spring IOC 容器初始化,裝配,和管理。這些 beans 經過容器中配置的元數據建立。好比,以 XML 文件中 的形式定義。
Spring 框架定義的 beans 都是單件 beans。在 bean tag 中有個屬性」
singleton」,若是它被賦爲 TRUE,bean 就是單件,不然就是一個 prototype bean。默認是 TRUE,因此全部在 Spring 框架中的 beans 缺省都是單件。
2二、一個 Spring Bean 定義 包含什麼?
一個 Spring Bean 的定義包含容器必知的全部配置元數據,包括如何建立一個 bean,它的生命週期詳情及它的依賴。
2三、 如何給 Spring 容器提供配置元數據?
這裏有三種重要的方法給 Spring 容器提供配置元數據。
XML 配置文件。
基於註解的配置。基於 java 的配置。
2四、 你怎樣定義類的做用域?
當定義一個 在 Spring 裏,咱們還能給這個 bean 聲明一個做用域。它能夠經過 bean 定義中的 scope 屬性來定義。如,當 Spring 要在須要的時候每次生產一個新的 bean 實例,bean 的 scope 屬性被指定爲 prototype。另外一方面,一個 bean 每次使用的時候必須返回同一個實例,這個 bean 的 scope 屬性 必須設爲 singleton。
2五、 解釋 Spring 支持的幾種 bean 的做用域。
Spring 框架支持如下五種 bean 的做用域:
• singleton : bean 在每一個 Spring ioc 容器中只有一個實例。
• prototype:一個 bean 的定義能夠有多個實例。
• request:每次 http 請求都會建立一個 bean,該做用域僅在基於 web 的 Spring ApplicationContext 情形下有效。
• session:在一個 HTTP Session 中,一個 bean 定義對應一個實例。該做用域僅在基於 web 的 Spring ApplicationContext 情形下有效。
• global-session:在一個全局的 HTTP Session 中,一個 bean 定義對應一個實例。該做用域僅在基於 web 的 Spring ApplicationContext 情形下有效。缺省的 Spring bean 的做用域是 Singleton.
2六、 Spring 框架中的單例 bean 是線程安全的嗎?
不,Spring 框架中的單例 bean 不是線程安全的。
2七、 解釋 Spring 框架中 bean 的生命週期。
• Spring 容器 從 XML 文件中讀取 bean 的定義,並實例化 bean。
• Spring 根據 bean 的定義填充全部的屬性。
• 若是 bean 實現了 BeanNameAware 接口,Spring 傳遞 bean 的 ID 到 setBeanName 方法。
• 若是 Bean 實現了 BeanFactoryAware 接口, Spring 傳遞 beanfactory 給 setBeanFactory 方法。
• 若是有任何與 bean 相關聯的 BeanPostProcessors,Spring 會在 postProcesserBeforeInitialization()方法內調用它們。
• 若是 bean 實現 IntializingBean 了,調用它的 afterPropertySet 方法,若是 bean 聲明瞭初始化方法,調用此初始化方法。
• 若是有 BeanPostProcessors 和 bean 關聯,這些 bean 的 postProcessAfterInitialization() 方法將被調用。
• 若是 bean 實現了 DisposableBean,它將調用 destroy()方法。
2八、哪些是重要的 bean 生命週期方法?你能重載它們嗎?
有兩個重要的 bean 生命週期方法,第一個是 setup , 它是在容器加載 bean 的時候被調用。第二個方法是 teardown 它是在容器卸載類的時候被調用。
The bean 標籤有兩個重要的屬性(init-method 和 destroy-method)。用它們你能夠本身定製初始化和註銷方法。它們也有相應的註解(@PostConstruct 和
@PreDestroy)。
2九、什麼是 Spring 的內部 bean?
當一個 bean 僅被用做另外一個 bean 的屬性時,它能被聲明爲一個內部 bean,爲了定義 inner bean,在 Spring 的 基於 XML 的 配置元數據中,能夠在 或 元素內使用 元素,內部 bean 一般是匿名的,它們的 Scope 通常是 prototype。
30、在 Spring 中如何注入一個 java 集合?
Spring 提供如下幾種集合的配置元素:
• 類型用於注入一列值,容許有相同的值。
• 類型用於注入一組值,不容許有相同的值。
• 類型用於注入一組鍵值對,鍵和值均可覺得任意類型。
• 類型用於注入一組鍵值對,鍵和值都只能爲 String 類型。
3一、什麼是 bean 裝配?
裝配,或 bean 裝配是指在 Spring 容器中把 bean 組裝到一塊兒,前提是容器須要知道 bean 的依賴關係,如何經過依賴注入來把它們裝配到一塊兒。
3二、什麼是 bean 的自動裝配?
Spring 容器可以自動裝配相互合做的 bean,這意味着容器不須要和配置,能經過 Bean 工廠自動處理 bean 之間的協做。
3三、解釋不一樣方式的自動裝配 。
有五種自動裝配的方式,能夠用來指導 Spring 容器用自動裝配方式來進行依賴注入。
• no:默認的方式是不進行自動裝配,經過顯式設置 ref 屬性來進行裝配。 • byName:經過參數名 自動裝配,Spring 容器在配置文件中發現 bean 的 autowire 屬性被設置成 byname,以後容器試圖匹配、裝配和該 bean 的屬性具備相同名字的 bean。
• byType::經過參數類型自動裝配,Spring 容器在配置文件中發現 bean 的 autowire 屬性被設置成 byType,以後容器試圖匹配、裝配和該 bean 的屬性具備相同類型的 bean。若是有多個 bean 符合條件,則拋出錯誤。
• constructor:這個方式相似於 byType, 可是要提供給構造器參數,若是沒有肯定的帶參數的構造器參數類型,將會拋出異常。
• autodetect:首先嚐試使用 constructor 來自動裝配,若是沒法工做,則使用 byType 方式。
34.自動裝配有哪些侷限性 ?
自動裝配的侷限性是:
• 重寫:你仍需用 和 配置來定義依賴,意味着總要重寫自動裝配。
• 基本數據類型:你不能自動裝配簡單的屬性,如基本數據類型,String 字符串,和類。
• 模糊特性:自動裝配不如顯式裝配精確,若是有可能,建議使用顯式裝配。
3五、你能夠在 Spring 中注入一個 null 和一個空字符串嗎?
能夠。
Spring 註解
3六、 什麼是基於 Java 的 Spring 註解配置? 給一些註解的例子.
基於 Java 的配置,容許你在少許的 Java 註解的幫助下,進行你的大部分 Spring 配置而非經過 XML 文件。
以@Configuration 註解爲例,它用來標記類能夠當作一個 bean 的定義,被
Spring IOC 容器使用。另外一個例子是@Bean 註解,它表示此方法將要返回一個對象,做爲一個 bean 註冊進 Spring 應用上下文。
3七、 什麼是基於註解的容器配置?
相對於 XML 文件,註解型的配置依賴於經過字節碼元數據裝配組件,而非尖括號的聲明。
開發者經過在相應的類,方法或屬性上使用註解的方式,直接組件類中進行配置,而不是使用 xml 表述 bean 的裝配關係。
3八、怎樣開啓註解裝配?
註解裝配在默認狀況下是不開啓的,爲了使用註解裝配,咱們必須在 Spring 配置文件中配置 context:annotation-config/元素。
3九、@Required 註解
這個註解代表 bean 的屬性必須在配置的時候設置,經過一個 bean 定義的顯式的屬性值或經過自動裝配,若@Required 註解的 bean 屬性未被設置,容器將拋出
BeanInitializationException。
40、@Autowired 註解
@Autowired 註解提供了更細粒度的控制,包括在何處以及如何完成自動裝配。它的用法和@Required 同樣,修飾 setter 方法、構造器、屬性或者具備任意名稱和/或多個參數的 PN 方法。
4一、@Qualifier 註解
當有多個相同類型的 bean 卻只有一個須要自動裝配時,將@Qualifier 註解和
@Autowire 註解結合使用以消除這種混淆,指定須要裝配的確切的 bean。
Spring 數據訪問
42.在 Spring 框架中如何更有效地使用 JDBC?
使用 SpringJDBC 框架,資源管理和錯誤處理的代價都會被減輕。因此開發者只需寫 statements 和 queries 從數據存取數據,JDBC 也能夠在 Spring 框架提供
的模板類的幫助下更有效地被使用,這個模板叫 JdbcTemplate (例子見這裏 here)
4三、JdbcTemplate
JdbcTemplate 類提供了不少便利的方法解決諸如把數據庫數據轉變成基本數據類型或對象,執行寫好的或可調用的數據庫操做語句,提供自定義的數據錯誤處理。
4四、Spring 對 DAO 的支持
Spring 對數據訪問對象(DAO)的支持旨在簡化它和數據訪問技術如 JDBC, Hibernate or JDO 結合使用。這使咱們能夠方便切換持久層。編碼時也不用擔憂會捕獲每種技術特有的異常。
4五、使用 Spring 經過什麼方式訪問 Hibernate?
在 Spring 中有兩種方式訪問 Hibernate:
• 控制反轉 Hibernate Template 和 Callback。
• 繼承 HibernateDAOSupport 提供一個 AOP 攔截器。
4六、Spring 支持的 ORM
Spring 支持如下 ORM:
• Hibernate
• iBatis
• JPA (Java Persistence API)
• TopLink
• JDO (Java Data Objects)
• OJB
47.如何經過HibernateDaoSupport將Spring和Hibernate 結合起來?
用 Spring 的 SessionFactory 調用 LocalSessionFactory。集成過程分三步:
• 配置 the Hibernate SessionFactory。
• 繼承 HibernateDaoSupport 實現一個 DAO。
• 在 AOP 支持的事務中裝配。
4八、Spring 支持的事務管理類型
Spring 支持兩種類型的事務管理:
• 編程式事務管理:這意味你經過編程的方式管理事務,給你帶來極大的靈活性,可是難維護。
• 聲明式事務管理:這意味着你能夠將業務代碼和事務管理分離,你只需用註解和 XML 配置來管理事務。
4九、Spring 框架的事務管理有哪些優勢?
• 它爲不一樣的事務 API 如 JTA,JDBC,Hibernate,JPA 和 JDO,提供一個不變的編程模式。
• 它爲編程式事務管理提供了一套簡單的 API 而不是一些複雜的事務 API 如
• 它支持聲明式事務管理。
• 它和 Spring 各類數據訪問抽象層很好得集成。
50、你更傾向用那種事務管理類型?
大多數 Spring 框架的用戶選擇聲明式事務管理,由於它對應用代碼的影響最小,所以更符合一個無侵入的輕量級容器的思想。聲明式事務管理要優於編程式事務管理,雖然比編程式事務管理(這種方式容許你經過代碼控制事務)少了一點靈活性。
Spring 面向切面編程(AOP)
5一、解釋 AOP
面向切面的編程,或 AOP, 是一種編程技術,容許程序模塊化橫向切割關注點,或橫切典型的責任劃分,如日誌和事務管理。
5二、Aspect 切面
AOP 核心就是切面,它將多個類的通用行爲封裝成可重用的模塊,該模塊含有一組 API 提供橫切功能。好比,一個日誌模塊能夠被稱做日誌的 AOP 切面。根據需
求的不一樣,一個應用程序能夠有若干切面。在 Spring AOP 中,切面經過帶有
@Aspect 註解的類實現。
5二、在 Spring AOP 中,關注點和橫切關注的區別是什麼?
關注點是應用中一個模塊的行爲,一個關注點可能會被定義成一個咱們想實現的一個功能。
橫切關注點是一個關注點,此關注點是整個應用都會使用的功能,並影響整個應用,好比日誌,安全和數據傳輸,幾乎應用的每一個模塊都須要的功能。所以這些都屬於橫切關注點。
5四、鏈接點
鏈接點表明一個應用程序的某個位置,在這個位置咱們能夠插入一個 AOP 切面,它其實是個應用程序執行 Spring AOP 的位置。
5五、通知
通知是個在方法執行前或執行後要作的動做,其實是程序執行時要經過
SpringAOP 框架觸發的代碼段。
Spring 切面能夠應用五種類型的通知:
• before:前置通知,在一個方法執行前被調用。
• after: 在方法執行以後調用的通知,不管方法執行是否成功。
• after-returning: 僅當方法成功完成後執行的通知。
• after-throwing: 在方法拋出異常退出時執行的通知。
• around: 在方法執行以前和以後調用的通知。
5六、切點
切入點是一個或一組鏈接點,通知將在這些位置執行。能夠經過表達式或匹配的方式指明切入點。
5七、 什麼是引入?
引入容許咱們在已存在的類中增長新的方法和屬性。
5八、 什麼是目標對象?
被一個或者多個切面所通知的對象。它一般是一個代理對象。也指被通知
(advised)對象。
5九、 什麼是代理?
代理是通知目標對象後建立的對象。從客戶端的角度看,代理對象和目標對象是同樣的。
60、有幾種不一樣類型的自動代理?
BeanNameAutoProxyCreator
DefaultAdvisorAutoProxyCreator
Metadata autoproxying
6一、什麼是織入。什麼是織入應用的不一樣點?
織入是將切面和到其餘應用類型或對象鏈接或建立一個被通知對象的過程。
織入能夠在編譯時,加載時,或運行時完成。
6二、解釋基於 XML Schema 方式的切面實現。
在這種狀況下,切面由常規類以及基於 XML 的配置實現。
6三、解釋基於註解的切面實現
在這種狀況下(基於@AspectJ 的實現),涉及到的切面聲明的風格與帶有 java5 標註的普通 java 類一致。
Spring 的 MVC
6四、什麼是 Spring 的 MVC 框架?
Spring 配備構建 Web 應用的全功能 MVC 框架。Spring 能夠很便捷地和其餘
MVC 框架集成,如 Struts,Spring 的 MVC 框架用控制反轉把業務對象和控制邏輯清晰地隔離。它也容許以聲明的方式把請求參數和業務對象綁定。
6五、DispatcherServlet
Spring 的 MVC 框架是圍繞 DispatcherServlet 來設計的,它用來處理全部的 HTTP 請求和響應。
6六、WebApplicationContext
WebApplicationContext 繼承了 ApplicationContext 並增長了一些 WEB 應用必備的特有功能,它不一樣於通常的 ApplicationContext ,由於它能處理主題,並找到被關聯的 servlet。
6七、什麼是 Spring MVC 框架的控制器?
控制器提供一個訪問應用程序的行爲,此行爲一般經過服務接口實現。控制器解析用戶輸入並將其轉換爲一個由視圖呈現給用戶的模型。Spring 用一個很是抽象的方式實現了一個控制層,容許用戶建立多種用途的控制器。
6八、@Controller 註解
該註解代表該類扮演控制器的角色,Spring 不須要你繼承任何其餘控制器基類或引用 Servlet API。
6九、@RequestMapping 註解
該註解是用來映射一個 URL 到一個類或一個特定的方處理法上。
微服務 面試題
一、您對微服務有何瞭解?
微服務,又稱微服務 架構,是一種架構風格,它將應用程序構建爲以業務領域爲模型的小型自治服務集合 。
通俗地說,你必須看到蜜蜂如何經過對齊六角形蠟細胞來構建它們的蜂窩狀物。他們最初從使用各類材料的小部分開始,並繼續從中構建一個大型蜂箱。這些細胞造成圖案,產生堅固的結構,將蜂窩的特定部分固定在一塊兒。這裏,每一個細胞獨立於另外一個細胞,但它也與其餘細胞相關。這意味着對一個細胞的損害不會損害其餘細胞,所以,蜜蜂能夠在不影響完整蜂箱的狀況下重建這些細胞。
圖 1:微服務的蜂窩表示 – 微服務訪談問題
請參考上圖。這裏,每一個六邊形形狀表明單獨的服務組件。與蜜蜂的工做相似,每一個敏捷團隊都使用可用的框架和所選的技術堆棧構建單獨的服務組件。就像在蜂箱中同樣,每一個服務組件造成一個強大的微服務架構,以提供更好的可擴展性。
此外,敏捷團隊能夠單獨處理每一個服務組件的問題,而對整個應用程序沒有影響或影響最小。
二、微服務架構有哪些優點?
圖 2:微服務的 優勢 – 微服務訪談問題
• 獨立開發 – 全部微服務均可以根據各自的功能輕鬆開發
• 獨立部署 – 基於其服務,能夠在任何應用程序中單獨部署它們
• 故障隔離 – 即便應用程序的一項服務不起做用,系統仍可繼續運行
• 混合技術堆棧 – 能夠使用不一樣的語言和技術來構建同一應用程序的不一樣服務
• 粒度縮放 – 單個組件可根據須要進行縮放,無需將全部組件縮放在一塊兒
3。微服務有哪些特色?
圖 3:微服務的 特色 – 微服務訪談問題
• 解耦 – 系統內的服務很大程度上是分離的。所以,整個應用程序能夠輕鬆構建,更改和擴展
• 組件化 – 微服務被視爲能夠輕鬆更換和升級的獨立組件
• 業務能力 – 微服務很是簡單,專一於單一功能
• 自治 – 開發人員和團隊能夠彼此獨立工做,從而提升速度
• 持續交付 – 經過軟件建立,測試和批准的系統自動化,容許頻繁發佈軟件
• 責任 – 微服務不關注應用程序做爲項目。相反,他們將應用程序視爲他們負責的產品
• 分散治理 – 重點是使用正確的工具來作正確的工做。這意味着沒有標準化模式或任何技術模式。開發人員能夠自由選擇最有用的工具來解決他們的問題
• 敏捷 – 微服務支持敏捷開發。任何新功能均可以快速開發並再次丟棄
四、設計微服務的最佳實踐是什麼?
如下是設計微服務的最佳實踐:
圖 4:設計微服務的最佳實踐 – 微服務訪談問題
五、微服務架構如何運做?微服務架構具備如下組件:
圖 5:微服務 架構 – 微服務面試問題
• 客戶端 – 來自不一樣設備的不一樣用戶發送請求。
• 身份提供商 – 驗證用戶或客戶身份並頒發安全令牌。
• API 網關 – 處理客戶端請求。
• 靜態內容 – 容納系統的全部內容。
• 管理 – 在節點上平衡服務並識別故障。
• 服務發現 – 查找微服務之間通訊路徑的指南。
• 內容交付網絡 – 代理服務器及其數據中心的分佈式網絡。 • 遠程服務 – 啓用駐留在 IT 設備網絡上的遠程訪問信息。
六、微服務架構的優缺點是什麼?
七、單片,SOA 和微服務架構有什麼區別?
圖 6: 單片 SOA 和微服務之間的比較 – 微服務訪談問題
• 單片架構相似於大容器,其中應用程序的全部軟件組件組裝在一塊兒並緊密封裝。
• 一個面向服務的架構是一種相互通訊服務的集合。通訊能夠涉及簡單的數據傳遞,也能夠涉及兩個或多個協調某些活動的服務。
• 微服務架構是一種架構風格,它將應用程序構建爲以業務域爲模型的小型自治服務集合。
八、在使用微服務架構時,您面臨哪些挑戰?
開發一些較小的微服務聽起來很容易,但開發它們時常常遇到的挑戰以下。
• 自動化組件:難以自動化,由於有許多較小的組件。所以,對於每一個組件,咱們必須遵循 Build,Deploy 和 Monitor 的各個階段。
• 易感性:將大量組件維護在一塊兒變得難以部署,維護,監控和識別問題。
它須要在全部組件周圍具備很好的感知能力。
• 配置管理:有時在各類環境中維護組件的配置變得困難。
• 調試:很難找到錯誤的每一項服務。維護集中式日誌記錄和儀表板以調試問題相當重要。
九、SOA 和微服務架構之間的主要區別是什麼?
SOA 和微服務之間的主要區別以下:
十、微服務有什麼特色?您能夠列出微服務的特徵,以下所示:
圖 7:微服務的特徵 – 微服務訪談問題
十一、什麼是領域驅動設計?
圖 8: DDD 原理 – 微服務面試問題
十二、爲何須要域驅動設計(DDD)?
圖 9:咱們須要 DDD 的因素 – 微服務面試問題
1三、什麼是無所不在的語言?
若是您必須定義泛在語言(UL),那麼它是特定域的開發人員和用戶使用的通用語言,經過該語言能夠輕鬆解釋域。
無處不在的語言必須很是清晰,以便它將全部團隊成員放在同一頁面上,並以機器能夠理解的方式進行翻譯。
1四、什麼是凝聚力?
模塊內部元素所屬的程度被認爲是凝聚力。
1五、什麼是耦合?
組件之間依賴關係強度的度量被認爲是耦合。一個好的設計老是被認爲具備高內聚力和低耦合性。
1六、什麼是 REST / RESTful 以及它的用途是什麼?
Representational State Transfer(REST)/ RESTful Web 服務是一種幫助計算機系統經過 Internet 進行通訊的架構風格。這使得微服務更容易理解和實現。
微服務能夠使用或不使用 RESTful API 實現,但使用 RESTful API 構建鬆散耦合的微服務老是更容易。
1七、你對 Spring Boot 有什麼瞭解?
事實上,隨着新功能的增長,彈簧變得愈來愈複雜。若是必須啓動新的 spring 項目,則必須添加構建路徑或添加 maven 依賴項,配置應用程序服務器,添加 spring 配置。因此一切都必須從頭開始。
Spring Boot 是解決這個問題的方法。使用 spring boot 能夠避免全部樣板代碼和配置。所以,基本上認爲本身就好像你正在烘烤蛋糕同樣,春天就像製做蛋糕所需的成分同樣,彈簧靴就是你手中的完整蛋糕。
圖 10: Spring Boot 的因素 – 微服務面試問題
1八、什麼是 Spring 引導的執行器?
Spring Boot 執行程序提供了 restful Web 服務,以訪問生產環境中運行應用程序的當前狀態。在執行器的幫助下,您能夠檢查各類指標並監控您的應用程序。
1九、什麼是 Spring Cloud?
根據 Spring Cloud 的官方網站,Spring Cloud 爲開發人員提供了快速構建分佈式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智能路由,領導選舉,分佈式會話,集羣狀態)。
20、Spring Cloud 解決了哪些問題?
在使用 Spring Boot 開發分佈式微服務時,咱們面臨的問題不多由 Spring Cloud 解決。
• 與分佈式系統相關的複雜性 – 包括網絡問題,延遲開銷,帶寬問題,安全問題。
• 處理服務發現的能力 – 服務發現容許集羣中的進程和服務找到彼此並進行通訊。
• 解決冗餘問題 – 冗餘問題常常發生在分佈式系統中。
• 負載平衡 – 改進跨多個計算資源(例如計算機集羣,網絡連接,中央處理單元)的工做負載分佈。
• 減小性能問題 – 減小因各類操做開銷致使的性能問題。
2一、在 Spring MVC 應用程序中使用 WebMvcTest 註釋有什麼用處?
在測試目標只關注 Spring MVC 組件的狀況下,WebMvcTest 註釋用於單元測試
Spring MVC 應用程序。在上面顯示的快照中,咱們只想啓動 ToTestController。
執行此單元測試時,不會啓動全部其餘控制器和映射。
22。你可否給出關於休息和微服務的要點?
雖然您能夠經過多種方式實現微服務,但 REST over HTTP 是實現微服務的一種方式。REST 還可用於其餘應用程序,如 Web 應用程序,API 設計和 MVC 應用程序,以提供業務數據。
微服務是一種體系結構,其中系統的全部組件都被放入單獨的組件中,這些組件能夠單獨構建,部署和擴展。微服務的某些原則和最佳實踐有助於構建彈性應用程序。
簡而言之,您能夠說 REST 是構建微服務的媒介。
2三、什麼是不一樣類型的微服務測試?
在使用微服務時,因爲有多個微服務協同工做,測試變得很是複雜。所以,測試分爲不一樣的級別。
• 在底層,咱們有面向技術的測試,如單元測試和性能測試。這些是徹底自動化的。
• 在中間層面,咱們進行了諸如壓力測試和可用性測試之類的探索性測試。
• 在頂層, 咱們的 驗收測試數量不多。這些驗收測試有助於利益相關者理解和驗證軟件功能。
2四、您對 Distributed Transaction 有何瞭解?
分佈式事務是指單個事件致使兩個或多個不能以原子方式提交的單獨數據源的突變的任何狀況。在微服務的世界中,它變得更加複雜,由於每一個服務都是一個工做單元,而且大多數時候多個服務必須協同工做才能使業務成功。
2五、什麼是 Idempotence 以及它在哪裏使用?
冪等性是可以以這樣的方式作兩次事情的特性,即最終結果將保持不變,即好像它只作了一次。
用法:在遠程服務或數據源中使用 Idempotence,這樣當它屢次接收指令時,它只處理指令一次。
2六、什麼是有界上下文?
有界上下文是域驅動設計的核心模式。DDD 戰略設計部門的重點是處理大型模型和團隊。DDD 經過將大型模型劃分爲不一樣的有界上下文並明確其相互關係來處理大型模型。
2七、什麼是雙因素身份驗證?雙因素身份驗證爲賬戶登陸過程啓用第二級身份驗證。
圖 11: 雙因素認證的表示 – 微服務訪談問題
所以,假設用戶必須只輸入用戶名和密碼,那麼這被認爲是單因素身份驗證。
2八、雙因素身份驗證的憑據類型有哪些?
這三種憑證是:
圖 12: 雙因素認證的證書類型 – 微服務面試問題
2九、什麼是客戶證書?
客戶端系統用於向遠程服務器發出通過身份驗證的請求的一種數字證書稱爲客戶端證書。客戶端證書在許多相互認證設計中起着很是重要的做用,爲請求者的身份提供了強有力的保證。
30、PACT 在微服務架構中的用途是什麼?
PACT 是一個開源工具,容許測試服務提供者和消費者之間的交互,與合同隔離,從而提升微服務集成的可靠性。
微服務中的用法
• 用於在微服務中實現消費者驅動的合同。
• 測試微服務的消費者和提供者之間的消費者驅動的合同。
查看即將到來的批次
3一、什麼是 OAuth?
OAuth 表明開放受權協議。這容許經過在 HTTP 服務上啓用客戶端應用程序(例如第三方提供商 Facebook,GitHub 等)來訪問資源全部者的資源。所以,您能夠在不使用其憑據的狀況下與另外一個站點共享存儲在一個站點上的資源。
3二、康威定律是什麼?
「任何設計系統的組織(普遍定義)都將產生一種設計,其結構是組織通訊結構的副本。」– MelConway
圖 13: Conway 定律的表示 – 微服務訪談問題
該法律基本上試圖傳達這樣一個事實:爲了使軟件模塊起做用,整個團隊應該進行良好的溝通。所以,系統的結構反映了產生它的組織的社會邊界。
3三、合同測試你懂什麼?
根據 Martin Flower 的說法,合同測試是在外部服務邊界進行的測試,用於驗證其是否符合消費服務預期的合同。
此外,合同測試不會深刻測試服務的行爲。更確切地說,它測試該服務調用的輸入&輸出包含所需的屬性和所述響應延遲,吞吐量是容許的限度內。
3四、什麼是端到端微服務測試?
端到端測試驗證了工做流中的每一個流程都正常運行。這可確保系統做爲一個總體協同工做並知足全部要求。
通俗地說,你能夠說端到端測試是一種測試,在特定時期後測試全部東西。
圖 14:測試層次 – 微服務面試問題
3五、Container 在微服務中的用途是什麼?
容器是管理基於微服務的應用程序以便單獨開發和部署它們的好方法。您能夠將微服務封裝在容器映像及其依賴項中,而後能夠使用它來滾動按需實例的微服務,而無需任何額外的工做。
圖 15: 容器的表示及其在微服務中的使用方式 – 微服務訪談問題
3六、什麼是微服務架構中的 DRY?
DRY 表明不要重複本身。它基本上促進了重用代碼的概念。這致使開發和共享庫,這反過來致使緊密耦合。
3七、什麼是消費者驅動的合同(CDC)?
這基本上是用於開發微服務的模式,以便它們能夠被外部系統使用。當咱們處理微服務時,有一個特定的提供者構建它,而且有一個或多個使用微服務的消費者。
一般,提供程序在 XML 文檔中指定接口。但在消費者驅動的合同中,每一個服務消費者都傳達了提供商指望的接口。
3八、Web,RESTful API 在微服務中的做用是什麼?
微服務架構基於一個概念,其中全部服務應該可以彼此交互以構建業務功能。所以,要實現這一點,每一個微服務必須具備接口。這使得 Web API 成爲微服務的一個很是重要的推進者。RESTful API 基於 Web 的開放網絡原則,爲構建微服務架構的各個組件之間的接口提供了最合理的模型。
3九、您對微服務架構中的語義監控有何瞭解?
語義監控,也稱爲 綜合監控, 將自動化測試與監控應用程序相結合,以檢測業務失敗因素。
40、咱們如何進行跨功能測試?
跨功能測試是對非功能性需求的驗證,即那些沒法像普通功能那樣實現的需求。
4一、咱們如何在測試中消除非決定論?
非肯定性測試(NDT)基本上是不可靠的測試。因此,有時可能會發生它們經過,顯然有時它們也可能會失敗。當它們失敗時,它們會從新運行經過。
從測試中刪除非肯定性的一些方法以下:
一、 隔離
二、 異步
三、 遠程服務
四、 隔離
五、 時間
六、 資源泄漏
4二、Mock 或 Stub 有什麼區別?
存根
• 一個有助於運行測試的虛擬對象。
• 在某些能夠硬編碼的條件下提供固定行爲。
• 永遠不會測試存根的任何其餘行爲。
例如,對於空堆棧,您能夠建立一個只爲 empty()方法返回 true 的存根。所以,這並不關心堆棧中是否存在元素。
嘲笑
• 一個虛擬對象,其中最初設置了某些屬性。
• 此對象的行爲取決於 set 屬性。
• 也能夠測試對象的行爲。
例如,對於 Customer 對象,您能夠經過設置名稱和年齡來模擬它。您能夠將 age 設置爲 12,而後測試 isAdult()方法,該方法將在年齡大於 18 時返回 true。所以,您的 Mock Customer 對象適用於指定的條件。
4三、您對 Mike Cohn 的測試金字塔瞭解多少?
Mike Cohn 提供了一個名爲 Test Pyramid 的模型。這描述了軟件開發所需的自動化測試類型。
圖 16: Mike Cohn 的測試金字塔 – 微服務面試問題
根據金字塔,第一層的測試數量應該最高。在服務層,測試次數應小於單元測試級別,但應大於端到端級別。
4四、Docker 的目的是什麼?
Docker 提供了一個可用於託管任何應用程序的容器環境。在此,軟件應用程序和支持它的依賴項緊密打包在一塊兒。
所以,這個打包的產品被稱爲 Container,由於它是由 Docker 完成的,因此它被稱爲 Docker 容器!
4五、什麼是金絲雀釋放?
Canary Releasing 是一種下降在生產中引入新軟件版本的風險的技術。這是經過將變動緩慢地推廣到一小部分用戶,而後將其發佈到整個基礎架構,即將其提供給每一個人來完成的。
4六、什麼是持續集成(CI)?
持續集成(CI)是每次團隊成員提交版本控制更改時自動構建和測試代碼的過程。
這鼓勵開發人員經過在每一個小任務完成後將更改合併到共享版本控制存儲庫來共享代碼和單元測試。
4七、什麼是持續監測?
持續監控深刻監控覆蓋範圍,從瀏覽器內前端性能指標,到應用程序性能,再到主機虛擬化基礎架構指標。
4八、架構師在微服務架構中的角色是什麼?
微服務架構中的架構師扮演如下角色:
• 決定整個軟件系統的佈局。
• 幫助肯定組件的分區。所以,他們確保組件相互粘合,但不緊密耦合。
• 與開發人員共同編寫代碼,瞭解平常生活中面臨的挑戰。
• 爲開發微服務的團隊提供某些工具和技術的建議。
• 提供技術治理,以便技術開發團隊遵循微服務原則。
4九、咱們能夠用微服務建立狀態機嗎?
咱們知道擁有本身的數據庫的每一個微服務都是一個可獨立部署的程序單元,這反過來又讓咱們能夠建立一個狀態機。所以,咱們能夠爲特定的微服務指定不一樣的狀態和事件。
例如,咱們能夠定義 Order 微服務。訂單能夠具備不一樣的狀態。Order 狀態的轉換能夠是 Order 微服務中的獨立事件。
50、什麼是微服務中的反應性擴展?
Reactive Extensions 也稱爲 Rx。這是一種設計方法,咱們經過調用多個服務來收集結果,而後編譯組合響應。這些調用能夠是同步或異步,阻塞或非阻塞。Rx 是分佈式系統中很是流行的工具,與傳統流程相反。
但願這些微服務面試問題能夠幫助您進行微服務架構師訪談。
翻譯來源:
https://www.edureka.co/blog/interview-questions/microservices-intervie w-questions/
Linux 面試題
一、絕對路徑用什麼符號表示?當前目錄、上層目錄用什麼表示?主目錄用什麼表示? 切換目錄用什麼命令?
答案:
絕對路徑: 如/etc/init.d
當前目錄和上層目錄: ./ ../ 主目錄: ~/
切換目錄: cd
二、怎麼查看當前進程?怎麼執行退出?怎麼查看當前路徑?
答案:
查看當前進程: ps 執行退出: exit
查看當前路徑: pwd
三、怎麼清屏?怎麼退出當前命令?怎麼執行睡眠?怎麼查看當
前用戶 id?查看指定幫助用什麼命令?
答案:
清屏: clear
退出當前命令: ctrl+c 完全退出
執行睡眠 : ctrl+z 掛起當前進程 fg 恢復後臺
查看當前用戶 id: 」id「:查看顯示目前登錄帳戶的 uid 和 gid 及所屬分組及用戶名
查看指定幫助: 如 man adduser 這個很全 並且有例子; adduser --help 這個告訴你一些經常使用參數; info adduesr;
四、Ls 命令執行什麼功能? 能夠帶哪些參數,有什麼區別?
答案:
ls 執行的功能: 列出指定目錄中的目錄,以及文件
哪些參數以及區別: a 全部文件 l 詳細信息,包括大小字節數,可讀可寫可執行的權限等
五、創建軟連接(快捷方式),以及硬連接的命令。
答案:
軟連接: ln -s slink source 硬連接: ln link source
六、目錄建立用什麼命令?建立文件用什麼命令?複製文件用什麼命令?
答案:
建立目錄: mkdir
建立文件:典型的如 touch,vi 也能夠建立文件,其實只要向一個不存在的文件輸出,都會建立文件
複製文件: cp 7. 文件權限修改用什麼命令?格式是怎麼樣的?文件權限修改: chmod
格式以下:
chmodu+xfile 給 file 的屬主增長執行權限 chmod 751 file 給 file 的屬主分配讀、寫、執行(7)的權限,給 file 的所在組分配讀、執行(5)的權限,給其餘用戶分配執行(1)的權限
chmodu=rwx,g=rx,o=xfile 上例的另外一種形式 chmod =r file 爲全部用戶分配讀權限
chmod444file 同上例 chmod a-wx,a+r file 同上例
$ chmod -R u+r directory 遞歸地給 directory 目錄下全部文件和子目錄的屬主分配讀的權限
七、查看文件內容有哪些命令能夠使用?
答案:
vi 文件名 #編輯方式查看,可修改 cat 文件名 #顯示所有文件內容 more 文件名 #分頁顯示文件內容
less 文件名 #與 more 類似,更好的是能夠往前翻頁 tail 文件名 #僅查看尾部,還能夠指定行數 head 文件名 #僅查看頭部,還能夠指定行數
八、隨意寫文件命令?怎麼向屏幕輸出帶空格的字符串,好比」 hello world」?
答案:
寫文件命令:vi
向屏幕輸出帶空格的字符串:echo hello world
九、終端是哪一個文件夾下的哪一個文件?黑洞文件是哪一個文件夾下的哪一個命令?
答案:
終端 /dev/tty
黑洞文件 /dev/null
十、移動文件用哪一個命令?更名用哪一個命令?
答案:
mv mv
十一、複製文件用哪一個命令?若是須要連同文件夾一塊複製呢?若是須要有提示功能呢?
答案:
cp cp -r ????
十二、刪除文件用哪一個命令?若是須要連目錄及目錄下文件一塊刪除呢?刪除空文件夾用什麼命令?
答案:
rm rm -r rmdir
1三、Linux 下命令有哪幾種可以使用的通配符?分別表明什麼含義?
答案:
「?」可替代單個字符。
「」可替代任意多個字符。
方括號「[charset]」可替代 charset 集中的任何單個字符,如[a-z],[abABC]
1四、用什麼命令對一個文件的內容進行統計?(行號、單詞數、字節數)
答案:
wc 命令 - c 統計字節數 - l 統計行數 - w 統計字數。
1五、Grep 命令有什麼用? 如何忽略大小寫? 如何查找不含該串的行?
答案:
是一種強大的文本搜索工具,它能使用正則表達式搜索文本,並把匹 配的行打印出來。
grep [stringSTRING] filename grep [^string] filename
1六、Linux 中進程有哪幾種狀態?在 ps 顯示出來的信息中,分別用什麼符號表示的?
答案:
一、 不可中斷狀態:進程處於睡眠狀態,可是此刻進程是不可中斷的。不可中斷,指進程不響應異步信號。
二、 暫停狀態/跟蹤狀態:向進程發送一個 SIGSTOP 信號,它就會因響應該信號 而進入 TASK_STOPPED 狀態;當進程正在被跟蹤時,它處於 TASK_TRACED 這個特殊的狀態。
正被跟蹤」指的是進程暫停下來,等待跟蹤它的進程對它進行操做。
三、 就緒狀態:在 run_queue 隊列裏的狀態
四、 運行狀態:在 run_queue 隊列裏的狀態
五、 可中斷睡眠狀態:處於這個狀態的進程由於等待某某事件的發生(好比等待socket 鏈接、等待信號量),而被掛起
六、 zombie 狀態(殭屍):父親沒有經過 wait 系列的系統調用會順便將子進程的屍體(task_struct)也釋放掉
七、 退出狀態
D 不可中斷 Uninterruptible(usually IO)
R 正在運行,或在隊列中的進程
S 處於休眠狀態 T 中止或被追蹤
Z 殭屍進程
W 進入內存交換(從內核 2.6 開始無效)
X 死掉的進程
1七、怎麼使一個命令在後臺運行?
答案:
通常都是使用 & 在命令結尾來讓程序自動運行。(命令後能夠不追加空格)
1八、利用 ps 怎麼顯示全部的進程? 怎麼利用 ps 查看指定進程的信息?
答案:
ps -ef (system v 輸出)
ps -aux bsd 格式輸出
ps -ef | grep pid
1九、 哪一個命令專門用來查看後臺任務?
答案:
job -l
20、 把後臺任務調到前臺執行使用什麼命令?把停下的後臺任務在後臺執行起來用什麼命令?
答案:
把後臺任務調到前臺執行 fg
把停下的後臺任務在後臺執行起來 bg
2一、 終止進程用什麼命令? 帶什麼參數?
答案:
kill [-s <信息名稱或編號>][程序] 或 kill [-l <信息編號>]
kill-9 pid
2二、怎麼查看系統支持的全部信號?
答案:
kill -l
2三、 搜索文件用什麼命令? 格式是怎麼樣的?
答案:
find <指定目錄> <指定條件> <指定動做>
whereis 加參數與文件名
locate 只加文件名
find 直接搜索磁盤,較慢。
find / -name "string"
2四、 查看當前誰在使用該主機用什麼命令? 查找本身所在的終端信息用什麼命令?
答案:
查找本身所在的終端信息:who am i
查看當前誰在使用該主機:who
2五、 使用什麼命令查看用過的命令列表?
答案:
history
2六、 使用什麼命令查看磁盤使用空間? 空閒空間呢?
答案:
df -hl
文件系統 容量 已用 可用 已用% 掛載點
Filesystem Size Used Avail Use% Mounted on /dev/hda2 45G 19G 24G
44% /
/dev/hda1 494M 19M 450M 4% /boot
2七、 使用什麼命令查看網絡是否連通?
答案:
netstat
2八、使用什麼命令查看 ip 地址及接口信息?
答案:
ifconfig
2九、 查看各種環境變量用什麼命令?
答案:
查看全部 env
查看某個,如 home: env $HOME
30、 經過什麼命令指定命令提示符?
答案:
• \u:顯示當前用戶帳號
• \h:顯示當前主機名
• \W:只顯示當前路徑最後一個目錄
• \w:顯示當前絕對路徑(當前用戶目錄會以~代替)
• $PWD:顯示當前全路徑
• $:顯示命令行’$'或者’#'符號
• #:下達的第幾個命令
• \d:表明日期,格式爲 week day month date,例如:"MonAug1"
• \t:顯示時間爲 24 小時格式,如:HH:MM:SS
• \T:顯示時間爲 12 小時格式
• \A:顯示時間爲 24 小時格式:HH:MM
• \v:BASH 的版本信息 如 export PS1=’[\u@\h\w#]$‘
3一、 查找命令的可執行文件是去哪查找的? 怎麼對其進行設置及添加?
答案:
whereis [-bfmsu][-B <目錄>...][-M <目錄>...][-S <目錄>...][文件...]
補充說明:whereis 指令會在特定目錄中查找符合條件的文件。這些文件的烈性應屬於原始代碼,二進制文件,或是幫助文件。
• -b 只查找二進制文件。
• -B <目錄> 只在設置的目錄下查找二進制文件。 -f 不顯示文件名前的路徑名稱。
• -m 只查找說明文件。
• -M <目錄> 只在設置的目錄下查找說明文件。-s 只查找原始代碼文件。
• -S <目錄> 只在設置的目錄下查找原始代碼文件。 -u 查找不包含指定類型的文件。
w -h ich 指令會在 PATH 變量指定的路徑中,搜索某個系統命令的位置,而且返回第一個搜索結果。
• -n 指定文件名長度,指定的長度必須大於或等於全部文件中最長的文件名。
• -p 與-n 參數相同,但此處的包括了文件的路徑。 -w 指定輸出時欄位的寬度。
• -V 顯示版本信息
3二、 經過什麼命令查找執行命令?
答案:
which 只能查可執行文件
whereis 只能查二進制文件、說明文檔,源文件等
3三、怎麼對命令進行取別名?
答案:
alias la='ls -a'
3四、du 和 df 的定義,以及區別?
答案:
du 顯示目錄或文件的大小
df 顯示每一個<文件>所在的文件系統的信息,默認是顯示全部文件系統。
(文件系統分配其中的一些磁盤塊用來記錄它自身的一些數據,如 i 節點,磁盤分佈圖,間接塊,超級塊等。這些數據對大多數用戶級的程序來講是不可見的,一般稱爲 Meta Data。) du 命令是用戶級的程序,它不考慮 Meta Data,而 df 命令則查看文件系統的磁盤分配圖並考慮 Meta Data。
df 命令得到真正的文件系統數據,而 du 命令只查看文件系統的部分狀況。
3五、awk 詳解。
答案:
awk '{pattern + action}' {filenames}
/bin/bash
daemon /bin/sh 搜索/etc/passwd 有 root 關鍵字的全部行
3六、當你須要給命令綁定一個宏或者按鍵的時候,應該怎麼作呢?
答案:
能夠使用 bind 命令,bind 能夠很方便地在 shell 中實現宏或按鍵的綁定。
在進行按鍵綁定的時候,咱們須要先獲取到綁定按鍵對應的字符序列。
好比獲取 F12 的字符序列獲取方法以下:先按下 Ctrl+V,而後按下 F12 .咱們就能夠獲得 F12 的字符序列 ^[[24~。
接着使用 bind 進行綁定。
[root@localhost ~]# bind ‘」\e[24~":"date"'
注意:相同的按鍵在不一樣的終端或終端模擬器下可能會產生不一樣的字符序列。
【附】也能夠使用 showkey -a 命令查看按鍵對應的字符序列。
3七、若是一個 linux 新手想要知道當前系統支持的全部命令的列表,他須要怎麼作?
答案:
使用命令 compgen -c,能夠打印出全部支持的命令列表。
[root@localhost ~]$ compgen -c l. ll
ls
which
if
then else elif fi
case
esac for select while until do
done
…
3八、若是你的助手想要打印出當前的目錄棧,你會建議他怎麼作?
答案:
使用 Linux 命令 dirs 能夠將當前的目錄棧打印出來。
[root@localhost ~]# dirs
/usr/share/X11
【附】:目錄棧經過 pushd popd 來操做。
3九、你的系統目前有許多正在運行的任務,在不重啓機器的條件下,有什麼方法能夠把全部正在運行的進程移除呢?
答案:
使用 linux 命令 ’disown -r ’能夠將全部正在運行的進程移除。
40、bash shell 中的 hash 命令有什麼做用?
答案:
linux 命令’hash’管理着一個內置的哈希表,記錄了已執行過的命令的完整路徑, 用該命令能夠打印出你所使用過的命令以及執行的次數。
[root@localhost ~]# hash hits command
2 /bin/ls
2 /bin/su
4一、哪個 bash 內置命令可以進行數學運算。
答案:
bash shell 的內置命令 let 能夠進行整型數的數學運算。
…
…
let c=a+b
…
…
4二、怎樣一頁一頁地查看一個大文件的內容呢?
答案:
經過管道將命令」cat file_name.txt」 和 ’more’ 鏈接在一塊兒能夠實現這個須要.
[root@localhost ~]# cat file_name.txt | more
4三、數據字典屬於哪個用戶的?
答案:
數據字典是屬於’SYS’用戶的,用戶‘SYS’ 和 ’SYSEM’是由系統默認自動建立的
4四、怎樣查看一個 linux 命令的概要與用法?假設你在/bin 目錄中偶然看到一個你從沒見過的的命令,怎樣才能知道它的做用和用法呢?
答案:
使用命令 whatis 能夠先出顯示出這個命令的用法簡要,好比,你能夠使用 whatis zcat 去查看‘zcat’的介紹以及使用簡要。
[root@localhost ~]# whatis zcat
zcat [gzip] (1) – compress or expand files
4五、使用哪個命令能夠查看本身文件系統的磁盤空間配額呢?
答案:
使用命令 repquota 可以顯示出一個文件系統的配額信息
【附】只有 root 用戶纔可以查看其它用戶的配額。
Spring Boot 面試題
一、什麼是 Spring Boot?
多年來,隨着新功能的增長,spring 變得愈來愈複雜。只需訪問
https://spring.io/projects 頁面,咱們就會看到能夠在咱們的應用程序中使用的全部 Spring 項目的不一樣功能。若是必須啓動一個新的 Spring 項目,咱們必須添加構建路徑或添加 Maven 依賴關係,配置應用程序服務器,添加 spring 配置。所以,開始一個新的 spring 項目須要不少努力,由於咱們如今必須從頭開始作全部事情。
Spring Boot 是解決這個問題的方法。Spring Boot 已經創建在現有 spring 框架之上。使用 spring 啓動,咱們避免了以前咱們必須作的全部樣板代碼和配置。所以,Spring Boot 能夠幫助咱們以最少的工做量,更加健壯地使用現有的 Spring 功能。
二、Spring Boot 有哪些優勢?
Spring Boot 的優勢有:
一、 減小開發,測試時間和努力。
二、 使用 JavaConfig 有助於避免使用 XML。
三、 避免大量的 Maven 導入和各類版本衝突。
四、 提供意見發展方法。
五、 經過提供默認值快速開始開發。
六、 沒有單獨的 Web 服務器須要。這意味着你再也不須要啓動 Tomcat,Glassfish 或其餘任何東西。
七、 須要更少的配置 由於沒有 web.xml 文件。只需添加用@ Configuration 註釋的類,而後添加用@Bean 註釋的方法,Spring 將自動加載對象並像之前同樣對其進行管理。您甚至能夠將@Autowired 添加到 bean 方法中,以使 Spring 自動裝入須要的依賴關係中。
八、 基於環境的配置 使用這些屬性,您能夠將您正在使用的環境傳遞到應用程序:
-Dspring.profiles.active = {enviornment}。在加載主應用程序屬性文件後,
Spring 將在(application{environment} .properties)中加載後續的應用程序屬性文件。
三、什麼是 JavaConfig?
Spring JavaConfig 是 Spring 社區的產品,它提供了配置 Spring IoC 容器的純
Java 方法。所以它有助於避免使用 XML 配置。使用 JavaConfig 的優勢在於:
一、 面向對象的配置。因爲配置被定義爲 JavaConfig 中的類,所以用戶能夠充分利用 Java 中的面向對象功能。一個配置類能夠繼承另外一個,重寫它的@Bean 方法等。
二、 減小或消除 XML 配置。基於依賴注入原則的外化配置的好處已被證實。可是,許多開發人員不但願在 XML 和 Java 之間來回切換。JavaConfig 爲開發人員提供了一種純 Java 方法來配置與 XML 配置概念類似的 Spring 容器。從技術角度來說,
只使用 JavaConfig 配置類來配置容器是可行的,但實際上不少人認爲將
JavaConfig 與 XML 混合匹配是理想的。
三、 類型安全和重構友好。JavaConfig 提供了一種類型安全的方法來配置 Spring 容器。因爲 Java 5.0 對泛型的支持,如今能夠按類型而不是按名稱檢索 bean,不須要任何強制轉換或基於字符串的查找。
四、如何從新加載 Spring Boot 上的更改,而無需從新啓動服務器?
這能夠使用 DEV 工具來實現。經過這種依賴關係,您能夠節省任何更改,嵌入式 tomcat 將從新啓動。Spring Boot 有一個開發工具(DevTools)模塊,它有助於提升開發人員的生產力。Java 開發人員面臨的一個主要挑戰是將文件更改自動部署到服務器並自動重啓服務器。開發人員能夠從新加載 Spring Boot 上的更改,而無需從新啓動服務器。這將消除每次手動部署更改的須要。Spring Boot 在發佈它的第一個版本時沒有這個功能。這是開發人員最須要的功能。DevTools 模塊徹底知足開發人員的需求。該模塊將在生產環境中被禁用。它還提供 H2 數據庫控制檯以更好地測試應用程序。
五、Spring Boot 中的監視器是什麼?
Spring boot actuator 是 spring 啓動框架中的重要功能之一。Spring boot 監視
器可幫助您訪問生產環境中正在運行的應用程序的當前狀態。有幾個指標必須在生產環境中進行檢查和監控。即便一些外部應用程序可能正在使用這些服務來向相關人員觸發警報消息。監視器模塊公開了一組可直接做爲 HTTP URL 訪問的 REST 端點來檢查狀態。
六、如何在 Spring Boot 中禁用 Actuator 端點安全性?
默認狀況下,全部敏感的 HTTP 端點都是安全的,只有具備 ACTUATOR 角色的用戶才能訪問它們。安全性是使用標準的 HttpServletRequest.isUserInRole 方法實
施的。 咱們能夠使用
來禁用安全性。只有在執行機構端點在防火牆後訪問時,才建議禁用安全性。 七、如何在自定義端口上運行 Spring Boot 應用程序?
爲了在自定義端口上運行 Spring Boot 應用程序,您能夠在 application.properties 中指定端口。
server.port = 8090
八、什麼是 YAML?
YAML 是一種人類可讀的數據序列化語言。它一般用於配置文件。
與屬性文件相比,若是咱們想要在配置文件中添加複雜的屬性,YAML 文件就更加結構化,並且更少混淆。能夠看出 YAML 具備分層配置數據。
九、如何實現 Spring Boot 應用程序的安全性?
爲了實現 Spring Boot 的安全性,咱們使用 spring-boot-starter-security 依賴項,而且必須添加安全配置。它只須要不多的代碼。配置類將必須擴展
WebSecurityConfigurerAdapter 並覆蓋其方法。
十、如何集成 Spring Boot 和 ActiveMQ?
對於集成 Spring Boot 和 ActiveMQ,咱們使用
依賴關係。 它只須要不多的配置,而且不須要樣板代碼。
十一、如何使用 Spring Boot 實現分頁和排序?
使用 Spring Boot 實現分頁很是簡單。使用 Spring Data-JPA 能夠實現將可分頁的
傳遞給存儲庫方法。
十二、什麼是 Swagger?你用 Spring Boot 實現了它嗎?
Swagger 普遍用於可視化 API,使用 Swagger UI 爲前端開發人員提供在線沙箱。
Swagger 是用於生成 RESTful Web 服務的可視化表示的工具,規範和完整框架實現。它使文檔可以以與服務器相同的速度更新。當經過 Swagger 正肯定義時,消費者能夠使用最少許的實現邏輯來理解遠程服務並與其進行交互。所以,Swagger 消除了調用服務時的猜想。
1三、什麼是 Spring Profiles?
Spring Profiles 容許用戶根據配置文件(dev,test,prod 等)來註冊 bean。所以,當應用程序在開發中運行時,只有某些 bean 能夠加載,而在 PRODUCTION 中,某些其餘 bean 能夠加載。假設咱們的要求是 Swagger 文檔僅適用於 QA 環境,而且禁用全部其餘文檔。這能夠使用配置文件來完成。Spring Boot 使得使用配置文件很是簡單。
1四、什麼是 Spring Batch?
Spring Boot Batch 提供可重用的函數,這些函數在處理大量記錄時很是重要,包括日誌/跟蹤,事務管理,做業處理統計信息,做業從新啓動,跳過和資源管理。它還提供了更先進的技術服務和功能,經過優化和分區技術,能夠實現極高批量和高性能批處理做業。簡單以及複雜的大批量批處理做業能夠高度可擴展的方式利用框架處理重要大量的信息。
1五、什麼是 FreeMarker 模板?
FreeMarker 是一個基於 Java 的模板引擎,最初專一於使用 MVC 軟件架構進行動態網頁生成。使用 Freemarker 的主要優勢是表示層和業務層的徹底分離。程序員
能夠處理應用程序代碼,而設計人員能夠處理 html 頁面設計。最後使用 freemarker 能夠將這些結合起來,給出最終的輸出頁面。
1六、如何使用 Spring Boot 實現異常處理?
Spring 提供了一種使用 ControllerAdvice 處理異常的很是有用的方法。 咱們經過實現一個 ControlerAdvice 類,來處理控制器類拋出的全部異常。
1七、您使用了哪些 starter maven 依賴項?
使用了下面的一些依賴項
spring-boot-starter-activemq spring-boot-starter-security
這有助於增長更少的依賴關係,並減小版本的衝突。
1八、什麼是 CSRF 攻擊?
CSRF 表明跨站請求僞造。這是一種攻擊,迫使最終用戶在當前經過身份驗證的 Web 應用程序上執行不須要的操做。CSRF 攻擊專門針對狀態改變請求,而不是數據竊取,由於攻擊者沒法查看對僞造請求的響應。
1九、什麼是 WebSockets?
WebSocket 是一種計算機通訊協議,經過單個 TCP 鏈接提供全雙工通訊信道。
一、 WebSocket 是雙向的 -使用 WebSocket 客戶端或服務器能夠發起消息發送。
二、 WebSocket 是全雙工的 -客戶端和服務器通訊是相互獨立的。
三、 單個 TCP 鏈接 -初始鏈接使用 HTTP,而後將此鏈接升級到基於套接字的鏈接。
而後這個單一鏈接用於全部將來的通訊
四、 Light -與 http 相比,WebSocket 消息數據交換要輕得多。
20、什麼是 AOP?
在軟件開發過程當中,跨越應用程序多個點的功能稱爲交叉問題。這些交叉問題與應用程序的主要業務邏輯不一樣。所以,將這些橫切關注與業務邏輯分開是面向方面編程(AOP)的地方。
2一、什麼是 Apache Kafka?
Apache Kafka 是一個分佈式發佈 - 訂閱消息系統。它是一個可擴展的,容錯的發佈 - 訂閱消息系統,它使咱們可以構建分佈式應用程序。這是一個 Apache 頂級項目。Kafka 適合離線和在線消息消費。
2二、咱們如何監視全部 Spring Boot 微服務?
Spring Boot 提供監視器端點以監控各個微服務的度量。這些端點對於獲取有關應用程序的信息(如它們是否已啓動)以及它們的組件(如數據庫等)是否正常運行頗有幫助。可是,使用監視器的一個主要缺點或困難是,咱們必須單獨打開應用程序的知識點以瞭解其狀態或健康情況。想象一下涉及 50 個應用程序的微服務,管理員將不得不擊中全部 50 個應用程序的執行終端。
爲了幫助咱們處理這種狀況,咱們將使用位於
的開源項目。 它創建在 Spring Boot Actuator 之上,它提供了一個 Web UI,使咱們可以可視化多個應用程序的度量。
Spring Cloud 面試題
一、什麼是 Spring Cloud?
Spring cloud 流應用程序啓動器是基於 Spring Boot 的 Spring 集成應用程序,提供與外部系統的集成。Spring cloud Task,一個生命週期短暫的微服務框架,用於快速構建執行有限數據處理的應用程序。
二、使用 Spring Cloud 有什麼優點?
使用 Spring Boot 開發分佈式微服務時,咱們面臨如下問題
一、 與分佈式系統相關的複雜性-這種開銷包括網絡問題,延遲開銷,帶寬問題,安全問題。
二、 服務發現-服務發現工具管理羣集中的流程和服務如何查找和互相交談。它涉及一個服務目錄,在該目錄中註冊服務,而後可以查找並鏈接到該目錄中的服務。
三、 冗餘-分佈式系統中的冗餘問題。
四、 負載平衡 --負載平衡改善跨多個計算資源的工做負荷,諸如計算機,計算機集羣,網絡鏈路,中央處理單元,或磁盤驅動器的分佈。
五、 性能-問題 因爲各類運營開銷致使的性能問題。
六、 部署複雜性-Devops 技能的要求。
三、服務註冊和發現是什麼意思?Spring Cloud 如何實現?
當咱們開始一個項目時,咱們一般在屬性文件中進行全部的配置。隨着愈來愈多的服務開發和部署,添加和修改這些屬性變得更加複雜。有些服務可能會降低,而某些位置可能會發生變化。手動更改屬性可能會產生問題。 Eureka 服務註冊和發現能夠在這種狀況下提供幫助。因爲全部服務都在 Eureka 服務器上註冊並經過調用 Eureka 服務器完成查找,所以無需處理服務地點的任何更改和處理。
四、負載平衡的意義什麼?
在計算中,負載平衡能夠改善跨計算機,計算機集羣,網絡連接,中央處理單元或磁盤驅動器等多種計算資源的工做負載分佈。負載平衡旨在優化資源使用,最大化吞吐量,最小化響應時間並避免任何單一資源的過載。使用多個組件進行負載平衡而不是單個組件可能會經過冗餘來提升可靠性和可用性。負載平衡一般涉及專用軟件或硬件,例如多層交換機或域名系統服務器進程。
五、什麼是 Hystrix?它如何實現容錯?
Hystrix 是一個延遲和容錯庫,旨在隔離遠程系統,服務和第三方庫的訪問點,當出現故障是不可避免的故障時,中止級聯故障並在複雜的分佈式系統中實現彈性。一般對於使用微服務架構開發的系統,涉及到許多微服務。這些微服務彼此協做。
思考如下微服務
假設若是上圖中的微服務 9 失敗了,那麼使用傳統方法咱們將傳播一個異常。但這仍然會致使整個系統崩潰。
隨着微服務數量的增長,這個問題變得更加複雜。微服務的數量能夠高達 1000.
這是 hystrix 出現的地方 咱們將使用 Hystrix 在這種狀況下的 Fallback 方法功能。咱們有兩個服務 employee-consumer 使用由 employee-consumer 公開的服務。
簡化圖以下所示
如今假設因爲某種緣由,employee-producer 公開的服務會拋出異常。咱們在這種狀況下使用 Hystrix 定義了一個回退方法。這種後備方法應該具備與公開服務相同的返回類型。若是暴露服務中出現異常,則回退方法將返回一些值。
六、什麼是 Hystrix 斷路器?咱們須要它嗎?
因爲某些緣由,employee-consumer 公開服務會引起異常。在這種狀況下使用
Hystrix 咱們定義了一個回退方法。若是在公開服務中發生異常,則回退方法返回一些默認值。
若是 firstPage method() 中的異常繼續發生,則 Hystrix 電路將中斷,而且員工使用者將一塊兒跳過 firtsPage 方法,並直接調用回退方法。 斷路器的目的是給第一頁方法或第一頁方法可能調用的其餘方法留出時間,並致使異常恢復。可能發生的狀況是,在負載較小的狀況下,致使異常的問題有更好的恢復機會 。
七、什麼是 Netflix Feign?它的優勢是什麼?
Feign 是受到 Retrofit,JAXRS-2.0 和 WebSocket 啓發的 java 客戶端聯編程序。 Feign 的第一個目標是將約束分母的複雜性統一到 http apis,而不考慮其穩定性。
在 employee-consumer 的例子中,咱們使用了 employee-producer 使用 REST 模板公開的 REST 服務。
可是咱們必須編寫大量代碼才能執行如下步驟
一、 使用功能區進行負載平衡。
二、 獲取服務實例,而後獲取基本 URL。
三、 利用 REST 模板來使用服務。 前面的代碼以下
@Controller
public class ConsumerControllerClient {
@Autowired
private LoadBalancerClient loadBalancer; public void getEmployee() throws RestClientException, IOException {
ServiceInstance serviceInstance=loadBalancer.choose("employee-producer");
System.out.println(serviceInstance.getUri());
String baseUrl=serviceInstance.getUri().toString(); baseUrl=baseUrl+"/employee";
RestTemplate restTemplate = new RestTemplate(); ResponseEntity
response=restTemplate.exchange(baseUrl,
HttpMethod.GET, getHeaders(),String.class);
}catch (Exception ex)
{
System.out.println(ex);
}
System.out.println(response.getBody());
以前的代碼,有像 NullPointer 這樣的例外的機會,並非最優的。咱們將看到如何使用 Netflix Feign 使呼叫變得更加輕鬆和清潔。若是 Netflix Ribbon 依賴關係也在類路徑中,那麼 Feign 默認也會負責負載平衡。
八、什麼是 Spring Cloud Bus?咱們須要它嗎?
考慮如下狀況:咱們有多個應用程序使用 Spring Cloud Config 讀取屬性,而
Spring Cloud Config 從 GIT 讀取這些屬性。
下面的例子中多個員工生產者模塊從 Employee Config Module 獲取 Eureka 註冊的財產。
若是假設 GIT 中的 Eureka 註冊屬性更改成指向另外一臺 Eureka 服務器,會發生什麼狀況。在這種狀況下,咱們將不得不從新啓動服務以獲取更新的屬性。
還有另外一種使用執行器端點/刷新的方式。可是咱們將不得不爲每一個模塊單獨調用這個 url。例如,若是 Employee Producer1 部署在端口 8080 上,則調用 http:
// localhost:8080 / refresh。一樣對於 Employee Producer2 http://
localhost:8081 / refresh 等等。這又很麻煩。這就是 Spring Cloud Bus 發揮做用的地方。
Spring Cloud Bus 提供了跨多個實例刷新配置的功能。所以,在上面的示例中,若是咱們刷新 Employee Producer1,則會自動刷新全部其餘必需的模塊。若是咱們有多個微服務啓動並運行,這特別有用。這是經過將全部微服務鏈接到單個消息代理來實現的。不管什麼時候刷新實例,此事件都會訂閱到偵聽此代理的全部微服務,而且它們也會刷新。能夠經過使用端點/總線/刷新來實現對任何單個實例的刷新。
RabbitMQ 面試題
一、什麼是 rabbitmq
採用 AMQP 高級消息隊列協議的一種消息隊列技術,最大的特色就是消費並不須要確保提供方存在,實現了服務之間的高度解耦
二、爲何要使用 rabbitmq
一、 在分佈式系統下具有異步,削峯,負載均衡等一系列高級功能;
二、 擁有持久化的機制,進程消息,隊列中的信息也能夠保存下來。
三、 實現消費者和生產者之間的解耦。
四、 對於高併發場景下,利用消息隊列能夠使得同步訪問變爲串行訪問達到必定量的限流,利於數據庫的操做。
5.能夠使用消息隊列達到異步下單的效果,排隊中,後臺進行邏輯下單。
三、使用 rabbitmq 的場景
一、 服務間異步通訊
二、 順序消費
三、 定時任務
四、 請求削峯
四、如何確保消息正確地發送至 RabbitMQ? 如何確保消息接收方消費了消息?
發送方確認模式
將信道設置成 confirm 模式(發送方確認模式),則全部在信道上發佈的消息都會被指派一個惟一的 ID。
一旦消息被投遞到目的隊列後,或者消息被寫入磁盤後(可持久化的消息),信道會發送一個確認給生產者(包含消息惟一 ID)。
若是 RabbitMQ 發生內部錯誤從而致使消息丟失,會發送一條 nack(not acknowledged,未確認)消息。發送方確認模式是異步的,生產者應用程序在等待確認的同時,能夠繼續發送消息。當確認消息到達生產者應用程序,生產者應用程序的回調方法就會被觸發來處理確認消息。接收方確認機制
接收方消息確認機制
消費者接收每一條消息後都必須進行確認(消息接收和消息確認是兩個不一樣操做)。只有消費者確認了消息,RabbitMQ 才能安全地把消息從隊列中刪除。
這裏並無用到超時機制,RabbitMQ 僅經過 Consumer 的鏈接中斷來確認是否須要從新發送消息。也就是說,只要鏈接不中斷,RabbitMQ 給了 Consumer 足夠長的時間來處理消息。保證數據的最終一致性;
下面羅列幾種特殊狀況
若是消費者接收到消息,在確認以前斷開了鏈接或取消訂閱,RabbitMQ 會認爲消息沒有被分發,而後從新分發給下一個訂閱的消費者。(可能存在消息重複消費的隱患,須要去重)
若是消費者接收到消息卻沒有確認消息,鏈接也未斷開,則 RabbitMQ 認爲該消費者繁忙,將不會給該消費者分發更多的消息。
5.如何避免消息重複投遞或重複消費?
在消息生產時,MQ 內部針對每條生產者發送的消息生成一個 inner-msg-id,做爲去重的依據(消息投遞失敗並重傳),避免重複的消息進入隊列;
在消息消費時,要求消息體中必需要有一個 bizId(對於同一業務全局惟一,如支付 ID、訂單 ID、帖子 ID 等)做爲去重的依據,避免同一條消息被重複消費。
六、消息基於什麼傳輸?
因爲 TCP 鏈接的建立和銷燬開銷較大,且併發數受系統資源限制,會形成性能瓶頸。RabbitMQ 使用信道的方式來傳輸數據。信道是創建在真實的 TCP 鏈接內的虛擬鏈接,且每條 TCP 鏈接上的信道數量沒有限制。
七、消息如何分發?
若該隊列至少有一個消費者訂閱,消息將以循環(round-robin)的方式發送給消費者。每條消息只會分發給一個訂閱的消費者(前提是消費者可以正常處理消息並進行確認)。
經過路由可實現多消費的功能
八、消息怎麼路由?
消息提供方->路由->一至多個隊列
消息發佈到交換器時,消息將擁有一個路由鍵(routing key),在消息建立時設定。
經過隊列路由鍵,能夠把隊列綁定到交換器上。
消息到達交換器後,RabbitMQ 會將消息的路由鍵與隊列的路由鍵進行匹配(針對不一樣的交換器有不一樣的路由規則);
經常使用的交換器主要分爲一下三種
fanout:若是交換器收到消息,將會廣播到全部綁定的隊列上 direct:若是路由鍵徹底匹配,消息就被投遞到相應的隊列
topic:能夠使來自不一樣源頭的消息可以到達同一個隊列。 使用 topic 交換器時,能夠使用通配符
九、如何確保消息不丟失?
消息持久化,固然前提是隊列必須持久化
RabbitMQ 確保持久性消息能從服務器重啓中恢復的方式是,將它們寫入磁盤上的一個持久化日誌文件,當發佈一條持久性消息到持久交換器上時,Rabbit 會在消息提交到日誌文件後才發送響應。
一旦消費者從持久隊列中消費了一條持久化消息,RabbitMQ 會在持久化日誌中把這條消息標記爲等待垃圾收集。若是持久化消息在被消費以前 RabbitMQ 重啓,那麼 Rabbit 會自動重建交換器和隊列(以及綁定),並從新發布持久化日誌文件中的消息到合適的隊列。
十、使用 RabbitMQ 有什麼好處?
一、 服務間高度解耦
二、 異步通訊性能高
三、 流量削峯
十一、RabbitMQ 的集羣
鏡像集羣模式
你建立的 queue,不管元數據仍是 queue 裏的消息都會存在於多個實例上,而後每次你寫消息到 queue 的時候,都會自動把消息到多個實例的 queue 裏進行消息同步。
好處在於,你任何一個機器宕機了,沒事兒,別的機器均可以用。壞處在於,第一,這個性能開銷也太大了吧,消息同步全部機器,致使網絡帶寬壓力和消耗很重!第二,這麼玩兒,就沒有擴展性可言了,若是某個 queue 負載很重,你加機器,新增的機器也包含了這個 queue 的全部數據,並無辦法線性擴展你的 queue
十二、mq 的缺點
系統可用性下降
系統引入的外部依賴越多,越容易掛掉,原本你就是 A 系統調用 BCD 三個系統的接口就行了,人 ABCD 四個系統好好的,沒啥問題,你偏加個 MQ 進來,萬一
MQ 掛了咋整?MQ 掛了,整套系統崩潰了,你不就完了麼。
系統複雜性提升
硬生生加個 MQ 進來,你怎麼保證消息沒有重複消費?怎麼處理消息丟失的狀況?怎麼保證消息傳遞的順序性?頭大頭大,問題一大堆,痛苦不已
一致性問題
A 系統處理完了直接返回成功了,人都覺得你這個請求就成功了;可是問題是,要是 BCD 三個系統那裏,BD 兩個系統寫庫成功了,結果 C 系統寫庫失敗了,咋整?你這數據就不一致了。
因此消息隊列實際是一種很是複雜的架構,你引入它有不少好處,可是也得針對它帶來的壞處作各類額外的技術方案和架構來規避掉,最好以後,你會發現,媽呀,系統複雜度提高了一個數量級,也許是複雜了 10 倍。可是關鍵時刻,用,仍是得用的
kafka 面試題
一、如何獲取 topic 主題的列表
bin/kafka-topics.sh --list --zookeeper localhost:2181
二、生產者和消費者的命令行是什麼?
生產者在主題上發佈消息:
bin/kafka-console-producer.sh --broker-list 192.168.43.49:9092 --topic Hello-Kafka
注意這裏的 IP 是 server.properties 中的 listeners 的配置。接下來每一個新行就是輸入一條新消息。消費者接受消息:
bin/kafka-console-consumer.sh --zookeeper localhost:2181 --topic Hello-Kafka --from-beginning
三、consumer 是推仍是拉?
Kafka 最初考慮的問題是,customer 應該從 brokes 拉取消息仍是 brokers 將消息推送到 consumer,也就是 pull 還 push。在這方面,Kafka 遵循了一種大部分消息系統共同的傳統的設計:producer 將消息推送到 broker,consumer 從 broker 拉取消息。
一些消息系統好比 Scribe 和 Apache Flume 採用了 push 模式,將消息推送到下游的 consumer。這樣作有好處也有壞處:由 broker 決定消息推送的速率,對於不一樣消費速率的 consumer 就不太好處理了。消息系統都致力於讓 consumer 以最大的速率最快速的消費消息,但不幸的是,push 模式下,當 broker 推送的速率遠大於 consumer 消費的速率時,consumer 恐怕就要崩潰了。最終 Kafka 仍是選取了傳統的 pull 模式。
Pull 模式的另一個好處是 consumer 能夠自主決定是否批量的從 broker 拉取數據。Push 模式必須在不知道下游 consumer 消費能力和消費策略的狀況下決定是當即推送每條消息仍是緩存以後批量推送。若是爲了不 consumer 崩潰而採用較低的推送速率,將可能致使一次只推送較少的消息而形成浪費。Pull 模式下, consumer 就能夠根據本身的消費能力去決定這些策略。
Pull 有個缺點是,若是 broker 沒有可供消費的消息,將致使 consumer 不斷在循環中輪詢,直到新消息到 t 達。爲了不這點,Kafka 有個參數可讓 consumer 阻塞知道新消息到達(固然也能夠阻塞知道消息的數量達到某個特定的量這樣就能夠批量發送)。
四、講講 kafka 維護消費狀態跟蹤的方法
大部分消息系統在 broker 端的維護消息被消費的記錄:一個消息被分發到
consumer 後 broker 就立刻進行標記或者等待 customer 的通知後進行標記。這樣也能夠在消息在消費後立馬就刪除以減小空間佔用。
可是這樣會不會有什麼問題呢?若是一條消息發送出去以後就當即被標記爲消費過的,一旦 consumer 處理消息時失敗了(好比程序崩潰)消息就丟失了。爲了解決這個問題,不少消息系統提供了另一個個功能:當消息被髮送出去以後僅僅被標記爲已發送狀態,當接到 consumer 已經消費成功的通知後才標記爲已被消費的狀態。這雖然解決了消息丟失的問題,但產生了新問題,首先若是 consumer 處理消息成功了可是向 broker 發送響應時失敗了,這條消息將被消費兩次。第二個問題時,broker 必須維護每條消息的狀態,而且每次都要先鎖住消息而後更改狀態而後釋放鎖。這樣麻煩又來了,且不說要維護大量的狀態數據,好比若是消
息發送出去但沒有收到消費成功的通知,這條消息將一直處於被鎖定的狀態,
Kafka 採用了不一樣的策略。Topic 被分紅了若干分區,每一個分區在同一時間只被一個 consumer 消費。這意味着每一個分區被消費的消息在日誌中的位置僅僅是一個簡單的整數:offset。這樣就很容易標記每一個分區消費狀態就很容易了,僅僅須要一個整數而已。這樣消費狀態的跟蹤就很簡單了。這帶來了另一個好處:consumer 能夠把 offset 調成一個較老的值,去從新消費老的消息。這對傳統的消息系統來講看起來有些難以想象,但確實是很是有用的,誰規定了一條消息只能被消費一次呢?
五、講一下主從同步**
https://blog.csdn.net/honglei915/article/details/37565289
六、爲何須要消息系統,mysql 不能知足需求嗎?
1.解耦:
容許你獨立的擴展或修改兩邊的處理過程,只要確保它們遵照一樣的接口約束。
2.冗餘:
消息隊列把數據進行持久化直到它們已經被徹底處理,經過這一方式規避了數據丟失風險。許多消息隊列所採用的」插入-獲取-刪除」範式中,在把一個消息從隊列中刪除以前,須要你的處理系統明確的指出該消息已經被處理完畢,從而確保你的數據被安全的保存直到你使用完畢。
3.擴展性:
由於消息隊列解耦了你的處理過程,因此增大消息入隊和處理的頻率是很容易的,只要另外增長處理過程便可。
4.靈活性 & 峯值處理能力:在訪問量劇增的狀況下,應用仍然須要繼續發揮做用,可是這樣的突發流量並不常見。若是爲以能處理這類峯值訪問爲標準來投入資源隨時待命無疑是巨大的浪費。使用消息隊列可以使關鍵組件頂住突發的訪問壓力,而不會由於突發的超負荷的請求而徹底崩潰。
5.可恢復性:
系統的一部分組件失效時,不會影響到整個系統。消息隊列下降了進程間的耦合度,因此即便一個處理消息的進程掛掉,加入隊列中的消息仍然能夠在系統恢復後被處理。
6.順序保證:
在大多使用場景下,數據處理的順序都很重要。大部分消息隊列原本就是排序的,而且能保證數據會按照特定的順序來處理。(Kafka 保證一個 Partition 內的消息的有序性)
7.緩衝:
有助於控制和優化數據流通過系統的速度,解決生產消息和消費消息的處理速度不一致的狀況。
8.異步通訊:
不少時候,用戶不想也不須要當即處理消息。消息隊列提供了異步處理機制,容許用戶把一個消息放入隊列,但並不當即處理它。想向隊列中放入多少消息就放多少,而後在須要的時候再去處理它們。
七、Zookeeper 對於 Kafka 的做用是什麼?
Zookeeper 是一個開放源碼的、高性能的協調服務,它用於 Kafka 的分佈式應用。
Zookeeper 主要用於在集羣中不一樣節點之間進行通訊
在 Kafka 中,它被用於提交偏移量,所以若是節點在任何狀況下都失敗了,它均可以從以前提交的偏移量中獲取
除此以外,它還執行其餘活動,如: leader 檢測、分佈式同步、配置管理、識別新節點什麼時候離開或鏈接、集羣、節點實時狀態等等。
八、數據傳輸的事務定義有哪三種?
和 MQTT 的事務定義同樣都是 3 種。
(1) 最多一次: 消息不會被重複發送,最多被傳輸一次,但也有可能一次不傳輸
(2) 最少一次: 消息不會被漏發送,最少被傳輸一次,但也有可能被重複傳輸.
(3) 精確的一次(Exactly once): 不會漏傳輸也不會重複傳輸,每一個消息都傳輸被一次並且僅僅被傳輸一次,這是你們所指望的
九、Kafka 判斷一個節點是否還活着有那兩個條件?
(1) 節點必須能夠維護和 ZooKeeper 的鏈接,Zookeeper 經過心跳機制檢查每一個節點的鏈接
(2) 若是節點是個 follower,他必須能及時的同步 leader 的寫操做,延時不能過久
十、Kafka 與傳統 MQ 消息系統之間有三個關鍵區別
(1).Kafka 持久化日誌,這些日誌能夠被重複讀取和無限期保留
(2).Kafka 是一個分佈式系統:它以集羣的方式運行,能夠靈活伸縮,在內部經過複製數據提高容錯能力和高可用性
(3).Kafka 支持實時的流式處理
十一、講一講 kafka 的 ack 的三種機制
request.required.acks 有三個值 0 1 -1(all)
0:生產者不會等待 broker 的 ack,這個延遲最低可是存儲的保證最弱當 server 掛掉的時候就會丟數據。
1:服務端會等待 ack 值 leader 副本確認接收到消息後發送 ack 可是若是 leader 掛掉後他不確保是否複製完成新 leader 也會致使數據丟失。
-1(all):服務端會等全部的 follower 的副本受到數據後纔會受到 leader 發出的 ack,這樣數據不會丟失
十二、消費者如何不自動提交偏移量,由應用提交?
將 auto.commit.offset 設爲 false,而後在處理一批消息後 commitSync() 或者異步提交 commitAsync()
即:
ConsumerRecords<> records = consumer.poll();
for (ConsumerRecord<> record : records){
。。。
tyr{
consumer.commitSync()
}
。。。
}
1三、消費者故障,出現活鎖問題如何解決?
出現「活鎖」的狀況,是它持續的發送心跳,可是沒有處理。爲了預防消費者在這種狀況下一直持有分區,咱們使用 max.poll.interval.ms 活躍檢測機制。 在此基礎上,若是你調用的 poll 的頻率大於最大間隔,則客戶端將主動地離開組,以便其餘消費者接管該分區。 發生這種狀況時,你會看到 offset 提交失敗(調用 commitSync()引起的 CommitFailedException)。這是一種安全機制,保障只有活動成員可以提交 offset。因此要留在組中,你必須持續調用 poll。
消費者提供兩個配置設置來控制 poll 循環:
max.poll.interval.ms:增大 poll 的間隔,能夠爲消費者提供更多的時間去處理返回的消息(調用 poll(long)返回的消息,一般返回的消息都是一批)。缺點是此值越大將會延遲組從新平衡。
max.poll.records:此設置限制每次調用 poll 返回的消息數,這樣能夠更容易的預測每次 poll 間隔要處理的最大值。經過調整此值,能夠減小 poll 間隔,減小從新平衡分組的
對於消息處理時間不可預測地的狀況,這些選項是不夠的。 處理這種狀況的推薦方法是將消息處理移到另外一個線程中,讓消費者繼續調用 poll。 可是必須注意確保已提交的 offset 不超過實際位置。另外,你必須禁用自動提交,並只有在線程完成處理後才爲記錄手動提交偏移量(取決於你)。 還要注意,你須要 pause 暫停分區,不會從 poll 接收到新消息,讓線程處理完以前返回的消息(若是你的處理能力比拉取消息的慢,那建立新線程將致使你機器內存溢出)。
1四、如何控制消費的位置
kafka 使用 seek(TopicPartition, long)指定新的消費位置。用於查找服務器保留的最先和最新的 offset 的特殊的方法也可用(seekToBeginning(Collection) 和
seekToEnd(Collection))
1五、kafka 分佈式(不是單機)的狀況下,如何保證消息的順序消費?
Kafka 分佈式的單位是 partition,同一個 partition 用一個 write ahead log 組織,因此能夠保證 FIFO 的順序。不一樣 partition 之間不能保證順序。可是絕大多數用戶均可以經過 message key 來定義,由於同一個 key 的 message 能夠保證只發送到同一個 partition。
Kafka 中發送 1 條消息的時候,能夠指定(topic, partition, key) 3 個參數。 partiton 和 key 是可選的。若是你指定了 partition,那就是全部消息發往同 1 個 partition,就是有序的。而且在消費端,Kafka 保證,1 個 partition 只能被 1 個 consumer 消費。或者你指定 key(好比 order id),具備同 1 個 key 的全部消息,會發往同 1 個 partition。
1六、kafka 的高可用機制是什麼?
這個問題比較系統,回答出 kafka 的系統特色,leader 和 follower 的關係,消息讀寫的順序便可。
http://www.javashuo.com/article/p-dmgubxay-ms.html https://www.tuicool.com/articles/BNRza2E
https://yq.aliyun.com/articles/64703
1七、kafka 如何減小數據丟失
http://www.javashuo.com/article/p-zpaltwiv-ms.html 1八、kafka 如何不消費重複數據?好比扣款,咱們不能重複的扣。 其實仍是得結合業務來思考,我這裏給幾個思路: 好比你拿個數據要寫庫,你先根據主鍵查一下,若是這數據都有了,你就別插入了,update 一下好吧。 好比你是寫 Redis,那沒問題了,反正每次都是 set,自然冪等性。 好比你不是上面兩個場景,那作的稍微複雜一點,你須要讓生產者發送每條數據的時候,裏面加一個全局惟一的 id,相似訂單 id 之類的東西,而後你這裏消費到了以後,先根據這個 id 去好比 Redis 裏查一下,以前消費過嗎?若是沒有消費過,你就處理,而後這個 id 寫 Redis。若是消費過了,那你就別處理了,保證別重複處理相同的消息便可。 好比基於數據庫的惟一鍵來保證重複數據不會重複插入多條。由於有惟一鍵約束了,重複數據插入只會報錯,不會致使數據庫中出現髒數據。 互聯網Java工程師面試題內容涵蓋:Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、 Redis、MySQL、Spring、Spring Boot、Spring Cloud、RabbitMQ、Kafka、 Linux 等技術棧