中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁(yè) > news >正文

湖南郴州市seo是做什么工作的

湖南郴州市,seo是做什么工作的,網(wǎng)站備案和域名備案有什么區(qū)別,內(nèi)江市建設(shè)教育培訓(xùn)官方網(wǎng)站Version : V1.0 北科Java面試寶典一、Java基礎(chǔ)面試題【24道】二、JVM虛擬機(jī)面試題【14道】三、集合相關(guān)面試題【17道】四、多線程 【25道】五、IO【5道】六、網(wǎng)絡(luò)編程 【9道】七、MySQL以及SQL面試題【20道】八、常用框架【19道】九、中間件和分布式 【54道】十、設(shè)計(jì)模式面試 …

Version : V1.0

  • 北科Java面試寶典
    • 一、Java基礎(chǔ)面試題【24道】
    • 二、JVM虛擬機(jī)面試題【14道】
    • 三、集合相關(guān)面試題【17道】
    • 四、多線程 【25道】
    • 五、IO【5道】
    • 六、網(wǎng)絡(luò)編程 【9道】
    • 七、MySQL以及SQL面試題【20道】
    • 八、常用框架【19道】
    • 九、中間件和分布式 【54道】
    • 十、設(shè)計(jì)模式面試 【2道】
    • 十一、 數(shù)據(jù)結(jié)構(gòu) 【19道】
    • 十二、 工具使用 【3道】

在這里插入圖片描述

北科Java面試寶典

一、Java基礎(chǔ)面試題【24道】

  1. 聊一聊Java平臺(tái)的理解!
    Java 本身是一種面向?qū)ο蟮恼Z(yǔ)言,最顯著的特性有兩個(gè)方面,一是所謂的“書寫一次,到處運(yùn)行”,能夠
    非常容易地獲得跨平臺(tái)能力;另外就是垃圾收集,Java 通過垃圾收集器回收分配內(nèi)存,大部分情況下,
    程序員不需要自己操心內(nèi)存的分配和回收。 一次編譯、到處運(yùn)行”說的是Java語(yǔ)言跨平臺(tái)的特性,Java的
    跨平臺(tái)特性與Java虛擬機(jī)的存在密不可分,可在不同的環(huán)境中運(yùn)行。比如說Windows平臺(tái)和Linux平臺(tái)
    都有相應(yīng)的JDK,安裝好JDK后也就有了Java語(yǔ)言的運(yùn)行環(huán)境。其實(shí)Java語(yǔ)言本身與其他的編程語(yǔ)言沒有
    特別大的差異,并不是說Java語(yǔ)言可以跨平臺(tái),而是在不同的平臺(tái)都有可以讓Java語(yǔ)言運(yùn)行的環(huán)境而
    已,所以才有了Java一次編譯,到處運(yùn)行這樣的效果。 Java具有三大特性: 封裝,繼承,多態(tài).利用這三大特
    性增加代碼的復(fù)用率和靈活度.
  2. String、StringBuffer、StringBuilder的區(qū)別!
    String的典型的不可變類型,內(nèi)部使用final關(guān)鍵字修飾,所以每次進(jìn)行字符串操作(拼接,截取等)都
    會(huì)產(chǎn)生新的對(duì)象!在開發(fā)中,會(huì)使用到大量的字符串操作!所以字符串的臨時(shí)對(duì)象,會(huì)對(duì)程序操作較大
    的性能開銷!產(chǎn)生了大量的內(nèi)存浪費(fèi)!
    StringBuilder比StringBuffer速度快, StringBuffer比String速度快
    StringBuffer線程安全
  3. int和Integer的區(qū)別!
    int是基本數(shù)據(jù)類型,是Java的8個(gè)原始數(shù)據(jù)類型之一,直接存數(shù)值。
    Integer是int對(duì)應(yīng)的包裝類,在拆箱和裝箱中java 可以根據(jù)上下文,自動(dòng)進(jìn)行轉(zhuǎn)換,極大地簡(jiǎn)化了相關(guān)
    編程。
    int是基本類型,Integer是對(duì)象,用一個(gè)引用指向這個(gè)對(duì)象。由于Integer是一個(gè)對(duì)象,在JVM中對(duì)象需
    要一定的數(shù)據(jù)結(jié)構(gòu)進(jìn)行描述,相比int而言,其占用的內(nèi)存更大一些。
  4. == 和 equals 的區(qū)別是什么?
    是直接比較的兩個(gè)對(duì)象的堆內(nèi)存地址,如果相等,則說明這兩個(gè)引用實(shí)際是指向同一個(gè)對(duì)象地址的。
    因此基本數(shù)據(jù)類型和String常量是可以直接通過
    來直接比較的。
    對(duì)于引用對(duì)象對(duì)比是否相等使用equals方法,equals方法比較的是對(duì)象中的值是否相等, 但是要從寫
    hashcode和equals
  5. 聊一聊JDK1.8版本的新特性!
    拉姆達(dá)表達(dá)式
    函數(shù)式接口,
    方法引用
    新的日期類LocalDate
    引入了stream類,支持鏈?zhǔn)骄幊?/li>
  6. final關(guān)鍵字的作用?
    final關(guān)鍵字可以用來修飾變量、方法和類。
    被final修飾的類該類成為最終類,無法被繼承。
    被final修飾的方法將成為最終方法,無法被子類重寫。但是,該方法仍然可以被繼承。
    final修飾類中的屬性或者變量
    無論屬性是基本類型還是引用類型,final所起的作用都是變量里面存放的“值”不能變。
    對(duì)于一個(gè)final變量,如果是基本數(shù)據(jù)類型的變量,則其數(shù)值一旦在初始化之后便不能更改;如果是引用
    類型的變量,則在對(duì)其初始化之后便不能再讓其指向另一個(gè)對(duì)象。
  7. 什么是內(nèi)存泄漏和內(nèi)存溢出!
    內(nèi)存泄漏(memoryleak),是指應(yīng)用程序在申請(qǐng)內(nèi)存后,無法釋放已經(jīng)申請(qǐng)的內(nèi)存空間,一次內(nèi)存泄漏危
    害可以忽略,但如果任其發(fā)展最終會(huì)導(dǎo)致內(nèi)存溢出(outofmemory)。如讀取 文件后流要進(jìn)行及時(shí)的
    關(guān)閉以及對(duì)數(shù)據(jù)庫(kù)連接的釋放。
    內(nèi)存溢出(outofmemory)是指應(yīng)用程序在申請(qǐng)內(nèi)存時(shí),沒有足夠的內(nèi)存空間供其使用。如我們?cè)陧?xiàng)目中
    對(duì)于大批量數(shù)據(jù)的導(dǎo)入,采用分批量提交的方式。
  8. 抽象類和接口的區(qū)別!
    抽象類 : 抽象類必須用 abstract 修飾,子類必須實(shí)現(xiàn)抽象類中的抽象方法,如果有未實(shí)現(xiàn)的,那么子類
    也必須用 abstract 修飾。抽象類默認(rèn)的權(quán)限修飾符為 public,可以定義為 public 或 procted,如果定
    義為 private,那么子類則無法繼承。抽象類不能創(chuàng)建對(duì)象
    接口和抽象類的區(qū)別 : 抽象類只能繼承一次,但是可以實(shí)現(xiàn)多個(gè)接口
    接口和抽象類必須實(shí)現(xiàn)其中所有的方法,抽象類中如果有未實(shí)現(xiàn)的抽象方法,那么子類也需要定義為抽
    象類。抽象類中可以有非抽象的方法
    接口中的變量必須用 public static final 修飾,并且需要給出初始值。所以實(shí)現(xiàn)類不能重新定義,也不能
    改變其值。
    接口中的方法默認(rèn)是 public abstract,也只能是這個(gè)類型。不能是 static,接口中的方法也不允許子類
    覆寫,抽象類中允許有static 的方法
  9. Error和Execption的區(qū)別?
    Exception 和 Error 都是繼承了 Throwable 類,在 Java 中只有 Throwable 類型的實(shí)例才可以被拋出
    (throw)或者捕獲(catch),它是異常處理機(jī)制的基本組成類型。
    Exception 和 Error 體現(xiàn)了 Java 平臺(tái)設(shè)計(jì)者對(duì)不同異常情況的分類。Exception 是程序正常運(yùn)行中,可
    以預(yù)料的意外情況,可能并且應(yīng)該被捕獲,進(jìn)行相應(yīng)處理。
    Error 是指在正常情況下,不大可能出現(xiàn)的情況,絕大部分的 Error 都會(huì)導(dǎo)致程序(比如 JVM自身)處于
    非正常的、不可恢復(fù)狀態(tài)。既然是非正常情況,所以不便于也不需要捕獲,常見的比如
    OutOfMemoryError 之類,都是 Error 的子類。
    Exception 又分為可檢查(checked)異常和不檢查(unchecked)異常,可檢查異常
  10. 說一說常見的Execption和解決方案!
    數(shù)組越界異常 : Java.lang.ArrayIndexOutofBoundsException
    產(chǎn)生的原因:訪問了不存在的索引
    解決的辦法:索引0到數(shù)組長(zhǎng)度-1的范圍內(nèi)取值
    空指針異常 : Java.lang.NullPointerException
    產(chǎn)生的原因:對(duì)象沒有創(chuàng)建就訪問了元素或者方法或者屬性
    解決的辦法: 先找出出現(xiàn)的所有引用類型,判斷哪個(gè)對(duì)象是沒有new的元素或者方法或者屬性,如
    果沒有就創(chuàng)建該對(duì)象
    沒有這樣的元素異常 : Java.util.NoSuchElementException
    產(chǎn)生的原因:在迭代器迭代的時(shí)候沒有下一個(gè)元素了
    解決的辦法:在迭代器之前做相對(duì)應(yīng)得判斷,如果沒有元素了就不迭代輸出了
    并發(fā)修改異常 : Java.util.ConcurrentModificationException
    產(chǎn)生的原因:在迭代器迭代的同時(shí)使用集合修改元素
    解決的辦法:使用普通for循環(huán)來遍歷 , 使用toArray來遍歷 , 使用ListIterator來遍歷
    類型轉(zhuǎn)換異常 : Java.lang.ClassCastException
    產(chǎn)生的原因:在向下轉(zhuǎn)型的過程中,沒有轉(zhuǎn)換成真實(shí)的類型
    解決的方法:在向下轉(zhuǎn)型之前使用instanceof關(guān)鍵字對(duì)所有子類做逐一判斷
    算法出錯(cuò)異常 : Java.lang.ArithmeticException
    產(chǎn)生的原因:除數(shù)不能為零
    解決的辦法:改變除數(shù)的結(jié)果再進(jìn)行測(cè)試
    沒有序列化異常 : Java.io.NotSerialzableException
    產(chǎn)生的原因:沒有實(shí)現(xiàn)serializable接口
    解決的辦法:對(duì)需要的寫入到文件的類實(shí)現(xiàn)serializable接口,表示允許該類的該類寫入到文件
  11. 重寫和重載區(qū)別
    重寫: 子類繼承父類, 在子類中存在和父類中一模一樣的方法, 從新編寫方法中的實(shí)現(xiàn)業(yè)務(wù)代碼.
    重載: 在同一個(gè)類中存在多個(gè)方法名相同, 傳參個(gè)數(shù),順序和類型不同, 返回值可以相同也可以不同的方法.
  12. 什么是反射, 反射的好處?
    Java 反射,就是在運(yùn)行狀態(tài)中:
    獲取任意類的名稱、package信息、所有屬性、方法、注解、類型、類加載器等
    獲取任意對(duì)象的屬性,并且能改變對(duì)象的屬性
    調(diào)用任意對(duì)象的方法
    判斷任意一個(gè)對(duì)象所屬的類
    實(shí)例化任意一個(gè)類的對(duì)象
    Java 的動(dòng)態(tài)就體現(xiàn)在這。通過反射我們可以實(shí)現(xiàn)動(dòng)態(tài)裝配,降低代碼的耦合度;動(dòng)態(tài)代理等。反射的過
    度使用會(huì)嚴(yán)重消耗系統(tǒng)資源。
  13. 事務(wù)控制在哪一層? 可否控制在dao層? 為什么?
    事務(wù)必須控制在service層, 不可以在dao層.
    因?yàn)閐ao層需要按照單一職責(zé)原則設(shè)計(jì), 一個(gè)類對(duì)應(yīng)一張表, 類中最好都是單表增刪改查, 增加代碼復(fù)
    用率而事務(wù)具有隔離性, service會(huì)調(diào)用多個(gè)dao方法組裝業(yè)務(wù), 如果事務(wù)控制在dao層就會(huì)被分隔成
    多個(gè)事務(wù), 無法整體控制
    所以事務(wù)必須控制在service層, 保證一套業(yè)務(wù)操作要么全成功, 要么全失敗.
  14. Cookie和session的區(qū)別和聯(lián)系?
    Cookie是客戶端瀏覽器用來保存數(shù)據(jù)的一塊空間, cookie沒有session安全, cookie中保存的數(shù)據(jù)量
    有大小限制
    Session是服務(wù)器端用來保存數(shù)據(jù)的一塊空間, session比較安全
    Cookie和session聯(lián)系:
    當(dāng)用戶第一次發(fā)送請(qǐng)求訪問網(wǎng)站的時(shí)候, cookie中沒有信息, 這個(gè)時(shí)候服務(wù)器就會(huì)生成一個(gè)session
    對(duì)象, 這個(gè)session對(duì)象有個(gè)唯一id叫做sessionID, 這個(gè)id會(huì)被保存到用戶的瀏覽器cookie中.
    當(dāng)用戶再次訪問服務(wù)器的時(shí)候, cookie中就會(huì)有sessionID, 會(huì)被帶到服務(wù)器, 服務(wù)器會(huì)根據(jù)這個(gè)id找
    到對(duì)應(yīng)的session對(duì)象使用.
    如果服務(wù)器沒有找到對(duì)應(yīng)的session對(duì)象則會(huì)新生成一個(gè)session對(duì)象, 然后將新的session對(duì)象的id
    再次寫入到cookie中保存.
  15. —個(gè)線程兩次調(diào)用start。方法會(huì)出現(xiàn)什么情況?
    Java的線程是不允許啟動(dòng)兩次的,第二次調(diào)用必然會(huì)拋出legalThreadStateException,這是一種運(yùn)行時(shí)
    異常,多次調(diào)用 start 被認(rèn)為是編程錯(cuò)誤。
  16. 談?wù)刦inal、finally、 finalize有什么不同!
    final 可以用來修飾類、方法、變量,分別有不同的意義,final 修飾的 class 代表不可以繼承擴(kuò)展,final
    的變量是不可以修改的,而 final 的方法也是不可以重寫的(override)。
    finally 則是 Java 保證重點(diǎn)代碼一定要被執(zhí)行的一種機(jī)制。我們可以使用 try-finally 或者 trycatch-finally
    來進(jìn)行類似關(guān)閉 JDBC 連接、保證 unlock 鎖等動(dòng)作。
    finalize 是基礎(chǔ)類 java.lang.Object 的一個(gè)方法,它的設(shè)計(jì)目的是保證對(duì)象在被垃圾收集前完成特定資源
    的回收。finalize 機(jī)制現(xiàn)在已經(jīng)不推薦使用,并且在 JDK 9 開始被標(biāo)記為deprecated。
  17. 強(qiáng)引用、軟引用、弱引用、幻象引用有什么區(qū)別!
    所謂強(qiáng)引用(“Strong” Reference) :
    就是我們最常見的普通對(duì)象引用,只要還有強(qiáng)引用指向一個(gè)對(duì)象,就能表明對(duì)象還“活著”,垃圾收
    集器不會(huì)碰這種對(duì)象。對(duì)于一個(gè)普通的對(duì)象,如果沒有其他的引用關(guān)系,只要超過了引用的作用域
    或者顯式地將相(強(qiáng))引用賦值為 null,就是可以被垃圾收集的了,當(dāng)然具體回收時(shí)機(jī)還是要看垃
    圾收集策略。
    軟引用(SoftReference) :
    是一種相對(duì)強(qiáng)引用弱化一些的引用,可以讓對(duì)象豁免一些垃圾收集,只有當(dāng) JVM 認(rèn)為內(nèi)存不足時(shí),
    才會(huì)去試圖回收軟引用指向的對(duì)象。JVM 會(huì)確保在拋出OutOfMemoryError 之前,清理軟引用指
    向的對(duì)象。軟引用通常用來實(shí)現(xiàn)內(nèi)存敏感的緩存,如果還有空閑內(nèi)存,就可以暫時(shí)保留緩存,當(dāng)內(nèi)
    存不足時(shí)清理掉,這樣就保證了使用緩存的同時(shí),不會(huì)耗盡內(nèi)存。
    弱引用(WeakReference):
    并不能使對(duì)象豁免垃圾收集,僅僅是提供一種訪問在弱引用狀態(tài)下對(duì)象的途徑。這就可以用來構(gòu)建
    一種沒有特定約束的關(guān)系,比如,維護(hù)一種非強(qiáng)制性的映射關(guān)系,如果試圖獲取時(shí)對(duì)象還在,就使
    用它,否則重現(xiàn)實(shí)例化。它同樣是很多緩存實(shí)現(xiàn)的選擇。
    幻象引用 :
    有時(shí)候也翻譯成虛引用,你不能通過它訪問對(duì)象?;孟笠脙H僅是提供了一種確保對(duì)象被 finalize
    以后,做某些事情的機(jī)制,比如,通常用來做所謂的 Post-Mortem 清理機(jī)制,我在專欄上一講中
    介紹的 Java 平臺(tái)自身 Cleaner 機(jī)制等,也有人利用幻象引用監(jiān)控對(duì)象的創(chuàng)建和銷毀。
  18. 父子類靜態(tài)代碼塊, 非靜態(tài)代碼塊, 構(gòu)造方法執(zhí)行順序
    父類 - 靜態(tài)代碼塊
    子類 - 靜態(tài)代碼塊
    父類 - 非靜態(tài)代碼
    父類 - 構(gòu)造函數(shù)
    子類 - 非靜態(tài)代碼
    子類 - 構(gòu)造函數(shù)
  19. 如何實(shí)現(xiàn)對(duì)象克隆
    實(shí)現(xiàn) Cloneable 接口并重寫 Object 類中的 clone()方法;
    實(shí)現(xiàn) Serializable 接口,通過對(duì)象的序列化和反序列化實(shí)現(xiàn)克隆,可以實(shí)現(xiàn)真正的深度克隆
  20. 什么是 java 序列化,如何實(shí)現(xiàn) java 序列化?
    序列化就是一種用來處理對(duì)象流的機(jī)制,所謂對(duì)象流也就是將對(duì)象的內(nèi)容進(jìn)行流化??梢詫?duì)流化后的對(duì)
    象進(jìn)行讀
    寫操作,也可將流化后的對(duì)象傳輸于網(wǎng)絡(luò)之間。序列化是為了解決在對(duì)對(duì)象流進(jìn)行讀寫操作時(shí)所引發(fā)的
    問題。
    序 列 化 的 實(shí) 現(xiàn) : 將 需 要 被 序 列 化 的 類 實(shí) 現(xiàn) Serializable 接 口
  21. 深拷貝和淺拷貝區(qū)別是什么?
    淺拷貝只是復(fù)制了對(duì)象的引用地址,兩個(gè)對(duì)象指向同一個(gè)內(nèi)存地址,所以修改其中任意的值,另一個(gè)值
    都會(huì)隨之變化,這就是淺拷貝
    深拷貝是將對(duì)象及值復(fù)制過來,兩個(gè)對(duì)象修改其中任意的值另一個(gè)值不會(huì)改變,這就是深拷貝
  22. jsp 和 servlet 有什么區(qū)別?
    jsp經(jīng)編譯后就變成了Servlet.(JSP的本質(zhì)就是Servlet,JVM只能識(shí)別Java的類,不能識(shí)別JSP的代碼,
    Web容器將JSP的代碼編譯成JVM能夠識(shí)別的Java類)
    jsp更擅長(zhǎng)表現(xiàn)于頁(yè)面顯示,servlet更擅長(zhǎng)于邏輯控制。
  23. 說一下 jsp 的 4 種作用域?
    JSP中的四種作用域包括page、request、session和application:
    page : 代表與一個(gè)頁(yè)面相關(guān)的對(duì)象和屬性。
    request : 代表與Web客戶機(jī)發(fā)出的一個(gè)請(qǐng)求相關(guān)的對(duì)象和屬性。一個(gè)請(qǐng)求可能跨越多個(gè)頁(yè)面,涉
    及多個(gè)Web組件;需要在頁(yè)面顯示的臨時(shí)數(shù)據(jù)可以置于此作用域。
    session : 代表與某個(gè)用戶與服務(wù)器建立的一次會(huì)話相關(guān)的對(duì)象和屬性。跟某個(gè)用戶相關(guān)的數(shù)據(jù)應(yīng)該
    放在用戶自己的session中。
    application : 代表與整個(gè)Web應(yīng)用程序相關(guān)的對(duì)象和屬性,它實(shí)質(zhì)上是跨越整個(gè)Web應(yīng)用程序,包
    括多個(gè)頁(yè)面、請(qǐng)求和會(huì)話的一個(gè)全局作用域。
  24. 請(qǐng)求轉(zhuǎn)發(fā)(forward)和重定向(redirect)的區(qū)別?
    請(qǐng)求轉(zhuǎn)發(fā)forward比重定向redirect快
    請(qǐng)求轉(zhuǎn)發(fā)的url地址只能是本網(wǎng)站內(nèi)部地址, 重定向的url地址可以是外部網(wǎng)站地址
    請(qǐng)求轉(zhuǎn)發(fā)瀏覽器url不發(fā)生變化, 重定向?yàn)g覽器url地址發(fā)生改變.
    請(qǐng)求轉(zhuǎn)發(fā)request域中的數(shù)據(jù)可以帶到轉(zhuǎn)發(fā)后的方法中, 重定向request域中的數(shù)據(jù)無法帶到重定向后的
    方法中.

二、JVM虛擬機(jī)面試題【14道】

  1. JDK1.7、1.8的JVM內(nèi)存模型,哪些區(qū)域可能發(fā)生OOM(out of memory)內(nèi)存溢出!
    Out of memory: 堆內(nèi)存溢出
    JDK 1.7:有永久代,但已經(jīng)把字符串常量池、靜態(tài)變量,存放在堆上。逐漸的減少永久代的使用。
    JDK 1.8:無永久代,運(yùn)行時(shí)常量池、類常量池,都保存在元空間。但字符串常量池仍然存放在堆上。
    JVM 內(nèi)存區(qū)域劃分圖 :
    內(nèi)存溢出通俗的講就是內(nèi)存不夠用了,并且 GC 通過垃圾回收也無法提供更多的內(nèi)存。實(shí)際上除了程序
    計(jì)數(shù)器,其他區(qū)域都有可能發(fā)生 OOM, 簡(jiǎn)單總結(jié)如下:
    【1】堆內(nèi)存不足是最常見的 OOM 原因之一,拋出錯(cuò)誤信息
    java.lang.OutOfMemoryError:Java heap space
    原因也不盡相同,可能是內(nèi)存泄漏,也有可能是堆的大小設(shè)置不合理。
    【2】對(duì)于虛擬機(jī)棧和本地方法棧,導(dǎo)致 OOM 一般為對(duì)方法自身不斷的遞歸調(diào)用,且 沒有結(jié)束點(diǎn),導(dǎo)
    致不斷的壓棧操作。類似這種情況,JVM 實(shí)際會(huì)拋出 StackOverFlowError , 但是如果 JVM 試圖去拓展棧
    空間的時(shí)候,就會(huì)拋出 OOM.
    【3】對(duì)于老版的 JDK, 因?yàn)橛谰么笮∈怯邢薜?#xff0c;并且 JVM 對(duì)老年代的內(nèi)存回收非常不積極,所以當(dāng)我
    們添加新的對(duì)象,老年代發(fā)生 OOM 的情況也非常常見。
    【4】隨著元數(shù)據(jù)區(qū)的引入,方法區(qū)內(nèi)存已經(jīng)不再那么窘迫,所以相應(yīng)的 OOM 有所改 觀,出現(xiàn) OOM,
    異常信息則變成了:“java.lang.OutOfMemoryError: Metaspace”。
  2. 請(qǐng)介紹類加載過程和雙親委派模型!
    類加載過程 : 加載 -> 連接 -> 驗(yàn)證 -> 準(zhǔn)備 -> 解析 -> 初始化
    雙親委派模型: 先找父類加載器, 讓父類加載器加載, 如果父類加載器無法加載就讓子類加載器加載.這個(gè)
    加載過程叫做雙親委派模型或者雙親委派機(jī)制.
  3. 談一談堆和棧的區(qū)別!
    棧: 存儲(chǔ)局部變量, 基本類型數(shù)據(jù), 動(dòng)態(tài)鏈接(堆中對(duì)象的內(nèi)存地址)
    堆: 凡是new出來的對(duì)象都在堆中, 也就是存儲(chǔ)數(shù)組和對(duì)象,垃圾回收器不定期到堆中收取垃圾.
  4. 說一說jvm常見垃圾回收器和特點(diǎn)!
    按照內(nèi)存空間來劃分,年輕代的垃圾回收器有:
    Serial:是一個(gè)串行的垃圾回收器
    ParNew:是Serial的并行版本
    Parallel Scavenge:也是一個(gè)并行的垃圾回收器,區(qū)別在于它注重吞吐量
    年輕代的三個(gè)垃圾回收器采用的垃圾回收算法都是復(fù)制算法,所以在進(jìn)行垃圾回收時(shí)都會(huì)暫停所有的用
    戶線程;
    然后是老年代的垃圾回收器:
    Serial Old:是Serial的老年代版本,串行,采用的是標(biāo)記-整理算法,同樣會(huì)STW
    Parallel Old:是Parallel Scavenge的老年代版本,并行,采用的是標(biāo)記-整理算法,會(huì)STW,注重
    吞吐量
    CMS:注重低延遲,采用的是標(biāo)記-清除算法,分為四個(gè)階段:初始標(biāo)記、并發(fā)標(biāo)記、重新標(biāo)記、
    并發(fā)清除;在初始化和重新標(biāo)記階段中是并行的,會(huì)STW,其余兩個(gè)階段都是并發(fā)執(zhí)行與用戶線程
    同時(shí)執(zhí)行;由于采用標(biāo)記清理算法,會(huì)產(chǎn)生空間碎片
    最后是整堆收集器:G1收集器,G1收集器的特點(diǎn)有:能夠獨(dú)立管理整個(gè)堆空間、可利用多CPU、多核的
    硬件優(yōu)勢(shì)縮短STW的時(shí)間、采用分代收集算法不會(huì)產(chǎn)生空間碎片
  5. Java創(chuàng)建對(duì)象的過程!
    對(duì)象的創(chuàng)建過程一般是從new指令開始的,JVM首先會(huì)對(duì)符號(hào)引用進(jìn)行解析,解析完畢后JVM會(huì)為對(duì)象在
    堆中分配內(nèi)存,之后,JVM會(huì)將該內(nèi)存進(jìn)行零值初始化。最后,JVM會(huì)調(diào)用對(duì)象的構(gòu)造函數(shù)。此時(shí),一般
    會(huì)有一個(gè)引用指向這個(gè)對(duì)象,將對(duì)象的地址值賦值給變量。在Java對(duì)象初始化過程中,主要涉及三種執(zhí)
    行對(duì)象初始化的結(jié)構(gòu),分別是 實(shí)例變量初始化、實(shí)例代碼塊初始化 以及 構(gòu)造函數(shù)初始化。
  6. Java中垃圾回收機(jī)制
    垃圾回收機(jī)制用到finalize。當(dāng)程序創(chuàng)建對(duì)象、數(shù)組等引用類型實(shí)體時(shí),系統(tǒng)都會(huì)在堆內(nèi)存中為之分
    配一塊內(nèi)存區(qū),對(duì)象就保存在這塊內(nèi)存中,當(dāng)這塊內(nèi)存不再被任何引用變量引用時(shí),這塊內(nèi)存就會(huì)
    變成垃圾,等待垃圾回收機(jī)制進(jìn)行回收。
    分析對(duì)象是否為垃圾的方法 : 可達(dá)性分析法, 引用計(jì)數(shù)法兩種
    強(qiáng)制垃圾回收 : 當(dāng)一個(gè)對(duì)象失去引用后,系統(tǒng)何時(shí)調(diào)用它的finalize ()方法對(duì)它進(jìn)行資源清理,何時(shí)
    它會(huì)變成不可達(dá)狀態(tài),系統(tǒng)何時(shí)回收它所占有的內(nèi)存。對(duì)于系統(tǒng)程序完全透明。程序只能控制一個(gè)
    對(duì)象任何不再被任何引用變量引用,絕不能控制它何時(shí)被回收。強(qiáng)制只是建議系統(tǒng)立即進(jìn)行垃圾回
    收,系統(tǒng)完全有可能并不立即進(jìn)行垃圾回收,垃圾回收機(jī)制也不會(huì)對(duì)程序的建議置之不理:垃圾回收
    機(jī)制會(huì)在收到通知后,盡快進(jìn)行垃圾回收。
    強(qiáng)制垃圾回收的兩個(gè)方法 : 調(diào)用System類的gc()靜態(tài)方法System.gc(), 調(diào)用Runtime對(duì)象的gc()實(shí)例
    方法:Runtime.getRuntime().gc()方法
    垃圾回收基本算法有四種 : 引用計(jì)數(shù)法, 標(biāo)記清除法, 標(biāo)記壓縮法, 復(fù)制算法
    垃圾回收復(fù)合算法 – 分代收集算法:
    當(dāng)前虛擬機(jī)的垃圾收集都采用分代收集算法,這種算法就是根據(jù)具體的情況選擇具體的垃圾回收算
    法。一般將java 堆分為新生代和老年代,這樣我們就可以根據(jù)各個(gè)年代的特點(diǎn)選擇合適的垃圾收集
    算法。
    比如在新生代中,每次收集都會(huì)有大量對(duì)象死去,所以可以選擇復(fù)制算法,只需要付出少量對(duì)象的
    復(fù)制成本就可以完成每次垃圾收集。而老年代的對(duì)象存活幾率是比較高的,而且沒有額外的空間對(duì)
    它進(jìn)行分配擔(dān)保,所以我們必須選擇“標(biāo)記-清除”或“標(biāo)記-壓縮”算法進(jìn)行垃圾收集。
  7. Java中垃圾回收算法
    (1)標(biāo)記-清除算法:使用可達(dá)性分析算法標(biāo)記內(nèi)存中的垃圾對(duì)象,并直接清理,容易造成空間碎片
    (2)標(biāo)記-壓縮算法:在標(biāo)記-清除算法的基礎(chǔ)上,將存活的對(duì)象整理在一起保證空間的連續(xù)性
    (3)復(fù)制算法:將內(nèi)存空間劃分成等大的兩塊區(qū)域,from和to只用其中的一塊區(qū)域,收集垃圾時(shí)將存
    活的對(duì)象復(fù)制到另一塊區(qū)域中,并清空使用的區(qū)域;解決了空間碎片的問題,但是空間的利用率低
    (4)復(fù)合算法 - 分代收集算法:是對(duì)前三種算法的整合,將內(nèi)存空間分為老年代和新生代,新生代中存
    儲(chǔ)一些生命周期短的對(duì)象,使用復(fù)制算法;而老年代中對(duì)象的生命周期長(zhǎng),則使用標(biāo)記-清除或標(biāo)記-整
    理算法。
  8. YoungGC和FullGC觸發(fā)時(shí)機(jī)?
    Young GC :Young GC其實(shí)一般就是在新生代的Eden區(qū)域滿了之后就會(huì)觸發(fā),采用復(fù)制算法來回
    收新生代的垃圾。
    Full GC : 調(diào)用System.gc()時(shí)。系統(tǒng)建議執(zhí)行Full GC,但是不必然執(zhí)行
    觸發(fā)時(shí)機(jī) :
    老年代空間不足
    方法區(qū)空間不足
    進(jìn)入老年代的平均大小大于老年代的可用內(nèi)存
    由Eden區(qū),幸存者0區(qū)向幸存者1區(qū)復(fù)制時(shí),對(duì)象大小大于1區(qū)可用內(nèi)存,則把該對(duì)象轉(zhuǎn)存到
    老年代,且老年代的可用內(nèi)存大小小于該對(duì)象大小。
    注意:full GC是開發(fā)或調(diào)優(yōu)中盡量要避免的,這樣STW會(huì)短一些
  9. FullGC觸發(fā)可能產(chǎn)生什么問題
    fullgc的時(shí)候除gc線程外的所有用戶線程處于暫停狀態(tài),也就是不會(huì)有響應(yīng)了。一般fullgc速度很快,毫秒級(jí)
    的,用戶無感知。除非內(nèi)存特別大上百G的,或者fullgc也無法收集到足夠內(nèi)存導(dǎo)致一直fullgc,應(yīng)用的外在表
    現(xiàn)就是程序卡死了.
  10. jvm調(diào)優(yōu)工具和性能調(diào)優(yōu)思路?
    Jvm中調(diào)優(yōu)使用的分析命令如下, 先試用下面命令分析jvm中的問題 :
    Jps : 用于查詢正在運(yùn)行的JVM進(jìn)程。 直接獲取進(jìn)程的pid
    Jstat : 可以實(shí)時(shí)顯示本地或遠(yuǎn)程JVM進(jìn)程中裝載,內(nèi)存,垃圾信息,JIT編譯等數(shù)據(jù)
    Jinfo : 用于查詢當(dāng)前運(yùn)行著的JVM屬性和參數(shù)的值
    Jmap : 用于顯示當(dāng)前java堆和永生代的詳細(xì)信息
    Jhat : 用于分析使用jmap生成的dump文件,是JDK自帶的工具
    Jstack: 用于生成當(dāng)JVM所有線程快照,線程快照是虛擬機(jī)每一條線程正在執(zhí)行的方法,目的是定位
    線程出現(xiàn)長(zhǎng)時(shí)間停頓的原因。
    下面是JVM常見的調(diào)優(yōu)參數(shù), 經(jīng)過上面命令分析定位問題后使用下面參數(shù)優(yōu)化:
    -Xmx 指定java程序的最大堆內(nèi)存
    -Xms 指定最小堆內(nèi)存
    -Xmn 設(shè)置年輕代大小 , 整個(gè)堆大小=年輕代大小+年老代大小。所以增大年輕代后,會(huì)減小年老代
    大小。此值對(duì)系統(tǒng)影響較大,Sun官方推薦為整個(gè)堆的3/8
    -Xss 指定線程的最大??臻g,此參數(shù)決定了java函數(shù)調(diào)用的深度,值越大說明調(diào)用深度越深,若值
    太小則容易棧溢出錯(cuò)誤(StackOverflowError)
    -XX: PermSize 指定方法區(qū)(永久區(qū))的初始值默認(rèn)是物理內(nèi)存的1/64。
    -XX:MetaspaceSize指定元數(shù)據(jù)區(qū)大小, 在Java8中,永久區(qū)被移除,代之的是元數(shù)據(jù)區(qū)
    -XX:NewRatio=n 年老代與年輕代的比值,-XX:NewRatio=2,表示年老代和年輕代的比值為2:1
    -XX:SurvivorRatio=n Eden區(qū)與Survivor區(qū)的大小比值,-XX:SurvivorRatio=8表示Eden區(qū)與
    Survivor區(qū)的大小比值是8:1:1,因?yàn)镾urvivor區(qū)有兩個(gè)(from,to);
  11. Jvm內(nèi)存模型?
    注意 : 大多數(shù)面試官混淆了內(nèi)存模型和內(nèi)存結(jié)構(gòu)的區(qū)別, 如果面試官這么問, 可以咨詢下面試官是否問的
    是jvm內(nèi)存的結(jié)構(gòu)都包含哪些東西, 還是問JMM(Java memory model)內(nèi)存模型原理
    Jvm內(nèi)存結(jié)構(gòu)由9塊組成:
    類加載器, 垃圾回收器, 執(zhí)行引擎, 方法區(qū), 堆, 棧, 直接內(nèi)存, 本地方法棧, 程序計(jì)數(shù)器(pc寄存器)
    JMM(java memory model)java內(nèi)存模型:
    JMM規(guī)定了所有變量(除了方法參數(shù)和本地變量,包括實(shí)例變量和靜態(tài)變量)都放在主內(nèi)存中。每
    個(gè)線程都有自己的工作內(nèi)存,工作內(nèi)存保存了該線程使用的主內(nèi)存的變量副本,所有的操作都在工
    作內(nèi)存中進(jìn)行,線程不能直接操作主內(nèi)存。線程之間通過將數(shù)據(jù)刷回主內(nèi)存的方式進(jìn)行通信。
    JMM定義了原子性,可見性和有序性。
    原子性:一個(gè)操作不可分割,不可中斷,不可被其他線程干擾。JMM提供moniterenter和
    monitereixt倆個(gè)字節(jié)碼指令保證代碼塊的原子性
    可見性:當(dāng)一個(gè)變量被修改后,其他線程能夠立即看到修改的結(jié)果
    有序性:禁止指令重排序
  12. GC如何識(shí)別垃圾?
    引用計(jì)數(shù)算法(已被淘汰的算法)
    給對(duì)象中添加一個(gè)引用計(jì)數(shù)器,每當(dāng)有一個(gè)地方引用它時(shí),計(jì)數(shù)器值就加1;當(dāng)引用失效時(shí),計(jì)數(shù)器值就
    減1;任何時(shí)刻計(jì)數(shù)器為0的對(duì)象就是不可能再被使用的。
    可達(dá)性分析算法
    目前主流的編程語(yǔ)言(java,C#等)的主流實(shí)現(xiàn)中,都是稱通過可達(dá)性分析(Reachability Analysis)來判
    定對(duì)象是否存活的。這個(gè)算法的基本思路就是通過一系列的稱為“GC Roots”的對(duì)象作為起始點(diǎn),從這
    些節(jié)點(diǎn)開始向下搜索,搜索所走過的路徑稱為引用鏈(Reference Chain),當(dāng)一個(gè)對(duì)象到GC Roots沒有
    任何引用鏈相連, 就是從GC Roots到這個(gè)對(duì)象不可達(dá)時(shí),則證明此對(duì)象是不可用的。
    分配流程
  13. 詳細(xì)介紹一下 CMS 垃圾回收器?
    CMS 是英文 Concurrent Mark-Sweep 的簡(jiǎn)稱,是以犧牲吞吐量為代價(jià)來獲得最短回收停頓時(shí)間的垃圾
    回收器。對(duì)于要求服務(wù)器響應(yīng)速度的應(yīng)用上,這種垃圾回收器非常適合。
    在啟動(dòng) JVM 的參數(shù)加上“-XX:+UseConcMarkSweepGC”來指定使用 CMS 垃圾回收器。
    CMS 使用的是標(biāo)記-清除的算法實(shí)現(xiàn)的,所以在 gc 的時(shí)候會(huì)產(chǎn)生大量的內(nèi)存碎片,當(dāng)剩余內(nèi)存不能滿足
    程序運(yùn)行要求時(shí),系統(tǒng)將會(huì)出現(xiàn) Concurrent Mode Failure,臨時(shí) CMS 會(huì)采用 Serial Old 回收器進(jìn)行垃
    圾清除,此時(shí)的性能將會(huì)被降低。
    CMS 工作機(jī)制相比其他的垃圾收集器來說更復(fù)雜,整個(gè)過程分為以下 4 個(gè)階段:
    (1)初始標(biāo)記
    只是標(biāo)記一下 GC Roots 能直接關(guān)聯(lián)的對(duì)象,速度很快,仍然需要暫停所有的工作線程。
    (2)并發(fā)標(biāo)記
    進(jìn)行 GC Roots 跟蹤的過程,和用戶線程一起工作,不需要暫停工作線程。
    (3)重新標(biāo)記
    為了修正在并發(fā)標(biāo)記期間,因用戶程序繼續(xù)運(yùn)行而導(dǎo)致標(biāo)記產(chǎn)生變動(dòng)的那一部分對(duì)象的標(biāo)記記錄,
    仍然需要暫停所有的工作線程。
    (4)并發(fā)清除
    清除 GC Roots 不可達(dá)對(duì)象,和用戶線程一起工作,不需要暫停工作線程。由于耗時(shí)最長(zhǎng)的并發(fā)標(biāo)
    記和并發(fā)清除過程中,垃圾收集線程可以和用戶現(xiàn)在一起并發(fā)工作, 所以總體上來看CMS 收集器的內(nèi)存
    回收和用戶線程是一起并發(fā)地執(zhí)行。
  14. Java創(chuàng)建對(duì)象的內(nèi)存分配流程?

三、集合相關(guān)面試題【17道】

  1. 聊一聊Java中容器體系結(jié)構(gòu)!
    Collection:集合接口
    List:是Collection的子接口,用來存儲(chǔ)有序的數(shù)據(jù)集合
    ArrayList:是List集合的實(shí)現(xiàn)類,底層采用動(dòng)態(tài)數(shù)組進(jìn)行存儲(chǔ)數(shù)據(jù),默認(rèn)是空數(shù)組,如果存值則
    擴(kuò)容至10,如果不夠則以1.5倍進(jìn)行擴(kuò)容。
    LinkedList:是List集合的實(shí)現(xiàn)類,底層采用雙向鏈表結(jié)構(gòu)進(jìn)行存儲(chǔ)數(shù)據(jù),增刪數(shù)據(jù)比較方便,
    速度快。
    Vector :Vector類實(shí)現(xiàn)了可擴(kuò)展的對(duì)象數(shù)組, 像數(shù)組一樣,它包含可以使用整數(shù)索引訪問的組
    件。但是,Vector的大小可以根據(jù)需要增長(zhǎng)或縮小,以適應(yīng)在創(chuàng)建Vector之后添加和刪除。
    【注】Vector是同步的(線程安全)。 如果不需要線程安全的實(shí)現(xiàn),建議使用ArrayList代替
    Vector.
    Set: 是Collection的子接口,用來存儲(chǔ)無序的數(shù)據(jù)集合
    HashSet:底層采用哈希表(HashMap)的方式存儲(chǔ)數(shù)據(jù),數(shù)據(jù)無序且唯一
    TreeSet:采用有序二叉樹進(jìn)行存儲(chǔ)數(shù)據(jù),遵循了自然排序。
    Map: 與Collection并列,用來存儲(chǔ)具有映射關(guān)系(key-value)的數(shù)據(jù)
    HashMap:哈希表結(jié)構(gòu)存儲(chǔ)數(shù)據(jù),key值可以為null
    TreeMap:紅黑樹算法的實(shí)現(xiàn)
    HashTable:哈希表實(shí)現(xiàn),key值不可以為null
    Properties:HashTable的子類,鍵值對(duì)存儲(chǔ)數(shù)據(jù)均為String類型,主要用來操作以.properties
    結(jié)尾的配置文件。
    【特點(diǎn)】存儲(chǔ)數(shù)據(jù)是以key,value對(duì)進(jìn)行存儲(chǔ),其中key值是以Set集合形式存儲(chǔ),唯一且不可重復(fù)。
    value是以Collection形式存儲(chǔ),可以重復(fù)。
  2. List、Set和Map的區(qū)別,以及各自的優(yōu)缺點(diǎn)
    List :
    可以允許重復(fù)的對(duì)象。可以插入多個(gè)null元素。是一個(gè)有序容器,保持了每個(gè)元素的插入順
    序,輸出的順序就是插入的順序。
    常用的實(shí)現(xiàn)類有 ArrayList、LinkedList 和 Vector。ArrayList 最為流行,它提供了使用索引的
    隨意訪問,而 LinkedList 則對(duì)于經(jīng)常需要從 List 中添加或刪除元素的場(chǎng)合更為合適。
    Set :
    不允許重復(fù)對(duì)象。無序容器,你無法保證每個(gè)元素的存儲(chǔ)順序,TreeSet通過 Comparator 或
    者 Comparable 維護(hù)了一個(gè)排序順序。只允許一個(gè) null 元素。
    Set 接口最流行的幾個(gè)實(shí)現(xiàn)類是 HashSet、LinkedHashSet 以及 TreeSet。最流行的是基于
    HashMap 實(shí)現(xiàn)的 HashSet;TreeSet 還實(shí)現(xiàn)了 SortedSet 接口,因此 TreeSet 是一個(gè)根據(jù)其
    compare() 和 compareTo() 的定義進(jìn)行排序的有序容器。而且可以重復(fù)。
    Map :
    Map不是collection的子接口或者實(shí)現(xiàn)類。Map是一個(gè)接口。
    Map 的 每個(gè) Entry 都持有兩個(gè)對(duì)象,也就是一個(gè)鍵一個(gè)值,Map 可能會(huì)持有相同的值對(duì)象但
    鍵對(duì)象必須是唯一的。
    TreeMap 也通過 Comparator 或者 Comparable 維護(hù)了一個(gè)排序順序。
    Map 里你可以擁有隨意個(gè) null 值但最多只能有一個(gè) null 鍵。
    Map 接口最流行的幾個(gè)實(shí)現(xiàn)類是 HashMap、LinkedHashMap、Hashtable 和 TreeMap。
    (HashMap、TreeMap最常用)
  3. ArrayList,LinkedList,Vector的區(qū)別!
    ArrayList和Vector是基于數(shù)組實(shí)現(xiàn)的。 ArrayList線程不安全,速度快, Vector線程安全,速度慢, 因?yàn)?br /> 底層數(shù)組實(shí)現(xiàn)所以查詢快, 修改快, 添加和刪除慢,
    LinkedList是基于雙向鏈表實(shí)現(xiàn)的, 線程不安全, 添加, 刪除快, 查詢和修改慢.
    ArrayList和Vector都是使用Object的數(shù)組形式來存儲(chǔ)的,當(dāng)向這兩種類型中增加元素的時(shí)候,若容
    量不夠,需要進(jìn)行擴(kuò)容。ArrayList擴(kuò)容后的容量是之前的1.5倍,然后把之前的數(shù)據(jù)拷貝到新建的
    數(shù)組中去。而Vector默認(rèn)情況下擴(kuò)容后的容量是之前的2倍。
    Vector可以設(shè)置容量增量,而ArrayList不可以。
  4. TreeSet如何保證對(duì)象的有序性!
    TreeSet是有序不可重復(fù)集,具有以下特點(diǎn):
    數(shù)據(jù)會(huì)按自然排序(可以理解為從小到大排序)
    不可存儲(chǔ)null
    數(shù)據(jù)不可重復(fù)
    非線程安全
    TreeSet底層依賴于TreeMap,TreeMap的數(shù)據(jù)結(jié)構(gòu)是二叉樹(紅黑樹),由底層數(shù)據(jù)結(jié)構(gòu)決定了
    TreeSet中元素有序且唯一。
    我們使用TreeSet時(shí),如果添加對(duì)象的話,我們就必須去實(shí)現(xiàn)Comparable接口,當(dāng)然也可以實(shí)現(xiàn)
    Comparator接口來保證對(duì)象的有序性。
  5. HashTable、HashMap、TreeMap的區(qū)別!
    Hashtable、HashMap、TreeMap都實(shí)現(xiàn)了Map接口,使用鍵值對(duì)的形式存儲(chǔ)數(shù)據(jù)和操作數(shù)據(jù)。
    Hashtable是java早期提供的,方法是同步的(加了synchronized)。key和value都不能是null
    值。
    HashMap的方法不是同步的,支持key和value為null的情況。行為上基本和Hashtable一致。由于
    Hashtable是同步的,性能開銷比較大,一般不推薦使用Hashtable。通常會(huì)選擇使用HashMap。
    HashMap進(jìn)行put和get操作,基本上可以達(dá)到常數(shù)時(shí)間的性能
    TreeMap是基于紅黑樹的一種提供順序訪問的Map,和HashMap不同,它的get或put操作的時(shí)間
    復(fù)雜度是O(log(n))。具體的順序由指定的Comparator來決定,或者根據(jù)鍵key的具體順序來決定。
    關(guān)系圖:
  6. HashMap的底層數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)
    JDK1.7采用 : 數(shù)組 + 鏈表結(jié)構(gòu)
    JDK1.8采用 : 數(shù)組 + 鏈表 + 紅黑樹
    紅黑樹:jdk1.8最重要的就是引入了紅黑樹的設(shè)計(jì),當(dāng)hash表的單一鏈表長(zhǎng)度超過 8 個(gè)的時(shí)候,鏈表結(jié)
    構(gòu)就會(huì)轉(zhuǎn)為紅黑樹結(jié)構(gòu)。
    HashMap的底層數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)為哈希表加紅黑樹。實(shí)現(xiàn)過程如下:
    調(diào)用HashMap的無參構(gòu)造方法,加載因子loadFactor賦值0.75,table數(shù)組是空。
    當(dāng)添加第一個(gè)元素時(shí),創(chuàng)建長(zhǎng)度16的數(shù)組,threshold=12。
    當(dāng)‘鏈表長(zhǎng)度大于等于8時(shí),并且數(shù)組長(zhǎng)度大于等于64時(shí),鏈表調(diào)整紅黑樹
    當(dāng)紅黑樹的節(jié)點(diǎn)個(gè)數(shù)小于6時(shí),調(diào)整為鏈表
    當(dāng)HashMap的容量超出閾值時(shí),擴(kuò)容為原來大小的2倍,減少元素的移動(dòng),提高效率。
  7. HashMap的擴(kuò)容機(jī)制
    為什么會(huì)需要擴(kuò)容:
    當(dāng)它在初始化時(shí)會(huì)創(chuàng)建一個(gè)容量為16的數(shù)組,當(dāng)元素?cái)?shù)量超過閾值(當(dāng)前容量X加載因子(通
    常為0.75)=擴(kuò)容閾值)時(shí),會(huì)將數(shù)組大小擴(kuò)展為當(dāng)前容量的兩倍。
    但是HashMap的容量是有上限的。如果hashmap的數(shù)組當(dāng)前容量達(dá)到了1073741824,則該
    數(shù)組不會(huì)再增長(zhǎng)。且閾值將被設(shè)置為Integer.MAX_VALUE(2^31-1)即永遠(yuǎn)不會(huì)超出閾值。
    Hashmap的擴(kuò)容機(jī)制在JDK8中,容量變化通常有以下集中情況:
    無參構(gòu)造:實(shí)例化的hashmap默認(rèn)內(nèi)部數(shù)組是null,也就是無實(shí)例化。第一次調(diào)用put方法
    時(shí),會(huì)開始第一次初始化擴(kuò)容,長(zhǎng)度為16.
    有參構(gòu)造:用于指定容量。會(huì)根據(jù)指定的正整數(shù)找到不小于指定容量的2的冪數(shù),將這個(gè)數(shù)設(shè)
    置賦值給閾值。第一次調(diào)用put方法時(shí),會(huì)將閾值賦值給容量,然后讓 閾值=容量X負(fù)載因子。
    因此并不是手動(dòng)指定了容量就一定不會(huì)觸發(fā)擴(kuò)容,超過閾值后一樣擴(kuò)容。
    如果不是第一次擴(kuò)容,則容量變?yōu)樵瓉淼?倍,閾值也變?yōu)樵瓉淼?倍。但負(fù)載因子不變。
    補(bǔ)充:
    首次put時(shí)會(huì)以擴(kuò)容的方式初始化,然后存入數(shù)據(jù),之后判斷是否需要擴(kuò)容
    如果不是首次put,則不咋需要初始化,會(huì)直接存入數(shù)據(jù),然后判斷是否需要擴(kuò)容。
    元素遷移:
    在JDK8中,由于數(shù)組的容量是以2的冪次方擴(kuò)容的,那么一個(gè)數(shù)組在擴(kuò)容時(shí),一個(gè)元素要么在
    原位置要么在原長(zhǎng)度+原位置的位置。
    數(shù)組長(zhǎng)度變?yōu)樵瓉淼?倍表現(xiàn)在二進(jìn)制上多了一個(gè)高位參與數(shù)組下標(biāo)確定。此時(shí),一個(gè)元素通
    過hash轉(zhuǎn)換坐標(biāo)的方法計(jì)算后會(huì)出現(xiàn)一個(gè)現(xiàn)象:
    最高位是0,則坐標(biāo)不變,最高位是1則坐標(biāo)變?yōu)?0000+原坐標(biāo),即原長(zhǎng)度+原坐標(biāo)。
  8. HashMap鏈表和紅黑樹轉(zhuǎn)化時(shí)機(jī)!
    HashMap中維護(hù)有一個(gè)Node類型的數(shù)組table,當(dāng)新添加的元素的hash值(hashCode & (length - 1))所
    指向的位置已有元素時(shí)就會(huì)被掛在該位置的最后面而形成鏈表。當(dāng)在插入一個(gè)元素后某一位置的鏈表長(zhǎng)
    度大于等于樹化的閾值(TREEIFY_THRESHOLD = 8)時(shí),會(huì)先去檢查table的size,如果此時(shí)table數(shù)組
    的長(zhǎng)度小于最小樹化容量(MIN_TREEIFY_CAPACITY = 64),會(huì)先對(duì)數(shù)組進(jìn)行擴(kuò)容,擴(kuò)容大小為原來的
    二倍。如果此時(shí)數(shù)組的長(zhǎng)度已經(jīng)大于64,則會(huì)將鏈表轉(zhuǎn)化為紅黑樹。在擴(kuò)容時(shí),如果發(fā)現(xiàn)發(fā)現(xiàn)某處已經(jīng)
    變?yōu)榧t黑樹的樹上的節(jié)點(diǎn)數(shù)量總和小于等于紅黑樹轉(zhuǎn)化為鏈表的閾值(UNTREEIFY_THRESHOLD =
    6),則會(huì)將此處的紅黑樹轉(zhuǎn)化為鏈表。
    簡(jiǎn)而言之,當(dāng)鏈表長(zhǎng)度超過8且哈希表容量大于64,會(huì)將鏈表轉(zhuǎn)化為紅黑樹。而當(dāng)紅黑樹的大小小于6,
    則由樹轉(zhuǎn)化為鏈表。
  9. 什么是Hash碰撞以及常見的解決方案
    Hash碰撞 : 對(duì)象Hash的前提是實(shí)現(xiàn)equals()和hashCode()兩個(gè)方法,那么HashCode()的作用就是保證
    對(duì)象返回唯一hash值,但當(dāng)兩個(gè)不同對(duì)象計(jì)算值一樣時(shí),這就發(fā)生了碰撞沖突。
    解決方案:
    開放地址法(再散列法)開放地執(zhí)法有一個(gè)公式:Hi=(H(key)+di) MOD m i=1,2,…,k(k<=m-1)
    其中,m為哈希表的表長(zhǎng)。di 是產(chǎn)生沖突的時(shí)候的增量序列。如果di值可能為1,2,3,…m-1,稱線性
    探測(cè)再散列。
    如果di取1,則每次沖突之后,向后移動(dòng)1個(gè)位置.如果di取值可能為1,-1,2,-2,4,-4,9,-9,16,-16,…kk,-
    kk(k<=m/2),稱二次探測(cè)再散列。如果di取值可能為偽隨機(jī)數(shù)列。稱偽隨機(jī)探測(cè)再散列。
    再哈希法Rehash當(dāng)發(fā)生沖突時(shí),使用第二個(gè)、第三個(gè)、哈希函數(shù)計(jì)算地址,直到無沖突時(shí)。
    缺點(diǎn):計(jì)算時(shí)間增加。
    比如上面第一次按照姓首字母進(jìn)行哈希,如果產(chǎn)生沖突可以按照姓字母首字母第二位進(jìn)行哈希,再
    沖突,第三位,直到不沖突為止.這種方法不易產(chǎn)生聚集,但增加了計(jì)算時(shí)間。
    鏈地址法(拉鏈法)將所有關(guān)鍵字為同義詞的記錄存儲(chǔ)在同一線性鏈表中.基本思想:將所有哈希地
    址為i的元素構(gòu)成一個(gè)稱為同義詞
    鏈的單鏈表,并將單鏈表的頭指針存在哈希表的第i個(gè)單元中,因而查找、插入和刪除主要在同義詞
    鏈中進(jìn)行。鏈地址法適用于經(jīng)常進(jìn)行插入和刪除的情況。
  10. HashMap在多線程操作中會(huì)出現(xiàn)什么問題!
    會(huì)出現(xiàn)線程安全問題, 可以使用加鎖解決, 但是速度慢, 所以建議使用juc包下的ConcurrentHashMap替代
    HashMap, 速度快且線程安全.
  11. 如何保證集合是線程安全的?
    第一: 使用JUC包下的ConcurrentHashMap, 線程安全, 并且速度也快
    第二: 選用synchronize或者Lock加鎖解決, 速度慢.
  12. 聊一聊JUC包下的并發(fā)工具
    CountDownLatch 閉鎖,使用時(shí)需要傳入一個(gè)int類型的參數(shù),一個(gè)線程等待一組線程執(zhí)行完畢后再恢復(fù)
    執(zhí)行;await() 等待其他線程都執(zhí)行完畢,通過計(jì)數(shù)器來判斷等待的線程是否全部執(zhí)行完畢。計(jì)數(shù)器:
    countDown方法,被等待線程執(zhí)行完畢后將計(jì)數(shù)器值-1,當(dāng)CountDownLatch的值減為0時(shí)無法恢復(fù),
    這就是叫做閉鎖的原因。
    CyclicBarrier 循環(huán)柵欄, 一組線程 同時(shí)到達(dá)臨界點(diǎn)后再同時(shí)恢復(fù)執(zhí)行(先到達(dá)臨界點(diǎn)的線程會(huì)阻塞,直到
    所有線程都到達(dá)臨界點(diǎn)),當(dāng)多個(gè)線程同時(shí)到達(dá)臨界點(diǎn)時(shí),隨機(jī)挑一個(gè)線程執(zhí)行barrierAction后再同時(shí)恢
    復(fù)執(zhí)行。await():調(diào)用該方法時(shí)表示線程已經(jīng)到達(dá)屏障,隨即阻塞。模擬:多線程向磁盤寫入數(shù)據(jù),計(jì)
    數(shù)器的值可以恢復(fù)。
    SemaPhore-信號(hào)量:SemaPhore是synchronized或Lock的加強(qiáng)版,作用是控制線程的并發(fā)數(shù)量。作
    用:用來控制同時(shí)訪問特定資源的線程數(shù)量,通過協(xié)調(diào)保證合理的使用公共資源。acquire():嘗試占用一
    個(gè)信號(hào)量,失敗的線程會(huì)阻塞,直達(dá)有新的信號(hào)量,再恢復(fù)執(zhí)行release():釋放一個(gè)信號(hào)量;acquire(n):
    嘗試占用n信號(hào)量,失敗的線程會(huì)阻塞,直達(dá)有新的信號(hào)量,再恢復(fù)執(zhí)行,release(n):釋放n信號(hào)量。
    Exchanger 線程交換器,Exchange類似于一個(gè)交換器,Exchange類允許在兩個(gè)線程之間定義同步點(diǎn)。
    當(dāng)兩個(gè)線程都到達(dá)同步點(diǎn)時(shí),他們交換數(shù)據(jù),因此第一個(gè)線程的數(shù)據(jù)進(jìn)入到第二個(gè)線程中,第二個(gè)線程
    的數(shù)據(jù)進(jìn)入到第一個(gè)線程中。
  13. ConcurrentHashMap如何保證線程安全
    底層采用CAS(內(nèi)存比較交換技術(shù)) + volatile + synchronize實(shí)現(xiàn), 初始化為無鎖狀態(tài)也就是使用CAS +
    volatile解決安全問題, 但是會(huì)涉及ABA問題. 但是幾率很小, 如果涉及ABA問題, 底層自動(dòng)切換成使用
    synchronize實(shí)現(xiàn).
  14. ConcurrentHashMap在1.7和1.8的底層實(shí)現(xiàn)
    JDK1.7底層采用 : 數(shù)組 + 鏈表,采用Segement保證安全
    JDK1.8底層采用: 數(shù)據(jù) + 鏈表 + 紅黑樹,采用CAS+synchronized代碼塊保證安全
  15. ConcurrentLinkedQueue和LinkedBlockingQueue有什么區(qū)別
    首先二者都是線程安全的得隊(duì)列,都可以用于生產(chǎn)與消費(fèi)模型的場(chǎng)景。
    LinkedBlockingQueue是阻塞隊(duì)列,其好處是:多線程操作共同的隊(duì)列時(shí)不需要額外的同步,由于具有
    插入與移除的雙重阻塞功能,對(duì)插入與移除進(jìn)行阻塞,隊(duì)列會(huì)自動(dòng)平衡負(fù)載,從而減少生產(chǎn)與消費(fèi)的處
    理速度差距。
    由于LinkedBlockingQueue有阻塞功能,其阻塞是基于鎖機(jī)制實(shí)現(xiàn)的,當(dāng)有多個(gè)線程消費(fèi)時(shí)候,隊(duì)列為
    空時(shí)消費(fèi)線程被阻塞,有元素時(shí)需要再喚醒消費(fèi)線程,隊(duì)列元素可能時(shí)有時(shí)無,導(dǎo)致用戶態(tài)與內(nèi)核態(tài)切
    換頻繁,消耗系統(tǒng)資源。從此方面來講,LinkedBlockingQueue更適用于多線程插入,單線程取出,即
    多個(gè)生產(chǎn)者與單個(gè)消費(fèi)者。
    ConcurrentLinkedQueue非阻塞隊(duì)列,采用 CAS+自旋操作,解決多線程之間的競(jìng)爭(zhēng),多寫操作增加沖
    突幾率,增加自選次數(shù),并不適合多寫入的場(chǎng)景。當(dāng)許多線程共享訪問一個(gè)公共集合時(shí),
    ConcurrentLinkedQueue 是一個(gè)恰當(dāng)?shù)倪x擇。從此方面來講,ConcurrentLinkedQueue更適用于單線
    程插入,多線程取出,即單個(gè)生產(chǎn)者與多個(gè)消費(fèi)者。
    總之,對(duì)于幾個(gè)線程生產(chǎn)與幾個(gè)線程消費(fèi),二者并沒有嚴(yán)格的規(guī)定, 只有誰(shuí)更適合。
  16. 說一下 HashSet 的實(shí)現(xiàn)原理
    HashSet底層使用了哈希表來支持的,特點(diǎn):存儲(chǔ)快, 底層由HashMap實(shí)現(xiàn)
    往HashSet添加元素的時(shí)候,HashSet會(huì)先調(diào)用元素的hashCode方法得到元素的哈希值 ,然后通過元
    素 的哈希值經(jīng)過移位等運(yùn)算,就可以算出該元素在哈希表中的存儲(chǔ)位置。
    如果算出的元素存儲(chǔ)的位置目前沒有任何元素存儲(chǔ),那么該元素可以直接存儲(chǔ)在該位置上
    如果算出的元素的存儲(chǔ)位置目前已經(jīng)存在有其他的元素了,那么還會(huì)調(diào)用該元素的equals方法與該位置
    的元素再比較一次,如果equals方法返回的是true,那么該位置上的元素視為重復(fù)元素,不允許添加,
    如果返回的是false,則允許添加
  17. HashSet和TreeSet有什么區(qū)別?
    HashSet是由一個(gè)hash表來實(shí)現(xiàn)的,因此,它的元素是無序的。add(),remove(),contains()方法的時(shí)
    間復(fù)雜度是O(1)。
    TreeSet是由一個(gè)樹形的結(jié)構(gòu)來實(shí)現(xiàn)的,它里面的元素是有序的。因此,add(),remove(),contains()方
    法的時(shí)間復(fù)雜度是O(logn)。

四、多線程 【25道】

  1. 聊一聊并行和并發(fā)的區(qū)別?
    并發(fā)是指同一時(shí)間一起發(fā)生的.
    例如: 一個(gè)處理器同時(shí)處理多個(gè)任務(wù)叫并發(fā)處理, 同一時(shí)間好多個(gè)請(qǐng)求一起訪問你的網(wǎng)站叫做并發(fā)請(qǐng)
    求等
    并行是指多個(gè)任務(wù)在同一時(shí)間一起運(yùn)行.
    例如: 多個(gè)處理器或者是多核的處理器同時(shí)處理多個(gè)不同的任務(wù), 這叫并行執(zhí)行.
  2. 線程和進(jìn)程的區(qū)別?
    進(jìn)程是執(zhí)行中的一個(gè)程序, 而一個(gè)進(jìn)程中執(zhí)行的一個(gè)任務(wù)即為一個(gè)線程
    一個(gè)線程只屬于一個(gè)進(jìn)程, 但一個(gè)進(jìn)程能包含多個(gè)線程
    線程無地址空間, 它包括在進(jìn)程的地址空間中
    線程的開銷比進(jìn)程小
  3. 說一說什么是原子性、可見性、有序性?
    原子性:提供互斥訪問,同一時(shí)刻只能有一個(gè)線程對(duì)數(shù)據(jù)進(jìn)行操作(Atomic、CAS算法、
    synchronized、Lock)
    可見性:一個(gè)主內(nèi)存的線程如果進(jìn)行了修改,可以及時(shí)被其他線程觀察到(synchronized、volatile)
    有序性:如果兩個(gè)線程不能從 happens-before原則 觀察出來,那么就不能觀察他們的有序性,虛擬機(jī)
    可以隨意的對(duì)他們進(jìn)行重排序,導(dǎo)致其觀察結(jié)果雜亂無序(happens-before原則)
  4. Java中實(shí)現(xiàn)多線程的方式
    通過擴(kuò)展Thread類來創(chuàng)建多線程:
    定義Thread類的子類,并重寫該類的run方法,該run方法的方法體就代表了線程要完成的任務(wù)。
    通過實(shí)現(xiàn)Runnable接口來創(chuàng)建多線程
    定義runnable接口的實(shí)現(xiàn)類,并重寫該接口的run()方法,該run()方法的方法體同樣是該線程的線
    程執(zhí)行體
    通過線程池實(shí)現(xiàn)
    定義線程池實(shí)例, 使用的時(shí)候從線程池中獲取線程使用.
    通過Callable和Future創(chuàng)建線程
    創(chuàng)建Callable接口的實(shí)現(xiàn)類,并實(shí)現(xiàn)call()方法,該call()方法將作為線程執(zhí)行體,并且有返回值
    創(chuàng)建Callable實(shí)現(xiàn)類的實(shí)例,使用FutureTask類來包裝Callable對(duì)象,該FutureTask對(duì)象封裝了該
    Callable對(duì)象的call()方法的返回值。
    使用FutureTask對(duì)象作為Thread對(duì)象的target創(chuàng)建并啟動(dòng)新線程。
    調(diào)用FutureTask對(duì)象的get()方法來獲得子線程執(zhí)行結(jié)束后的返回值
  5. Java中提供的線程池種類,及其特點(diǎn)!
    五種線程池
    Single Thread Executor : 這是一個(gè)單線程的Executor,它創(chuàng)建單個(gè)工作線程來執(zhí)行任務(wù),如果這
    個(gè)線程異常結(jié)束,會(huì)創(chuàng)建一個(gè)新的來替代它;它的特點(diǎn)是能確保依照任務(wù)在隊(duì)列中的順序來串行執(zhí)

    代碼: Executors.newSingleThreadExecutor()
    Cached Thread Pool : 創(chuàng)建一個(gè)可緩存的線程池,如果線程池的規(guī)模超過了處理需求,將自動(dòng)回收
    空閑線程,而當(dāng)需求增加時(shí),則可以自動(dòng)添加新線程,線程池的規(guī)模不存在任何限制。
    代碼:Executors.newCachedThreadPool()
    Fixed Thread Pool : 擁有固定線程數(shù)的線程池,如果沒有任務(wù)執(zhí)行,那么線程會(huì)一直等待, 代
    碼: Executors.newFixedThreadPool(4) 在構(gòu)造函數(shù)中的參數(shù)4是線程池的大小,你可以隨意設(shè)
    置,也可以和cpu的核數(shù)量保持一致,獲取cpu的核數(shù)量
    代碼 : int cpuNums = Runtime.getRuntime().availableProcessors();
    Scheduled Thread Pool : 創(chuàng)建一個(gè)固定長(zhǎng)度的線程池,而且以延遲或定時(shí)的方式來執(zhí)行任務(wù),類
    似于Timer。
    代碼:Executors.newScheduledThreadPool()
  6. 線程池的工作原理以及重要參數(shù)含義
    原理:
    線程池會(huì)初始化一定數(shù)量線程, 每次使用線程從線程池中拿一個(gè)使用, 省去了創(chuàng)建線程的開銷和時(shí)間,
    使用完畢, 放回線程池中, 不銷毀, 省去了銷毀的開銷和時(shí)間.
    重要參數(shù):
    corePoolSize:線程池核心線程數(shù)量
    maximumPoolSize:線程池最大線程數(shù)量
    keepAliverTime:當(dāng)活躍線程數(shù)大于核心線程數(shù)時(shí),空閑的多余線程最大存活時(shí)間
    unit:存活時(shí)間的單位
    workQueue:存放任務(wù)的隊(duì)列
    threadFactory:創(chuàng)建線程的工廠
    handler:拒絕策略
  7. 線程池的阻塞隊(duì)列有哪些?
    ArrayBlockingQueue : 數(shù)組有界阻塞隊(duì)列FIFO, 按照阻塞的先后順序訪問隊(duì)列,默認(rèn)情況下不保證線程
    公平的訪問隊(duì)列, 如果要保證公平性,會(huì)降低一定的吞吐量
    LinkedBlockingQueue : 鏈表有界阻塞隊(duì)列,默認(rèn)最大長(zhǎng)度為Integer.MAX_VALUE。此隊(duì)列按照先進(jìn)先
    出的原則對(duì)元素進(jìn)行排序SynchronousQueue : 不存儲(chǔ)元素的阻塞隊(duì)列
    DelayedWorkQueue : 延遲獲取元素隊(duì)列,指定時(shí)間后獲取,為無界阻塞隊(duì)列。
  8. 線程池的拒絕策略有哪些?
    拒絕策略核心接口:
    java.util.concurrent.RejectedExecutionHandler
    實(shí)現(xiàn):
    CallerRunsPolicy : java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy
    當(dāng)有新任務(wù)提交后,如果線程池沒被關(guān)閉且沒有能力執(zhí)行,則把這個(gè)任務(wù)交于提交任務(wù)的線程
    執(zhí)行,也就是誰(shuí)提交任務(wù),誰(shuí)就負(fù)責(zé)執(zhí)行任務(wù)。
    AbortPolicy : java.util.concurrent.ThreadPoolExecutor.AbortPolicy
    拒絕策略在拒絕任務(wù)時(shí),會(huì)直接拋出一個(gè)類型為 RejectedExecutionException 的
    RuntimeException,讓你感知到任務(wù)被拒絕了,于是你便可以根據(jù)業(yè)務(wù)邏輯選擇重試或者放
    棄提交等策略。
    DiscardPolicy : java.util.concurrent.ThreadPoolExecutor.DiscardPolicy
    當(dāng)新任務(wù)被提交后直接被丟棄掉,也不會(huì)給你任何的通知,相對(duì)而言存在一定的風(fēng)險(xiǎn),因?yàn)槲?br /> 們提交的時(shí)候根本不知道這個(gè)任務(wù)會(huì)被丟棄,可能造成數(shù)據(jù)丟失。
    DiscardOldestPolicy : java.util.concurrent.ThreadPoolExecutor.DiscardOldestPolicy
    如果線程池沒被關(guān)閉且沒有能力執(zhí)行,則會(huì)丟棄任務(wù)隊(duì)列中的頭結(jié)點(diǎn),通常是存活時(shí)間最長(zhǎng)的
    任務(wù),這種策略與第二種不同之處在于它丟棄的不是最新提交的,而是隊(duì)列中存活時(shí)間最長(zhǎng)
    的,這樣就可以騰出空間給新提交的任務(wù),但同理它也存在一定的數(shù)據(jù)丟失風(fēng)險(xiǎn)。
  9. synchronized和reentranlock鎖的區(qū)別?
    Synchronized屬于重量級(jí)鎖, JDK早期版本使用了線程的狀態(tài)變化來實(shí)現(xiàn), JDK1.8中使用了自適應(yīng)自旋鎖
    實(shí)現(xiàn). 總體來說安全, 但是效率慢
    Reentranlock是JUC包下的鎖, 底層使用CAS + Volatile關(guān)鍵字實(shí)現(xiàn). 效率高.
  10. synchronized底層如何實(shí)現(xiàn)?什么是鎖升級(jí)、降級(jí)!
    jdk 中做了優(yōu)化,提供了三種不同的 Monitor實(shí)現(xiàn),分別是:
    偏斜鎖 (Biased Locking)
    輕量級(jí)鎖
    重量級(jí)鎖
    所謂鎖的升級(jí),降級(jí),實(shí)際上是 JVM 對(duì) synchronized優(yōu)化的一種策略,JVM 會(huì)檢測(cè)不同的競(jìng)爭(zhēng)狀態(tài),
    然后自動(dòng)切換到合適的鎖實(shí)現(xiàn),這種切換就是鎖的升級(jí),降級(jí)。
    當(dāng)沒有出現(xiàn)鎖的競(jìng)爭(zhēng)時(shí),默認(rèn)使用的是偏斜鎖。JVM 會(huì)利用 CAS 實(shí)現(xiàn).
    如果有另一個(gè)線程試圖鎖定某個(gè)以被加持偏斜鎖的對(duì)象時(shí),JVM 就需要撤銷偏斜鎖,并切換到輕量級(jí)鎖
    實(shí)現(xiàn)。如果獲取成功,就使用輕量級(jí)鎖,否者,進(jìn)一步升級(jí)到重量級(jí)鎖
  11. reentranlock的底層實(shí)現(xiàn)原理
    reentranlock 是基于AQS(AbstractQueueSynchronizer) 采用FIFO的隊(duì)列表示排隊(duì)等待的線程.
    AQS底層采用CAS(內(nèi)存比較交換技術(shù)) + Volatile關(guān)鍵字實(shí)現(xiàn).
  12. volatile關(guān)鍵字的特點(diǎn)
    保證線程之間的可見性,當(dāng)一個(gè)線程對(duì)共享的變量進(jìn)行了修改,其他的線程能夠通過此關(guān)鍵字發(fā)現(xiàn)
    這個(gè)修改
    禁止指令重排序,編譯器在編譯的過程中會(huì)對(duì)程序進(jìn)行優(yōu)化,在保證結(jié)果不變的前提下,調(diào)整指令
    執(zhí)行的順序,提高執(zhí)行效率,如果加了volatile關(guān)鍵字,則會(huì)禁止指令重排序。
    不能保證原子性
  13. Java為什么會(huì)指令重排
    java中源代碼文件會(huì)被編譯成.class的字節(jié)碼文件, 字節(jié)碼指定在執(zhí)行之前, jvm底層有內(nèi)置的對(duì)字節(jié)碼的
    優(yōu)化策略, 也就是指令重排機(jī)制, 會(huì)調(diào)整指令執(zhí)行順序. 目的是加快執(zhí)行速度.
  14. 悲觀鎖和樂觀鎖的區(qū)別
    悲觀鎖 : 無論讀還是更改對(duì)象都要加鎖, 所以慢, 但是安全.
    樂觀鎖 : 讀不加鎖, 更改對(duì)象加鎖, 所以快, 但是沒有悲觀鎖安全
  15. 什么是CAS, 以及它的ABA問題, 如何解決ABA問題
    CAS的含義 :
    CAS是compare and swap的縮寫,即我們所說的比較交換。
    CAS 操作包含三個(gè)操作數(shù) —— 內(nèi)存位置(V)、預(yù)期原值(A)和新值(B)。如果內(nèi)存地址里面的值
    和A的值是一樣的,那么就將內(nèi)存里面的值更新成B。CAS是通過無限循環(huán)來獲取數(shù)據(jù)的,若果在第
    一輪循環(huán)中,a線程獲取地址里面的值被b線程修改了,那么a線程需要自旋,到下次循環(huán)才有可能
    機(jī)會(huì)執(zhí)行。
    CAS的ABA問題 :
    CAS容易造成ABA問題。一個(gè)線程a將數(shù)值改成了b,接著又改成了a,此時(shí)CAS認(rèn)為是沒有變化,其
    實(shí)是已經(jīng)變化過了,而這個(gè)問題的解決方案可以使用版本號(hào)標(biāo)識(shí),每操作一次version加1。在
    java5中,已經(jīng)提供了AtomicStampedReference來解決問題。
    CAS造成CPU利用率增加。之前說過了CAS里面是一個(gè)循環(huán)判斷的過程,如果線程一直沒有獲取到
    狀態(tài),cpu資源會(huì)一直被占用。
  16. Atomic變量如何保證的原子性
    它底層是使用CAS + volatile關(guān)鍵字來保證原子性操作,從而達(dá)到線程安全的目的.
  17. ThreadLocal是什么,有什么作用
    ThreadLocal是一個(gè)本地線程副本變量工具類。主要用于將私有線程和該線程存放的副本對(duì)象做一個(gè)映
    射,各個(gè)線程之間的變量互不干擾,在高并發(fā)場(chǎng)景下可以實(shí)現(xiàn)無狀態(tài)的調(diào)用,特別適用于各個(gè)線程依賴
    不通 的變量值完成操作的場(chǎng)景。
    簡(jiǎn)單說ThreadLocal就是一種以空間換時(shí)間的做法,在每個(gè)Thread里面維護(hù)了一個(gè)以開地址法實(shí)現(xiàn)的
    ThreadLocal.ThreadLocalMap,把數(shù)據(jù)進(jìn)行隔離,數(shù)據(jù)不共享,自然就沒有線程安全的問題了。
  18. ThreadLocal的內(nèi)存泄漏問題
    ThreadLocalMap 中的 key 是一個(gè) ThreadLocal 對(duì)象,且是一個(gè)弱引用,而 value 卻是一個(gè)強(qiáng)引
    用。
    存在一種情況,可能導(dǎo)致內(nèi)存泄漏。如果在某一時(shí)刻,將 ThreadLocal 實(shí)例設(shè)置為 null ,即
    ThreadLocal 沒有強(qiáng)引用了,如果發(fā)生 GC 時(shí),由于 ThreadLocal 實(shí)例只存在弱引用,所以被回收
    了,但是 value 仍然存在一個(gè)當(dāng)前線程連接過來的強(qiáng)引用,其不會(huì)被回收,只有等到線程結(jié)束死亡或
    者手動(dòng)清空 value 或者等到另一個(gè) ThreadLocal 對(duì)象進(jìn)行 get 或 set 操作時(shí)剛好觸發(fā)
    static class ThreadLocalMap {
    static class Entry extends WeakReference<ThreadLocal<?>> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<?> k, Object v) {
    super(k);
    value = v;
    }
    }
    // 。。。。
    }
    ThreadLocal的內(nèi)存泄漏問題
    expungeStaleEntry 函數(shù)并且剛好能夠檢查到本 ThreadLocal 對(duì)象 key 為空(概率太小),這樣才
    不會(huì)發(fā)生內(nèi)存泄漏。否則, value 始終有引用指向它,它也不會(huì)被 GC 回收,那么就會(huì)導(dǎo)致內(nèi)存泄漏。
    雖然發(fā)生內(nèi)存泄漏的概率比較小,但是為了保險(xiǎn)起見,也建議在使用完 ThreadLocal 對(duì)象后調(diào)用一下
    remove 方法清理一下值。
    作者:guozhchun
  19. jdk1.8對(duì)鎖進(jìn)行了哪些優(yōu)化
    LongAdder 類似automicLong, 但是提供了“熱點(diǎn)分離”。過程如下:如果并發(fā)不激烈,則與
    automicLong 一樣,cas賦值。如果出現(xiàn)并發(fā)操作,則使用數(shù)組,數(shù)組的各元素之和為真實(shí)value值,讓
    操作分散在數(shù)組各個(gè)元素上,把并發(fā)操作壓力分散,一遇到并發(fā)就擴(kuò)容數(shù)組,最后達(dá)到高效率。一般cas
    如果遇到高并發(fā),可能一直賦值失敗導(dǎo)致不斷循環(huán),熱點(diǎn)分離可以解決這個(gè)問題
    stampedLock 改進(jìn)讀寫鎖,讀不阻塞寫。
    completableFuture 對(duì)Future進(jìn)行增強(qiáng),支持函數(shù)式編程的流式調(diào)用
  20. 死鎖發(fā)生的情況和如何避免死鎖
    死鎖就是多個(gè)線程同時(shí)等待其他線程釋放鎖,導(dǎo)致被無限期阻塞的現(xiàn)象。
    發(fā)生死鎖的四個(gè)必要條件:
    互斥條件
    不可搶占條件
    占有且申請(qǐng)條件
    循環(huán)等待條件
    避免死鎖:
    盡量避免一個(gè)線程同時(shí)獲取多個(gè)鎖
    盡量避免一個(gè)線程在鎖內(nèi)部占用多個(gè)資源,盡量保證每個(gè)鎖只占用一個(gè)資源
    順序加鎖
    加鎖時(shí)限
    死鎖檢驗(yàn)
  21. 介紹鎖的升級(jí)過程
    鎖狀態(tài)一種有四種 : 從級(jí)別由低到高依次是:無鎖、偏向鎖,輕量級(jí)鎖,重量級(jí)鎖,
    鎖狀態(tài)只能升級(jí),不能降級(jí)
    升級(jí)過程 :
    無鎖狀態(tài) - > 當(dāng)一個(gè)線程訪問同步代碼塊時(shí)升級(jí)成偏向鎖 - > 偏向鎖 -> 有鎖競(jìng)爭(zhēng)時(shí)升級(jí)成輕量級(jí)鎖 - >
    輕量級(jí)鎖 - > 自旋N次失敗, 鎖膨脹, 升級(jí)成重量級(jí)鎖 - > 重量級(jí)鎖
  22. 介紹鎖的降級(jí)過程
    鎖降級(jí)
    鎖降級(jí)發(fā)生在讀寫鎖中,寫鎖降級(jí)讀鎖的過程
    讀寫鎖 : ReentrantReadWriteLock
    讀寫鎖,既可以獲取讀鎖,也可以獲取寫鎖
    寫鎖是獨(dú)占鎖,所謂獨(dú)占即為獨(dú)自占有,別的線程既不能獲取到該鎖的寫鎖,也不能獲取到對(duì)
    應(yīng)的讀鎖。
    讀鎖是共享鎖,所謂共享即是所有線程都可以共同持有該讀鎖
    鎖降級(jí)過程 :
    鎖降級(jí)指的是寫鎖降級(jí)為讀鎖的過程,他的過程是持有寫鎖,獲取讀鎖,然后釋放寫鎖
  23. 怎么解決多線程的大量訪問時(shí)的數(shù)據(jù)同步
    可以加鎖解決, 至于鎖可以使用synchronized重量級(jí)鎖, 也可以使用Lock輕量級(jí)鎖
    還可以使用線程安全的對(duì)象作為多線程共用的數(shù)據(jù)操作對(duì)象, 比如ConcurrentHashMap, 或者Atomic原
    子操作類等
    速度快慢則是, 線程安全操作對(duì)象ConcurrentHashMap或者原子操作類比輕量級(jí)鎖快, 輕量級(jí)鎖比重量
    級(jí)鎖要快.
  24. 線程的 run()和 start()有什么區(qū)別
    每個(gè)線程都是通過某個(gè)特定Thread對(duì)象所對(duì)應(yīng)的run()方法來完成其操作的,方法run()稱為線程體。也
    就是run方法中是線程具體要執(zhí)行的任務(wù)或者業(yè)務(wù).
    Start方法是啟動(dòng)線程, 調(diào)用線程類的Start方法線程開始運(yùn)行. 這時(shí)無需等待run方法體代碼執(zhí)行完畢,可
    以直接繼續(xù)執(zhí)行下面的代碼, 真正實(shí)現(xiàn)了多線程運(yùn)行
  25. JDK1.6對(duì)Synchronized底層做了哪些優(yōu)化
    Synchronized底層早期JDK版本是采用線程的狀態(tài)轉(zhuǎn)換實(shí)現(xiàn)的, 主要使用了線程的阻塞和喚醒來實(shí)現(xiàn).
    JDK1.6中使用了自適應(yīng)自旋鎖實(shí)現(xiàn), 還加入的鎖消除, 鎖粗化等優(yōu)化策略
    自適應(yīng)自旋鎖 : JDK 1.6引入了更加聰明的自旋鎖,即自適應(yīng)自旋鎖。所謂自適應(yīng)就意味著自旋的次數(shù)不
    再是固定的,它是由前一次在同一個(gè)鎖上的自旋時(shí)間及鎖的擁有者的狀態(tài)來決定。
    鎖消除 : 為了保證數(shù)據(jù)的完整性,我們?cè)谶M(jìn)行操作時(shí)需要對(duì)這部分操作進(jìn)行同步控制,但是在有些情況
    下,JVM檢測(cè)到不可能存在共享數(shù)據(jù)競(jìng)爭(zhēng),這是JVM會(huì)對(duì)這些同步鎖進(jìn)行鎖消除
    鎖粗化 : 就是將多個(gè)連續(xù)的加鎖、解鎖操作連接在一起,擴(kuò)展成一個(gè)范圍更大的鎖

五、IO【5道】

  1. Java提供了哪些IO方式?
    傳統(tǒng)BIO同步阻塞IO, 這里面又分為字節(jié)流和字符流
    JDK1.4引入NIO, 同步非阻塞IO, 速度比傳統(tǒng)BIO快, 并且更節(jié)省資源
    JDK1.7引入NIO2也叫做AIO, 異步非阻塞IO, 基于事件和回調(diào)機(jī)制實(shí)現(xiàn), 速度更快
  2. NIO, BIO, AIO區(qū)別?
    NIO:在JDK1.4以前,Java的IO模型一直是BIO,從JDK1.4開始,JDK引入的新的IO模型NIO,它是同步
    非阻塞的。而服務(wù)器的實(shí)現(xiàn)模式是多個(gè)請(qǐng)求一個(gè)線程,即請(qǐng)求會(huì)注冊(cè)到多路復(fù)用器Selecter上,多路復(fù)
    用器輪詢到連接有IO請(qǐng)求時(shí)才啟動(dòng)一個(gè)線程處理
    BIO:同步阻塞,服務(wù)器的實(shí)現(xiàn)模式是一個(gè)連接一個(gè)線程,這樣的模式很明顯的一個(gè)缺陷是:優(yōu)于客戶
    端連接數(shù)與服務(wù)器線程數(shù)成正比關(guān)系,可能造成不必要的線程開銷,嚴(yán)重的還會(huì)導(dǎo)致服務(wù)器內(nèi)存溢出,
    當(dāng)然,這種情況可以通過線程池改善,但并不能從本質(zhì)上消除這個(gè)弊端
    AIO:JDK1.7發(fā)布了NIO2.0,這就是真正意義上的異步非阻塞,服務(wù)器的實(shí)現(xiàn)模式為多個(gè)有效請(qǐng)求一個(gè)
    線程,客戶端的IO請(qǐng)求都是由OS完成再通知服務(wù)器應(yīng)用去啟動(dòng)線程處理(回調(diào))
  3. 有哪些緩沖流?如何實(shí)現(xiàn)緩沖功能!
    緩沖流也叫高效流,是對(duì)四個(gè)基本的FileXxx流的增強(qiáng),按照數(shù)據(jù)類型分類:
    字節(jié)緩沖流 :BufferedInputStream,BufferedOutputStream
    字符緩沖流:BufferedReader,BufferedWriter
    基本原理:
    是在創(chuàng)建流對(duì)象的時(shí)候,會(huì)創(chuàng)建一個(gè)內(nèi)置默認(rèn)大小的緩沖區(qū)數(shù)組,減少系統(tǒng)IO次數(shù),從而提高讀寫
    效率
    字節(jié)緩沖流
    public BufferedInputStream(InputStream in) :創(chuàng)建一個(gè) 新的緩沖輸入流。
    public BufferedOutputStream(OutputStream out) : 創(chuàng)建一個(gè)新的緩沖輸出流。
  4. 實(shí)現(xiàn)文件拷貝的幾種方式!
    通過字節(jié)流實(shí)現(xiàn)文件拷貝
    通過字符流實(shí)現(xiàn)文件拷貝
    通過字節(jié)緩沖流實(shí)現(xiàn)文件拷貝
    通過字符緩沖流實(shí)現(xiàn)文件拷貝
    通過JAVA NIO非直接緩沖區(qū)拷貝文件
    通過JAVA NIO直接緩沖區(qū)拷貝文件
    通過JAVA NIO通道傳輸拷貝文件
  5. 什么Java序列化,如何實(shí)現(xiàn)序列化!
    序列化:就是一種用來處理對(duì)象流的機(jī)制,所謂對(duì)象流也就是將對(duì)象的內(nèi)容進(jìn)行流化??梢詫?duì)流化后的
    對(duì)象進(jìn)行讀寫操作,也可將流化后的對(duì)象傳輸于網(wǎng)絡(luò)之間。序列化是為了解決在對(duì)對(duì)象流進(jìn)行讀寫操作
    時(shí)所引發(fā)的問題。
    序列化的實(shí)現(xiàn):將需要被序列化的類實(shí)現(xiàn)Serializable接口,該接口沒有需要實(shí)現(xiàn)的方法,implements
    Serializable只是為了標(biāo)注該對(duì)象是可被序列化的,然后使用一個(gè)輸出流(如:FileOutputStream)來構(gòu)造
    一個(gè)ObjectOutputStream(對(duì)象流)對(duì)象,接著,使用ObjectOutputStream對(duì)象的writeObject(Object
    obj)方法就可以將參數(shù)為obj的對(duì)象寫出(即保存其狀態(tài)),要恢復(fù)的話則用輸入流。

六、網(wǎng)絡(luò)編程 【9道】

  1. http協(xié)議和RPC協(xié)議區(qū)別
    RPC是遠(yuǎn)程過程調(diào)用, 是JDK底層定義的規(guī)范, 它的實(shí)現(xiàn)既可以使用TCP也可以使用http, 底層可以使用二
    進(jìn)制傳輸, 效率高.
    Http是協(xié)議, http協(xié)議底層位于傳輸層是tcp協(xié)議. 通用性好可以傳輸json數(shù)據(jù), 效率稍微慢一些
  2. OSI網(wǎng)絡(luò)模型七層都有哪些
    OSI參考模型分為7層,分別是物理層,數(shù)據(jù)鏈路層,網(wǎng)絡(luò)層,傳輸層,會(huì)話層,表示層和應(yīng)用層。
  3. 傳輸層上的TCP和UDP區(qū)別
    TCP與UDP的特點(diǎn):
    UDP:無連接、不可靠、傳輸速度快. 適合傳輸語(yǔ)音, 視頻等
    TCP:面向連接、可靠、傳輸速度沒有UDP快, 例如: http, smtp等協(xié)議底層就是tcp
  4. http協(xié)議1.0和1.1版本區(qū)別
    主要有4個(gè)方面:緩存處理,帶寬優(yōu)化和網(wǎng)絡(luò)連接使用,Host請(qǐng)求頭的區(qū)別,長(zhǎng)連接
    ● 緩存處理:HTTP1.1則引入了更多的緩存控制策略
    ● 長(zhǎng)連接:HTTP1.1默認(rèn)使用長(zhǎng)連接,可有效減少TCP的三次握手開銷,在一個(gè)TCP連接上可以傳送多個(gè)
    HTTP請(qǐng)求和響應(yīng),減少了建立和關(guān)閉連接的消耗和延遲
    ● Host請(qǐng)求頭的區(qū)別:HTTP1.0是沒有host域的,HTTP1.1才支持這個(gè)參數(shù)
    ● 帶寬優(yōu)化和網(wǎng)絡(luò)連接使用:在1.1后,現(xiàn)在只會(huì)發(fā)送head信息,果服務(wù)器認(rèn)為客戶端有權(quán)限請(qǐng)求服務(wù)
    器,則返回100,當(dāng)接收到100后才會(huì)將剩下的信息發(fā)送到服務(wù)器
  5. http是短連接還是長(zhǎng)連接, 如何實(shí)現(xiàn)的
    HTTP協(xié)議與TCP/IP協(xié)議的關(guān)系
    HTTP的長(zhǎng)連接和短連接本質(zhì)上是TCP長(zhǎng)連接和短連接。HTTP屬于應(yīng)用層協(xié)議,在傳輸層使用TCP
    協(xié)議,在網(wǎng)絡(luò)層使用IP協(xié)議。IP協(xié)議主要解決網(wǎng)絡(luò)路由和尋址問題,TCP協(xié)議主要解決如何在IP層
    之上可靠的傳遞數(shù)據(jù)包,使在網(wǎng)絡(luò)上的另一端收到發(fā)端發(fā)出的所有包,并且順序與發(fā)出順序一致。
    TCP有可靠,面向連接的特點(diǎn)。
    如何理解HTTP協(xié)議是無狀態(tài)的
    HTTP協(xié)議是無狀態(tài)的,指的是協(xié)議對(duì)于事務(wù)處理沒有記憶能力,服務(wù)器不知道客戶端是什么狀
    態(tài)。也就是說,打開一個(gè)服務(wù)器上的網(wǎng)頁(yè)和你之前打開這個(gè)服務(wù)器上的網(wǎng)頁(yè)之間沒有任何聯(lián)系。
    HTTP是一個(gè)無狀態(tài)的面向連接的協(xié)議,無狀態(tài)不代表HTTP不能保持TCP連接,更不能代表HTTP使
    用的是UDP協(xié)議(無連接)。
    什么是長(zhǎng)連接、短連接?
    在HTTP/1.0中,默認(rèn)使用的是短連接。也就是說,瀏覽器和服務(wù)器每進(jìn)行一次HTTP操作,就建立
    一次連接,但任務(wù)結(jié)束就中斷連接。如果客戶端瀏覽器訪問的某個(gè)HTML或其他類型的 Web頁(yè)中包
    含有其他的Web資源,如JavaScript文件、圖像文件、CSS文件等;當(dāng)瀏覽器每遇到這樣一個(gè)Web
    資源,就會(huì)建立一個(gè)HTTP會(huì)話。
    但從 HTTP/1.1起,默認(rèn)使用長(zhǎng)連接,用以保持連接特性。使用長(zhǎng)連接的HTTP協(xié)議,會(huì)在響應(yīng)頭有
    加入這行代碼:Connection:keep-alive
    在使用長(zhǎng)連接的情況下,當(dāng)一個(gè)網(wǎng)頁(yè)打開完成后,客戶端和服務(wù)器之間用于傳輸HTTP數(shù)據(jù)的 TCP
    連接不會(huì)關(guān)閉,如果客戶端再次訪問這個(gè)服務(wù)器上的網(wǎng)頁(yè),會(huì)繼續(xù)使用這一條已經(jīng)建立的連接。
    Keep-Alive不會(huì)永久保持連接,它有一個(gè)保持時(shí)間,可以在不同的服務(wù)器軟件(如Apache)中設(shè)
    定這個(gè)時(shí)間。實(shí)現(xiàn)長(zhǎng)連接要客戶端和服務(wù)端都支持長(zhǎng)連接。
    HTTP協(xié)議的長(zhǎng)連接和短連接,實(shí)質(zhì)上是TCP協(xié)議的長(zhǎng)連接和短連接。
    TCP連接
    當(dāng)網(wǎng)絡(luò)通信時(shí)采用TCP協(xié)議時(shí),在真正的讀寫操作之前,server與client之間必須建立一個(gè)連
    接,當(dāng)讀寫操作完成后,雙方不再需要這個(gè)連接 時(shí)它們可以釋放這個(gè)連接,連接的建立是需
    要三次握手的,而釋放則需要4次握手,所以說每個(gè)連接的建立都是需要資源消耗和時(shí)間消耗
    三次握手建立連接 , 四次揮手關(guān)閉連接
    短連接的操作步驟是:
    建立連接——數(shù)據(jù)傳輸——關(guān)閉連接…建立連接——數(shù)據(jù)傳輸——關(guān)閉連接
    長(zhǎng)連接的操作步驟是:
    建立連接——數(shù)據(jù)傳輸…(保持連接)…數(shù)據(jù)傳輸——關(guān)閉連接
  6. 簡(jiǎn)述tcp三次握手四次揮手過程
    先向HTTP服務(wù)器發(fā)起TCP的確認(rèn)請(qǐng)求(三次握手)
    客戶端 --> SYN --> 服務(wù)器
    服務(wù)器 --> SYN+ACK —>客戶端
    客戶端 --> ACK --> 服務(wù)器
    客戶端要和服務(wù)器斷開TCP連接(四次揮手)
    客戶端 --> FIN +ACK —> 服務(wù)器
    服務(wù)器 --> FIN —> 客戶端
    服務(wù)器 --> ACK --> 客戶端
    客戶端 --> ACK —> 服務(wù)器
  7. http有多少類響應(yīng)碼?分別什么含義
    響應(yīng)碼由三位十進(jìn)制數(shù)字組成,它們出現(xiàn)在由HTTP服務(wù)器發(fā)送的響應(yīng)的第一行。
    響應(yīng)碼分五種類型,由它們的第一位數(shù)字表示:
    1xx:信息,請(qǐng)求收到,繼續(xù)處理
    2xx:成功,行為被成功地接受、理解和采納
    3xx:重定向,為了完成請(qǐng)求,必須進(jìn)一步執(zhí)行的動(dòng)作
    4xx:客戶端錯(cuò)誤,請(qǐng)求包含語(yǔ)法錯(cuò)誤或者請(qǐng)求無法實(shí)現(xiàn)
    5xx:服務(wù)器錯(cuò)誤,服務(wù)器不能實(shí)現(xiàn)一種明顯無效的請(qǐng)求
  8. tomcat的實(shí)現(xiàn)原理!tomcat如何進(jìn)行優(yōu)化?
    tomcat是一個(gè)基于JAVA的WEB容器,其實(shí)現(xiàn)了JAVA EE中的 Servlet 與 jsp 規(guī)范,與Nginx Apache 服務(wù)
    器不同在于一般用于動(dòng)態(tài)請(qǐng)求處理。在架構(gòu)設(shè)計(jì)上采用面向組件的方式設(shè)計(jì)。即整體功能是通過組件的
    方式拼裝完成。另外每個(gè)組件都可以被替換以保證靈活性。
    實(shí)現(xiàn)原理:
    Tomcat是運(yùn)行在JVM中的一個(gè)進(jìn)程。它定義為“中間件”,顧名思義是一個(gè)在Java項(xiàng)目與JVM之間的中間容
    器。
    Web項(xiàng)目的本質(zhì),是一大堆的資源文件和方法。Web項(xiàng)目沒有入口方法(即main方法),這意味著
    Web項(xiàng)目中的方法不會(huì)自動(dòng)運(yùn)行起來。Web項(xiàng)目部署進(jìn)Tomcat的webapp中的目的是很明確的,那就是
    希望Tomcat去調(diào)用寫好的方法去為客戶端返回需要的資源和數(shù)據(jù)。
    Tomcat可以運(yùn)行起來,并調(diào)用寫好的方法。那么,Tomcat有一個(gè)main方法。對(duì)于Tomcat而言,它并
    不知道用戶會(huì)有什么樣的方法,這些都只是在項(xiàng)目被部署進(jìn)webapp下后才確定的。由此,可知Tomcat
    用到了Java的反射來實(shí)現(xiàn)類的動(dòng)態(tài)加載、實(shí)例化、獲取方法、調(diào)用方法。但是部署到Tomcat的中的Web
    項(xiàng)目必須是按照規(guī)定好的接口來進(jìn)行編寫,以便進(jìn)行調(diào)用。
    優(yōu)化:
    修改內(nèi)存的相關(guān)配置
    修改TOMCAT_HOME/bin/catalina.sh,在其中加入,也可以放在 CLASSPATH=下面, 加一些
    對(duì)內(nèi)存調(diào)優(yōu)的參數(shù)
    優(yōu)化連接器Connector
    Connector是連接器,負(fù)責(zé)接收客戶的請(qǐng)求,以及向客戶端回送響應(yīng)的消息。所以 Connector
    的優(yōu)化是重要部分。默認(rèn)情況下 Tomcat只支持200線程訪問,超過這個(gè)數(shù)量的連接將被等待
    甚至超時(shí)放棄,所以我們需要提高這方面的處理能力。
    在TOMCAT_HOME/conf/server.xml添加最大線程數(shù)量和最小空閑線程數(shù),請(qǐng)求的數(shù)量
    配置線程池
    Executor代表了一個(gè)線程池,可以在Tomcat組件之間共享。使用線程池的好處在于減少了創(chuàng)
    建銷毀線程的相關(guān)消耗,而且可以提高線程的使用效率。
  9. get 和 post 請(qǐng)求有哪些區(qū)別?
    GET在瀏覽器回退時(shí)是無害的,而POST會(huì)再次提交請(qǐng)求。
    GET請(qǐng)求會(huì)被瀏覽器主動(dòng)cache,而POST不會(huì),除非手動(dòng)設(shè)置。
    GET請(qǐng)求只能進(jìn)行url編碼,而POST支持多種編碼方式。
    GET請(qǐng)求參數(shù)會(huì)被完整保留在瀏覽器歷史記錄里,而POST中的參數(shù)不會(huì)被保留。
    GET請(qǐng)求在URL中傳送的參數(shù)是有長(zhǎng)度限制的,而POST沒有。
    參數(shù)的數(shù)據(jù)類型,GET只接受ASCII字符,而POST沒有限制。
    GET比POST更不安全,因?yàn)閰?shù)直接暴露在URL上,所以不能用來傳遞敏感信息。
    GET參數(shù)通過URL傳遞,POST放在Request body中

七、MySQL以及SQL面試題【20道】

  1. 說一說什么是數(shù)據(jù)庫(kù)事務(wù)!
    數(shù)據(jù)庫(kù)事務(wù)就是在一套業(yè)務(wù)操作的多條sql語(yǔ)句執(zhí)行中要么全成功, 要么全失敗. 保證了數(shù)據(jù)的一致性.
    事務(wù)的四個(gè)屬性:原子性,一致性,隔離性,持久性。
    原子性:在事務(wù)中進(jìn)行的修改,要么全部執(zhí)行,要么全不執(zhí)行。如果在事務(wù)完成之前系統(tǒng)出現(xiàn)故
    障,SQLServer會(huì)撤銷在事務(wù)中的修改。
    一致性:為了事務(wù)在查詢和修改時(shí)數(shù)據(jù)不發(fā)生沖突。
    隔離性:隔離性是一種用于控制數(shù)據(jù)訪問的機(jī)制,能夠確保事務(wù)只能訪問處于期望的一致性級(jí)別下
    的數(shù)據(jù)。SQLServer使用鎖對(duì)各個(gè)事務(wù)之間正在修改和查詢的數(shù)據(jù)進(jìn)行隔離。
    持久性:在將數(shù)據(jù)修改寫入到磁盤之前,總是先把這些修改寫入到事務(wù)日志中。這樣子,即使數(shù)據(jù)
    還沒有寫入到磁盤中,也可以認(rèn)為事務(wù)是持久化的。這是如果系統(tǒng)重新啟動(dòng),SQL Server也會(huì)檢查
    數(shù)據(jù)庫(kù)日志,進(jìn)行恢復(fù)處理。
    隔離級(jí)別:讀未提交、讀已提交、可重復(fù)讀、串行化
  2. 事務(wù)并發(fā)產(chǎn)生的問題和隔離級(jí)別!
    事務(wù)并發(fā)產(chǎn)生的問題:
    臟讀:一個(gè)事務(wù)讀取另一個(gè)事務(wù)的未提交數(shù)據(jù)! 真錯(cuò)誤!read UNCOMMITTED;
    不可重復(fù)讀:一個(gè)事務(wù)讀取;另一個(gè)事務(wù)的提交的修改數(shù)據(jù)!read committed;
    虛讀()幻讀:一個(gè)事務(wù)讀取了另一個(gè)數(shù)的提交的插入數(shù)據(jù)!repeatable read
    隔離級(jí)別:讀未提交、讀已提交、可重復(fù)讀、串行化
    隔離級(jí)別選擇:
    數(shù)據(jù)庫(kù)隔離級(jí)別越高!數(shù)據(jù)越安全,性能越低!
    數(shù)據(jù)庫(kù)隔離級(jí)別越低!數(shù)據(jù)越不安全,性能越高
    建議:設(shè)置為第二個(gè)隔離級(jí)別 read committed;
  3. Spring中事務(wù)的傳播特性有哪些?
    七種傳播特性:
    propagation_requierd:如果當(dāng)前沒有事務(wù),就新建一個(gè)事務(wù),如果已存在一個(gè)事務(wù)中,加入到這個(gè)事
    務(wù)中,這是最常見的選擇。
    propagation_supports:支持當(dāng)前事務(wù),如果沒有當(dāng)前事務(wù),就以非事務(wù)方法執(zhí)行。
    propagation_mandatory:使用當(dāng)前事務(wù),如果沒有當(dāng)前事務(wù),就拋出異常。
    propagation_required_new:新建事務(wù),如果當(dāng)前存在事務(wù),把當(dāng)前事務(wù)掛起。
    propagation_not_supported:以非事務(wù)方式執(zhí)行操作,如果當(dāng)前存在事務(wù),就把當(dāng)前事務(wù)掛起。
    propagation_never:以非事務(wù)方式執(zhí)行操作,如果當(dāng)前事務(wù)存在則拋出異常。
    propagation_nested:如果有事務(wù)在運(yùn)行,當(dāng)前的方法就應(yīng)該在這個(gè)事務(wù)的嵌套事務(wù)內(nèi)運(yùn)行,否則就啟
    動(dòng)一個(gè)新的事務(wù),并在它自己的事務(wù)內(nèi)運(yùn)行。
    Spring 默認(rèn)的事務(wù)傳播行為是 PROPAGATION_REQUIRED
  4. MySQL的內(nèi)部有哪幾部分組成?
    連接器
    MYSQL擁有非常多的客戶端比如:navicat,jdbc,SQLyog等客戶端,這些客戶端都需要向
    MYSQL通信都必須要建立連接,這個(gè)建立連接的工作就是由連接器完成的
    查詢緩存(5.8版本開始取消了這個(gè))
    連接建立之后,你就可以執(zhí)行select語(yǔ)句了 這個(gè)時(shí)候首先會(huì)去查詢下緩存,緩存的存儲(chǔ)形式類似于
    key-value,key保存的是sql語(yǔ)句value 保存的是結(jié)果集,如果查詢不在緩存中就會(huì)執(zhí)行sql語(yǔ)句執(zhí)
    行完成后把執(zhí)行結(jié)果放入緩存中,如果是能在緩存中查詢到那么直接返回
    詞法分析器
    解析sql語(yǔ)句中的詞法, 語(yǔ)法
    優(yōu)化器
    對(duì)解析后生成的執(zhí)行計(jì)劃進(jìn)行自動(dòng)優(yōu)化, 提升查詢效率
    執(zhí)行器
    執(zhí)行sql語(yǔ)句分析后生成的執(zhí)行計(jì)劃, 執(zhí)行后返回結(jié)果
  5. MySQL如何實(shí)現(xiàn)樂觀鎖和悲觀鎖
    ①樂觀鎖實(shí)現(xiàn):版本號(hào)控制及時(shí)間戳控制。
    版本號(hào)控制:表中加一個(gè) version 字段;當(dāng)讀取數(shù)據(jù)時(shí),連同這個(gè) version 字段一起讀出;數(shù)據(jù)每
    更新一次就將此值加一;當(dāng)提交更新時(shí),判斷數(shù)據(jù)庫(kù)表中對(duì)應(yīng)記錄的當(dāng)前版本號(hào)是否與之前取出來
    的版本號(hào)一致,如果一致則可以直接更新,如果不一致則表示是過期數(shù)據(jù)需要重試或者做其它操
    作。
    時(shí)間戳控制:其原理和版本號(hào)控制差不多,也是在表中添加一個(gè) timestamp 的時(shí)間戳字段,然后
    提交更新時(shí)判斷數(shù)據(jù)庫(kù)中對(duì)應(yīng)記錄的當(dāng)前時(shí)間戳是否與之前取出來的時(shí)間戳一致,一致就更新,不
    一致就重試。
    ②悲觀鎖實(shí)現(xiàn):必須關(guān)閉mysql數(shù)據(jù)庫(kù)的自動(dòng)提交屬性,開啟事務(wù),再進(jìn)行數(shù)據(jù)庫(kù)操作,最后提交事
    務(wù)。
  6. MySQL常用的存儲(chǔ)引擎及區(qū)別
    InnoDB默認(rèn)的存儲(chǔ)引擎, 不需要任何配置, 默認(rèn)使用的就是它, 支持事務(wù), 支持主外鍵連接, 速度一般
    MyISAM不支持事務(wù), 速度快, 以讀寫插入為主的應(yīng)用程序,比如博客系統(tǒng)、新聞門戶網(wǎng)站。
    Memory存儲(chǔ)的數(shù)據(jù)都放在內(nèi)存中, 服務(wù)器斷電, 數(shù)據(jù)丟失, 速度最快, 現(xiàn)基本被redis取代.
  7. 說一說對(duì)MySQL索引的理解
    什么是數(shù)據(jù)庫(kù)索引?
    數(shù)據(jù)庫(kù)索引,是數(shù)據(jù)庫(kù)管理系統(tǒng)中一個(gè)排序的數(shù)據(jù)結(jié)構(gòu),索引實(shí)現(xiàn)通常使用B樹及變種的B+樹。在
    數(shù)據(jù)之外,數(shù)據(jù)庫(kù)系統(tǒng)還維護(hù)著滿足特定查找算法的數(shù)據(jù)結(jié)構(gòu),這些數(shù)據(jù)結(jié)構(gòu)以某種方式引用(指
    向)數(shù)據(jù),這樣就可以在這些數(shù)據(jù)結(jié)構(gòu)上實(shí)現(xiàn)高級(jí)查找算法。這種數(shù)據(jù)結(jié)構(gòu)就是索引。
    索引的作用?
    協(xié)助快速查詢、更新數(shù)據(jù)庫(kù)表中數(shù)據(jù)。
    副作用:
    增加了數(shù)據(jù)庫(kù)的存儲(chǔ)空間插入和修改數(shù)據(jù)時(shí)要花費(fèi)較多的時(shí)間(因?yàn)樗饕矔?huì)隨之變動(dòng))
  8. MySQL中什么字段適合添加索引
    表的主鍵、外鍵必須有索引;
    經(jīng)常與其他表進(jìn)行連接的表,在連接字段上應(yīng)該建立索引;
    經(jīng)常出現(xiàn)在Where子句中的字段,特別是大表的字段,應(yīng)該建立索引;
    索引應(yīng)該建在選擇性高的字段上;
    索引應(yīng)該建在小字段上,對(duì)于大的文本字段甚至超長(zhǎng)字段,不要建索引;
    復(fù)合索引的建立需要進(jìn)行仔細(xì)分析;盡量考慮用單字段索引代替:
  9. MySQL中常見的索引類型
    普通索引:是最基本的索引,它沒有任何限制
    唯一索引:與前面的普通索引類似,不同的就是:索引列的值必須唯一,但允許有空值。如果是組合索
    引,則列值的組合必須唯一
    主鍵索引:是一種特殊的唯一索引,一個(gè)表只能有一個(gè)主鍵,不允許有空值。一般是在建表的時(shí)候同時(shí)
    創(chuàng)建主鍵索引
    組合索引:指多個(gè)字段上創(chuàng)建的索引,只有在查詢條件中使用了創(chuàng)建索引時(shí)的第一個(gè)字段,索引才會(huì)被
    使用。使用組合索引時(shí)遵循最左前綴集合
  10. MySQL中索引失效的場(chǎng)景!
    WHERE字句的查詢條件里有不等于號(hào)(WHERE column!=…),MYSQL將無法使用索引,類似地,如果
    WHERE字句的查詢條件里使用了函數(shù)(如:WHERE DAY(column)=…),MYSQL將無法使用索引
    在JOIN操作中(需要從多個(gè)數(shù)據(jù)表提取數(shù)據(jù)時(shí)),MYSQL只有在主鍵和外鍵的數(shù)據(jù)類型相同時(shí)才能使用
    索引,否則即使建立了索引也不會(huì)使用
    如果WHERE子句的查詢條件里使用了比較操作符LIKE和REGEXP,MYSQL只有在搜索模板的第一個(gè)字符
    不是通配符的情況下才能使用索引。比如說,如果查詢條件是LIKE ‘a(chǎn)bc%’,MYSQL將使用索引;如果條
    件是LIKE ‘%abc’,MYSQL將不使用索引。
  11. 說一說Hash和B+樹結(jié)構(gòu)索引區(qū)別?
    hash索引 : 等值查詢效率高,不能排序,不能進(jìn)行范圍查詢;Hash索引僅僅能滿足"=",“IN"和”<=>"查
    詢,不能使用范圍查詢
    B+樹索引 : 數(shù)據(jù)有序,支持范圍查詢, 查詢效率沒有hash索引高.
  12. B+比B樹索引的區(qū)別?
    B樹,每個(gè)節(jié)點(diǎn)都儲(chǔ)存key和dta,所有節(jié)點(diǎn)組成這棵樹,并且葉子節(jié)點(diǎn)指針為null,葉子節(jié)點(diǎn)不包含任何
    關(guān)鍵字的信息。
    B+樹,所有葉子節(jié)點(diǎn)中包含了全部關(guān)鍵字的信息,及指向含有這些關(guān)鍵字記錄的指針,且葉子節(jié)點(diǎn)本身
    依關(guān)鍵字的大小自小爾達(dá)的順序鏈接,所有的非終端節(jié)點(diǎn)可以看成是索引部分,節(jié)點(diǎn)中僅含有其子樹根
    節(jié)點(diǎn)中最大的(或最小的)關(guān)鍵字。
  13. 聚集(集中)索引和非聚集(稀疏)索引的區(qū)別
    【聚集索引】:也稱 Clustered Index。是指關(guān)系表記錄的物理順序與索引的邏輯順序相同。由于一張表
    只能按照一種物理順序存放,一張表最多也只能存在一個(gè)聚集索引。與非聚集索引相比,聚集索引有著
    更快的檢索速度。
    MySQL 里只有 INNODB 表支持聚集索引,INNODB 表數(shù)據(jù)本身就是聚集索引,也就是常說 IOT,索引
    組織表。非葉子節(jié)點(diǎn)按照主鍵順序存放,葉子節(jié)點(diǎn)存放主鍵以及對(duì)應(yīng)的行記錄。所以對(duì) INNODB 表進(jìn)行
    全表順序掃描會(huì)非???。
    【非聚集索引】:也叫 Secondary Index。指的是非葉子節(jié)點(diǎn)按照索引的鍵值順序存放,葉子節(jié)點(diǎn)存放
    索引鍵值以及對(duì)應(yīng)的主鍵鍵值。MySQL 里除了 INNODB 表主鍵外,其他的都是二級(jí)索引。MYISAM,
    memory 等引擎的表索引都是非聚集索引。簡(jiǎn)單點(diǎn)說,就是索引與行數(shù)據(jù)分開存儲(chǔ)。一張表可以有多個(gè)
    二級(jí)索引。
  14. 什么是索引倒排!
    倒排索引源于實(shí)際應(yīng)用中需要根據(jù)屬性的值來查找記錄。這種索引表中的每一項(xiàng)都包括一個(gè)屬性值和具
    有該屬性值的各記錄的地址。由于不是由記錄來確定屬性值,而是由屬性值來確定記錄的位置,因而稱
    為倒排索引(inverted index)。帶有倒排索引的文件我們稱為倒排索引文件,簡(jiǎn)稱倒排文件(inverted
    file)。
  15. 如何快速的復(fù)制一張表!
    將表結(jié)構(gòu)和數(shù)據(jù)導(dǎo)出成sql腳本文件, 可以根據(jù)要求修改腳本中的表名字防止重名, 然后再導(dǎo)入到mysql中
    在庫(kù)中創(chuàng)建新表后, 使用insert into 表名(字段名) select 字段名 from 表名
  16. SQL語(yǔ)句優(yōu)化的方案?
    第一, 開啟慢查詢?nèi)罩?讓系統(tǒng)運(yùn)行一段時(shí)間, 打開慢查詢?nèi)罩菊业骄唧w需要優(yōu)化的sql語(yǔ)句
    第二, 使用explain執(zhí)行計(jì)劃分析sql語(yǔ)句中問題出現(xiàn)的哪里
    第三, 根據(jù)sql語(yǔ)句編寫規(guī)范, 進(jìn)行優(yōu)化, 例如: 不要使用like模糊查詢, 因?yàn)樗饕龝?huì)失效; 盡量避免使用
    select*, 因?yàn)闀?huì)返回?zé)o用字段; 條件中不要使用or關(guān)鍵字, 因?yàn)闀?huì)全表掃描等.
  17. 組合索引的最左原則?
    MySQL 的聯(lián)合索引會(huì)首先根據(jù)聯(lián)合索引中最左邊的、也就是第一個(gè)字段進(jìn)行排序,在第一個(gè)字段排序的
    基礎(chǔ)上,再對(duì)聯(lián)合索引中后面的第二個(gè)字段進(jìn)行排序,依此類推。聯(lián)合索引當(dāng)遇到范圍查詢(>、<、
    between、like)就會(huì)停止匹配,建立索引時(shí)匹配度高的字段在前,匹配度低的字段在后
    舉例 : a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)順序的索引,d是用不到索引的,如果建立
    (a,b,d,c)的索引則都可以用到,a,b,d的順序可以任意調(diào)整。
    =和in可以亂序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意順序,mysql的查詢優(yōu)化器會(huì)幫
    你優(yōu)化成索引可以識(shí)別的形式
  18. 什么是行鎖, 表鎖, 頁(yè)鎖?
    行鎖 : 開銷大,加鎖慢;會(huì)出現(xiàn)死鎖;鎖定粒度小,發(fā)生鎖沖突的概率低
    行鎖就是針對(duì)數(shù)據(jù)表中行記錄的鎖。這很好理解,比如事務(wù)A更新了一行,而這時(shí)候事務(wù)B也要更新
    同一行,則必須等事務(wù)A的操作完成后才能進(jìn)行更新。
    表鎖 : 開銷小,加鎖快;不會(huì)出現(xiàn)死鎖;鎖定粒度大,發(fā)生鎖沖突概率高
    表鎖的語(yǔ)法是 lock tables … read/write??梢杂胾nlock tables主動(dòng)釋放鎖,也可以在客戶端斷開
    的時(shí)候自動(dòng)釋放。需要注意,lock tables語(yǔ)法除了會(huì)限制別的線程的讀寫外,也限定了本線程接下
    來的操作對(duì)象。
    頁(yè)級(jí)鎖
    頁(yè)級(jí)鎖是MySQL中鎖定粒度介于行級(jí)鎖和表級(jí)鎖中間的一種鎖。表級(jí)鎖速度快,但沖突多,行級(jí)沖
    突少,但速度慢。所以取了折衷的頁(yè)級(jí),一次鎖定相鄰的一組記錄。
    特點(diǎn):開銷和加鎖時(shí)間界于表鎖和行鎖之間;會(huì)出現(xiàn)死鎖;鎖定粒度界于表鎖和行鎖之間,并發(fā)度
    一般
  19. 數(shù)據(jù)庫(kù)的三范式是什么
    第一范式:1NF 是對(duì)屬性的原子性約束,強(qiáng)調(diào)的引擎是列的原子性,即數(shù)據(jù)庫(kù)表的每一列都是不可分割
    的原子數(shù)據(jù)項(xiàng)。
    第二范式:2NF 是對(duì)記錄的惟一性約束,要求實(shí)體的屬性完全依賴于主關(guān)鍵字。所謂完全依賴是指不能
    存在僅依賴主關(guān)鍵字一部分的屬性。
    第三范式:3NF 是對(duì)字段冗余性的約束,任何非主屬性不依賴于其它非主屬性。即任何字段不能由其他
    字段派生出來, 它要求字段沒有冗余。
  20. 什么情況下設(shè)置了索引但無法使用
    以“%”開頭的 LIKE 語(yǔ)句,模糊匹配
    OR 語(yǔ)句前后沒有同時(shí)使用索引
    數(shù)據(jù)類型出現(xiàn)隱式轉(zhuǎn)化(如 varchar 不加單引號(hào)的話可能會(huì)自動(dòng)轉(zhuǎn)換為 int 型)

八、常用框架【19道】

  1. MyBatis$和#的區(qū)別
    #{ }可以防止Sql 注入,它會(huì)將所有傳入的參數(shù)作為一個(gè)字符串來處理。
    Mybatis在處理#{}時(shí),會(huì)將SQL語(yǔ)句中的#{}替換為?號(hào),調(diào)用PrepaerdStatement的set方法來賦值。
    $ {} 則將傳入的參數(shù)拼接到Sql上去執(zhí)行,一般用于表名和字段名參數(shù),$ 所對(duì)應(yīng)的參數(shù)應(yīng)該由服務(wù)器端
    提供,前端可以用參數(shù)進(jìn)行選擇,避免 Sql 注入的風(fēng)險(xiǎn)
    Mybatis在處理 時(shí),就是把 {}時(shí),就是把 時(shí),就是把{}換成變量的值。
  2. MyBatis中一級(jí)緩存和二級(jí)緩存的區(qū)別
    一級(jí)緩存 :
    一級(jí)緩存是基于sqlsession默認(rèn)開啟的,在操作數(shù)據(jù)庫(kù)時(shí)需要構(gòu)造SqlSession對(duì)象,在對(duì)象中有一
    個(gè)HashMap用于存儲(chǔ)緩存數(shù)據(jù)。不同的SqlSession之間的緩存數(shù)據(jù)區(qū)域是互相不影響的。
    一級(jí)緩存作用是sqlsession范圍的,在同一個(gè)sqlsession中執(zhí)行兩次相同的sql時(shí),第一次得到的數(shù)
    據(jù)會(huì)緩存放在內(nèi)存中,第二次不再去數(shù)據(jù)庫(kù)獲取,而是直接在緩存中獲取,提高效率。
    如果執(zhí)行了增刪改并提交到數(shù)據(jù)庫(kù),mybatis是會(huì)把sqlsession中的一級(jí)緩存清空的,這樣是為了
    數(shù)據(jù)的準(zhǔn)確性,避免臟讀現(xiàn)象。
    二級(jí)緩存 :
    二級(jí)緩存是基于mapper的namespace作用域,但多個(gè)sqlsession操作同一個(gè)namespace下的sql
    時(shí),并且傳入的參數(shù)也相同,執(zhí)行相同的sql語(yǔ)句,第一次執(zhí)行完畢后會(huì)將數(shù)據(jù)緩存,這就是二級(jí)
    緩存。
    二級(jí)緩存同樣是使用HashMap進(jìn)行數(shù)據(jù)存儲(chǔ)。相比一級(jí)緩存SqlSession,二級(jí)緩存的范圍更大,
    多個(gè)Sqlsession可以共用二級(jí)緩存,二級(jí)緩存它是可以跨越多個(gè)sqlsession的。
  3. MyBatis和數(shù)據(jù)庫(kù)交互的原理
    詳細(xì)流程如下:
    加載mybatis全局配置文件(數(shù)據(jù)源、mapper映射文件等),解析配置文件,MyBatis基于XML配置文
    件生成Configuration,和一個(gè)個(gè)MappedStatement(包括了參數(shù)映射配置、動(dòng)態(tài)SQL語(yǔ)句、結(jié)果映射
    配置),其對(duì)應(yīng)著<select | update | delete | insert>標(biāo)簽項(xiàng)。
    SqlSessionFactoryBuilder通過Configuration對(duì)象生成SqlSessionFactory,用來開啟SqlSession。
    SqlSession對(duì)象完成和數(shù)據(jù)庫(kù)的交互, 通過Executor執(zhí)行器將MappedStatement對(duì)象進(jìn)行解析,最后通
    過JDBC執(zhí)行sql。
    借助MappedStatement中的結(jié)果映射關(guān)系,將返回結(jié)果轉(zhuǎn)化成HashMap、JavaBean等存儲(chǔ)結(jié)構(gòu)并返
    回。
  4. Spring的IOC是什么
    SpringIOC是控制反轉(zhuǎn), 負(fù)責(zé)創(chuàng)建對(duì)象,管理對(duì)象,裝配對(duì)象,配置對(duì)象,并且管理對(duì)象的整個(gè)生命周期,
    也就是以前創(chuàng)建對(duì)象需要new, 那么在使用了spring的IOC后, 所有這樣的工作都交給spring進(jìn)行管理.
  5. Spring的常用注解
    @Autowired 用于自動(dòng)注入bean
    @Resource 根據(jù)名字注入bean
    @Controller 用于聲明控制層類
    @Repository 用于聲明Dao持久層類
    @Service 用于聲明Service業(yè)務(wù)層類
    @Component 用于聲明一個(gè)普通JavaBean
    @Configuration 用于聲明初始化類相當(dāng)于spring核心配置文件的標(biāo)簽
    @Bean 聲明一個(gè)配置, 相當(dāng)于spring核心配置文件的標(biāo)簽
  6. Spring的IOC中創(chuàng)建對(duì)象的整體流程
    通過ClassPathXmlApplicationContext對(duì)象加載spring核心配置文件創(chuàng)建ApplicationContext對(duì)象
    通過applicationContext對(duì)象的getBean(beanName)方法創(chuàng)建所需類對(duì)象
    轉(zhuǎn)換beanName,因?yàn)閭魅氲膮?shù)可能是別名,也可能是FactoryBean,所以需要解析
    如果是beanName,不需要處理
    如果是 “&beanName”,則去掉&
    如果是別名,則轉(zhuǎn)換為beanName
  7. Spring的Bean的三級(jí)緩存
    一級(jí)緩存singletonObjects是完整的bean,它可以被外界任意使用,并且不會(huì)有歧義。
    二級(jí)緩存earlySingletonObjects是不完整的bean,沒有完成初始化,它與singletonObjects的分離主要
    是職責(zé)的分離以及邊界劃分,可以試想一個(gè)Map緩存里既有完整可使用的bean,也有不完整的,只能持
    有引用的bean,在復(fù)雜度很高的架構(gòu)中,很容易出現(xiàn)歧義,并帶來一些不可預(yù)知的錯(cuò)誤。
    三級(jí)緩存singletonFactories,其職責(zé)就是包裝一個(gè)bean,有回調(diào)邏輯,所以它的作用非常清晰,并且
    只能處于第三層。
    在實(shí)際使用中,要獲取一個(gè)bean,先從一級(jí)緩存一直查找到三級(jí)緩存,緩存bean的時(shí)候是從三級(jí)到一
    級(jí)的順序保存,并且緩存bean的過程中,三個(gè)緩存都是互斥的,只會(huì)保持bean在一個(gè)緩存中,而且,
    最終都會(huì)在一級(jí)緩存中。
  8. Spring如何處理循環(huán)依賴
    構(gòu)造器參數(shù)循環(huán)依賴 :
    通過構(gòu)造器注入構(gòu)成的循環(huán)依賴,此依賴是無法解決的,只能拋出BeanCurrentlyIn
    CreationException異常表示循環(huán)依賴。
    如在創(chuàng)建TestA類時(shí),構(gòu)造器需要TestB類,那將去創(chuàng)建TestB,在創(chuàng)建TestB類時(shí)又發(fā)現(xiàn)需要TestC
    類,則又去創(chuàng)建TestC,最終在創(chuàng)建TestC時(shí)發(fā)現(xiàn)又需要TestA,從而形成一個(gè)環(huán),沒辦法創(chuàng)建。
    Spring容器會(huì)將每一個(gè)正在創(chuàng)建的Bean 標(biāo)識(shí)符放在一個(gè)“當(dāng)前創(chuàng)建Bean池”中,Bean標(biāo)識(shí)符在創(chuàng)建
    過程中將一直保持在這個(gè)池中,因此如果在創(chuàng)建Bean過程中發(fā)現(xiàn)自己已經(jīng)在“當(dāng)前創(chuàng)建Bean池”里
    時(shí)將拋出BeanCurrentlyInCreationException異常表示循環(huán)依賴;而對(duì)于創(chuàng)建完畢的Bean將從“當(dāng)
    前創(chuàng)建Bean池”中清除掉。
    setter方式單例,默認(rèn)方式 :
    Spring先是用構(gòu)造實(shí)例化Bean對(duì)象 ,此時(shí)Spring會(huì)將這個(gè)實(shí)例化結(jié)束的對(duì)象放到一個(gè)Map中,并
    且Spring提供了獲取這個(gè)未設(shè)置屬性的實(shí)例化對(duì)象引用的方法。當(dāng)Spring實(shí)例化了StudentA、
    StudentB、StudentC后,緊接著會(huì)去設(shè)置對(duì)象的屬性,此時(shí)StudentA依賴StudentB,就會(huì)去Map
    中取出存在里面的單例StudentB對(duì)象,以此類推,不會(huì)出來循環(huán)的問題。
    prototype作用域bean的循環(huán)依賴 :
    這種循環(huán)依賴同樣無法解決,因?yàn)閟pring不會(huì)緩存prototype作用域的bean,而spring中循環(huán)依賴
    的解決方式正是通過緩存來實(shí)現(xiàn)的。
    Spring解決這個(gè)問題主要靠巧妙的三層緩存,Spring首先從singleTonObjects(一級(jí)緩存)中嘗試
    獲取,如果獲取不到并且對(duì)象在創(chuàng)建中,則嘗試從earlySingleTonObjects(二級(jí)緩存)中獲取,
    如果還是獲取不到并且允許從singleTonFactories通過getObject獲取,則通過
    singleTonFactory.getObject()(三級(jí)緩存)獲取。
    如果獲取到了則移除相對(duì)應(yīng)的singleTonFactory,將singleTonObject放入到
    earlySingleTonObjects,其實(shí)就是將三級(jí)緩存提升到二級(jí)緩存,這個(gè)就是緩存升級(jí)。Spring在進(jìn)行
    對(duì)象創(chuàng)建的時(shí)候,會(huì)依次從一級(jí)、二級(jí)、三級(jí)緩存中尋找對(duì)象,如果找到直接返回。
    拓展:
    一級(jí)緩存:singletonObjects,存放完全實(shí)例化屬性賦值完成的單例對(duì)象的cache,直接可以使
    用。
    二級(jí)緩存:earlySingletonObjects,存放提前曝光的單例對(duì)象的cache,尚未進(jìn)行屬性封裝的
    Bean。
    三級(jí)緩存:singletonFactories,存放單例對(duì)象工廠的cache。
  9. @Autowired和@Resource的區(qū)別
    @Autowired是自動(dòng)注入, 一個(gè)接口只有一個(gè)實(shí)現(xiàn)類的時(shí)候使用
    @Resource是根據(jù)bean的名字注入, 一個(gè)接口有多個(gè)實(shí)現(xiàn)類的時(shí)候使用, @Resource(實(shí)現(xiàn)類bean名字)
    根據(jù)實(shí)現(xiàn)類的名字注入指定實(shí)現(xiàn)類.
  10. SpringMVC的執(zhí)行流程
  11. Spring和SpringMVC的父子工廠關(guān)系
    Spring容器是父容器,包含的對(duì)象有dao,service等
    Springmvc是子容器,包括controller
    子容器可以訪問父容器的對(duì)象
    父容器不能訪問子容器的對(duì)象
  12. 闡述SpringBoot啟動(dòng)類中注解
    @SpringBootAplication:這個(gè)注解是啟動(dòng)springboot,從源碼我們會(huì)發(fā)現(xiàn)這個(gè)注解被
    @Configuration、@EnableAutoConfiguration、 @ComponentScan三個(gè)注解修飾。換言之,
    springboot提供了統(tǒng)一的注解來替代這三個(gè)注解。
    @EnableEurekaClient:這個(gè)注解是必須的,表示注冊(cè)到某個(gè)Eureka服務(wù)(注冊(cè)中心)中,相當(dāng)于給這個(gè)
    服務(wù)加了一個(gè)通行證,通行證的具體的內(nèi)容需要在application.yml中配置。一般配置里面會(huì)有:
    eureka、client、serviceurl、defaultZone:http://,代表注冊(cè)到上面的注冊(cè)中心,這個(gè)注冊(cè)中心里面
    的服務(wù)包括所有的接口都可以通過協(xié)商對(duì)方暴露的接口之后直接按照規(guī)則進(jìn)行調(diào)用
    @MapperScan:這個(gè)注解是用來掃描到dao的范圍的。如果使用的是mybatis的話,需要通過配置文件
    來之指定Mapper和主要的配置文件的位置。
    @EnableRedisHttpSession:這個(gè)注解是用來獲取session中緩存的內(nèi)容, 還需要配合配置文件來完
    成。
  13. SpringBoot如何實(shí)現(xiàn)的自動(dòng)裝配
    Spring Boot 通過@EnableAutoConfiguration開啟自動(dòng)裝配,通過 SpringFactoriesLoader 最終加載
    META-INF/spring.factories中的自動(dòng)配置類實(shí)現(xiàn)自動(dòng)裝配,自動(dòng)配置類其實(shí)就是通過@Conditional按需
    加載的配置類,想要其生效必須引入spring-boot-starter-xxx包實(shí)現(xiàn)起步依賴
  14. Spring事務(wù)的傳播行為?
    事務(wù)傳播行為(propagation behavior)指的就是當(dāng)一個(gè)事務(wù)方法被另一個(gè)事務(wù)方法調(diào)用時(shí),這個(gè)事務(wù)
    方法應(yīng)該如何進(jìn)行。是為自己開啟一個(gè)新事務(wù)運(yùn)行,還是由原來的事務(wù)執(zhí)行, 這是由傳播行為決定的
  15. Spring中AOP底層實(shí)現(xiàn)原理
    AOP底層實(shí)現(xiàn)使用了動(dòng)態(tài)代理
    在spring中有兩種實(shí)現(xiàn)方式, 一種是JDK動(dòng)態(tài)代理, 一種是CJlib動(dòng)態(tài)代理
    JDK動(dòng)態(tài)代理針對(duì)實(shí)現(xiàn)了接口的類使用
    CJlib動(dòng)態(tài)代理針對(duì)只有類的時(shí)候使用
  16. Spring中ApplicationContext對(duì)象和BeanFactory對(duì)象區(qū)別?
    這兩個(gè)對(duì)象都可以創(chuàng)建JavaBean對(duì)象
    ApplicationContext對(duì)象 : 這個(gè)對(duì)象底層是通過BeanFactory對(duì)象實(shí)現(xiàn)的, 但是ApplicationContext創(chuàng)建
    JavaBean的時(shí)機(jī)是調(diào)用了這個(gè)對(duì)象的getBean()方法, 就會(huì)立即創(chuàng)建JavaBean
    BeanFactory對(duì)象 : 它創(chuàng)建JavaBean的時(shí)機(jī)是調(diào)用getBean方法不進(jìn)行創(chuàng)建JavaBean而是等到用到了
    JavaBean的時(shí)候才去創(chuàng)建.
  17. Spring中的注入方式有哪些
    常用的注入方式主要有三種:
    構(gòu)造方法注入 : 構(gòu)造方法注入會(huì)有不支持的情況發(fā)生,因?yàn)樵谡{(diào)用構(gòu)造方法中必須傳入正確的構(gòu)造
    參數(shù),否則報(bào)錯(cuò)。
    setter注入 : 注入支持大部分的依賴注入
    基于注解的注入 : 可以在類中使用@Autowired或是@Resource注解進(jìn)行注入.
    Spring中Bean的生命周期
  18. Spring 支持幾種 bean 的作用域
    支持如下5種作用域:
    singleton(默認(rèn)的):單例模式,在整個(gè)Spring IoC容器中,使用singleton定義的Bean將只有一個(gè)實(shí)

    prototype:原型模式,每次通過容器的getBean方法獲取prototype定義的Bean時(shí),都將產(chǎn)生一
    個(gè)新的Bean實(shí)例
    request:對(duì)于每次HTTP請(qǐng)求,使用request定義的Bean都將產(chǎn)生一個(gè)新實(shí)例,即每次HTTP請(qǐng)求
    將會(huì)產(chǎn)生不同的Bean實(shí)例。只有在Web應(yīng)用中使用Spring時(shí),該作用域才有效
    session:對(duì)于每次HTTP Session,使用session定義的Bean豆?jié){產(chǎn)生一個(gè)新實(shí)例。同樣只有在
    Web應(yīng)用中使用Spring時(shí),該作用域才有效
    globalsession:每個(gè)全局的HTTP Session,使用session定義的Bean都將產(chǎn)生一個(gè)新實(shí)例。典型
    情況下,僅在使用portlet context的時(shí)候有效。同樣只有在Web應(yīng)用中使用Spring時(shí),該作用域才
    有效
  19. Spring中Bean的生命周期

九、中間件和分布式 【54道】

  1. Nginx的應(yīng)用場(chǎng)景有哪些?
    負(fù)載均衡, 反向代理, 靜態(tài)資源服務(wù)器
  2. Nginx負(fù)載均衡的策略有哪些?
    輪詢(默認(rèn)), 指定權(quán)重, IP hash
  3. Nginx的進(jìn)程模型 ?
    nginx模型有兩種進(jìn)程,master進(jìn)程(相當(dāng)于管理進(jìn)程)和worker進(jìn)程(實(shí)際工作進(jìn)程)。
    master進(jìn)程主要用來管理worker進(jìn)程,管理包含:接收來自外界的信號(hào),向各worker進(jìn)程發(fā)送信號(hào),
    監(jiān)控worker進(jìn)程的運(yùn)行狀態(tài),當(dāng)worker進(jìn)程退出后(異常情況下),會(huì)自動(dòng)重新啟動(dòng)新的worker進(jìn)程。
    而基本的網(wǎng)絡(luò)事件,則是放在worker進(jìn)程中來處理了。多個(gè)worker進(jìn)程之間是對(duì)等的,他們同等競(jìng)爭(zhēng)來
    自客戶端的請(qǐng)求,各進(jìn)程互相之間是獨(dú)立的。一個(gè)請(qǐng)求,只可能在一個(gè)worker進(jìn)程中處理,一個(gè)worker
    進(jìn)程,不可能處理其它進(jìn)程的請(qǐng)求。worker進(jìn)程的個(gè)數(shù)是可以設(shè)置的,一般我們會(huì)設(shè)置與機(jī)器cpu核數(shù)
    一致,這里面的原因與nginx的進(jìn)程模型以及事件處理模型是分不開的。
  4. Nginx常用命令!
    啟動(dòng) ./nginx
    關(guān)閉 ./nginx -s stop
    查看nginx進(jìn)程 ps -ef | grep nginx
    重新加載nginx ./nginx -s reload
  5. Nginx的優(yōu)化方案!
    nginx 進(jìn)程數(shù),建議按照cpu 數(shù)目來指定,一般為它的倍數(shù) (如,2個(gè)四核的cpu計(jì)為8)。
    為每個(gè)進(jìn)程分配cpu,上例中將8 個(gè)進(jìn)程分配到8 個(gè)cpu,當(dāng)然可以寫多個(gè),或者將一個(gè)進(jìn)程分配到多個(gè)
    cpu。
    配置每個(gè)進(jìn)程允許的最多連接數(shù), 理論上每臺(tái)nginx 服務(wù)器的最大連接數(shù)為 : worker進(jìn)程數(shù) * worker連
    接數(shù)。
  6. Redis的應(yīng)用場(chǎng)景!
    熱點(diǎn)數(shù)據(jù)的緩存, 限時(shí)業(yè)務(wù)的運(yùn)用, 計(jì)數(shù)器相關(guān)問題, 排行榜相關(guān)問題, 分布式鎖, 點(diǎn)贊、好友等相互關(guān)系的
    存儲(chǔ)等
  7. Redis存儲(chǔ)數(shù)據(jù)的結(jié)構(gòu)!
    Redis的Key-Value格式中Key只能是String類型
    Redis的Value類型有5種:
    String, List, Set(無序Set), ZSet(有序Set), Hash類型(Map)
  8. Redis持久化策略!
    redis的持久化策策略有2種:默認(rèn)是RDB
    RDB(數(shù)據(jù)快照模式),定期存儲(chǔ),保存的是數(shù)據(jù)本身,操作磁盤頻率低, 速度快, 服務(wù)器突然斷電數(shù)據(jù)
    可能丟失一部分.
    AOF(追加模式),每次修改數(shù)據(jù)時(shí),同步到硬盤(寫操作日志),保存的是數(shù)據(jù)的變更記錄, 頻繁操作磁
    盤, 速度慢, 但是數(shù)據(jù)可靠不容易丟失.
  9. Redis集群架構(gòu)!
    哨兵模式:
    需要三臺(tái)服務(wù)器, 一臺(tái)哨兵服務(wù)器, 一臺(tái)主機(jī), 一臺(tái)備機(jī)
    哨兵使用心跳檢測(cè)技術(shù)每隔一段時(shí)間向主機(jī)發(fā)送ping命令, 主機(jī)返回pong命令, 認(rèn)為主機(jī)存活, 如果主機(jī)
    不返回pong命令, 認(rèn)為主機(jī)宕機(jī)
    哨兵服務(wù)器就會(huì)通知備機(jī)進(jìn)行切換, 備機(jī)充當(dāng)主機(jī), 備機(jī)會(huì)最后ping一次主機(jī), 如果主機(jī)返回pong命令不
    進(jìn)行切換, 如果主機(jī)沒有返回pong命令則認(rèn)為主機(jī)確實(shí)宕機(jī), 備機(jī)切換成主機(jī)替代主機(jī)工作
  10. Redis的淘汰策略
    volatile-lru:從設(shè)置過期時(shí)間的數(shù)據(jù)集中挑選出最近最少使用的數(shù)據(jù)淘汰。
    volatile-ttl:淘汰機(jī)制采用LRU,策略基本上與volatile-lru相似,從設(shè)置過期時(shí)間的數(shù)據(jù)集中挑選將要過
    期的數(shù)據(jù)淘汰,ttl值越大越優(yōu)先被淘汰。
    volatile-random:隨機(jī)淘汰, 從已設(shè)置過期時(shí)間的數(shù)據(jù)集中任意選擇數(shù)據(jù)淘汰。
    allkeys-lru:從所有數(shù)據(jù)集中挑選最近最少使用的數(shù)據(jù)淘汰,該策略要淘汰的key面向的是全體key集
    合,而非過期的key集合。
    allkeys-random:從所有數(shù)據(jù)集中選擇任意數(shù)據(jù)淘汰。
  11. Redis緩存的擊穿,穿透,雪崩,傾斜問題!
    緩存擊穿:
    就是某一個(gè)熱點(diǎn)數(shù)據(jù),緩存中某一時(shí)刻失效了,因而大量并發(fā)請(qǐng)求打到數(shù)據(jù)庫(kù)上,就像被擊穿了一
    樣。說白了,就是某個(gè)數(shù)據(jù),數(shù)據(jù)庫(kù)有,但是緩存中沒有。那么,緩存擊穿,就會(huì)使得因?yàn)檫@一個(gè)
    熱點(diǎn)數(shù)據(jù),將大量并發(fā)請(qǐng)求打擊到數(shù)據(jù)庫(kù)上,從而導(dǎo)致數(shù)據(jù)庫(kù)被打垮。
    緩存擊穿解決方案:
    去掉熱點(diǎn)數(shù)據(jù)的生存時(shí)間
    熱點(diǎn)數(shù)據(jù)訪問到數(shù)據(jù)庫(kù)的時(shí)候加個(gè)鎖, 這樣同一時(shí)間只能有一個(gè)訪問熱點(diǎn)數(shù)據(jù)的請(qǐng)求訪問數(shù)據(jù)庫(kù), 防
    止數(shù)據(jù)庫(kù)宕機(jī).
    緩存穿透 :
    緩存穿透與擊穿的區(qū)別就是,
    擊穿:redis中沒有數(shù)據(jù), 數(shù)據(jù)庫(kù)里“有”數(shù)據(jù);
    穿透:redis中沒有數(shù)據(jù), 數(shù)據(jù)庫(kù)里也“沒”數(shù)據(jù)。
    緩存穿透解決方案:
    用戶查詢會(huì)有查詢參數(shù), 使用查詢參數(shù)作為key, value值設(shè)置為null, 存入redis并設(shè)置生存時(shí)間, 如果
    這樣的請(qǐng)求多了, redis抗壓,但是不會(huì)造成數(shù)據(jù)庫(kù)宕機(jī).
    使用布隆過濾器, 直接過濾這樣的查詢請(qǐng)求
    緩存雪崩 : 指的是大面積的 key 同時(shí)過期,導(dǎo)致大量并發(fā)打到我們的數(shù)據(jù)庫(kù)。
    雪崩解決方案 : 將key的過期時(shí)間設(shè)置為隨機(jī), 這樣不會(huì)在同一時(shí)間大量過期, 不會(huì)在同一時(shí)間造成
    大量數(shù)據(jù)庫(kù)訪問, 防止數(shù)據(jù)庫(kù)宕機(jī)
  12. Redis的緩存和數(shù)據(jù)庫(kù)的雙寫一致性!
    數(shù)據(jù)庫(kù)和redis同步數(shù)據(jù)流程 : 寫數(shù)據(jù)庫(kù), 刪除redis對(duì)應(yīng)緩存數(shù)據(jù), 再將數(shù)據(jù)庫(kù)最新數(shù)據(jù)寫入redis中
    將不一致分為三種情況:
    數(shù)據(jù)庫(kù)有數(shù)據(jù),緩存沒有數(shù)據(jù);
    數(shù)據(jù)庫(kù)有數(shù)據(jù),緩存也有數(shù)據(jù),數(shù)據(jù)不相等;
    數(shù)據(jù)庫(kù)沒有數(shù)據(jù),緩存有數(shù)據(jù)。
    解決方案大概有以下幾種:
    對(duì)刪除緩存進(jìn)行重試,數(shù)據(jù)的一致性要求越高,我越是重試得快。
    定期全量更新,簡(jiǎn)單地說,就是我定期把緩存全部清掉,然后再全量加載。
    給所有的緩存一個(gè)失效期
  13. Redis如何實(shí)現(xiàn)的分布式鎖!
    獲取鎖:
    使用setnx命令向redis中存入一個(gè)鍵值對(duì)并設(shè)置過期時(shí)間
    setnx命令在存入之前會(huì)進(jìn)行判斷, 如果redis中存在這個(gè)鍵值對(duì), 則無法存入并返回狀態(tài)0, 相當(dāng)于鎖
    被占用, 無法獲取鎖可以進(jìn)入等待或再一次嘗試, 如果redis中不存在這個(gè)鍵值對(duì), 則可以存入并返回
    狀態(tài)1
    釋放鎖:
    使用setnx命令存入數(shù)據(jù)后, 相當(dāng)于獲取到了鎖, 執(zhí)行完業(yè)務(wù)后一定要使用delete命令刪除這個(gè)鍵值
    對(duì), 就相當(dāng)于釋放鎖,其他任務(wù)就可以繼續(xù)以上面方式獲取鎖, 因?yàn)樵O(shè)置了鍵值對(duì)的超時(shí)時(shí)間,在規(guī)定
    時(shí)間內(nèi)沒有釋放鎖會(huì)redis會(huì)自動(dòng)讓這個(gè)鍵值對(duì)失效,防止死鎖
  14. Redis的線程模型
    從redis的性能上進(jìn)行考慮,單線程避免了上下文頻繁切換問題,效率高;
    從redis的內(nèi)部結(jié)構(gòu)設(shè)計(jì)原理進(jìn)行考慮,redis是基于Reactor模式開發(fā)了自己的網(wǎng)絡(luò)事件處理器: 這個(gè)處
    理器被稱為文件事件處理器(file event handler)。而這個(gè)文件事件處理器是單線程的,所以才叫redis
    的單線程模型,這也決定了redis是單線程的
  15. Elasticsearch的應(yīng)用場(chǎng)景
    互聯(lián)網(wǎng)全文檢: 像百度, 谷歌等
    站內(nèi)全文檢索: 貼吧內(nèi)帖子搜索, 京東, 淘寶商品搜索等
    總之就是大數(shù)據(jù)量, 海量數(shù)據(jù)的搜索功能都可以用ElasticSearch
  16. 什么是倒排索引
    搜索前, 根據(jù)被搜索的內(nèi)容創(chuàng)建文檔對(duì)象, 文檔對(duì)象有唯一id, 對(duì)被搜索內(nèi)容進(jìn)行切分詞, 也就是將被搜索
    的內(nèi)容中的一句句話切分成一個(gè)個(gè)詞, 組成索引, 索引記錄了文檔id, 也就是索引和文檔有關(guān)聯(lián)關(guān)系, 查詢
    的時(shí)候先查詢索引, 根據(jù)索引找到文檔id, 根據(jù)文檔id找到文檔內(nèi)容, 這個(gè)過程叫做倒排索引算法
  17. Elasticsearch在5.x,6.x,7.x版本的區(qū)別
    5.x Lucene 6.x 的支持,磁盤空間少一半;索引時(shí)間少一半;查詢性能提升25%;支持IPV6。
    6.x 開始不支持一個(gè) index 里面存在多個(gè) type
    7.x TransportClient被廢棄以至于es7的java代碼,只能使用restclient。對(duì)于java編程,建議采用 Highlevel-rest-client 的方式操作ES集群
  18. Elasticsearch中分片的概念
    單個(gè)節(jié)點(diǎn)由于物理機(jī)硬件限制,存儲(chǔ)的文檔是有限的,如果一個(gè)索引包含海量文檔,則不能在單個(gè)節(jié)點(diǎn)
    存儲(chǔ)。ES提供分 片機(jī)制,同一個(gè)索引可以存儲(chǔ)在不同分片(數(shù)據(jù)容器)中,這些分片又可以存儲(chǔ)在集群
    中不同節(jié)點(diǎn)上
    分片分為 主分片(primary shard) 以及 從分片(replica shard)
    主分片與從分片關(guān)系:從分片只是主分片的一個(gè)副本,它用于提供數(shù)據(jù)的冗余副本
    從分片應(yīng)用:在硬件故障時(shí)提供數(shù)據(jù)保護(hù),同時(shí)服務(wù)于搜索和檢索這種只讀請(qǐng)求
    是否可變:索引中的主分片的數(shù)量在索引創(chuàng)建后就固定下來了,但是從分片的數(shù)量可以隨時(shí)改變
    索引默認(rèn)創(chuàng)建的分片:默認(rèn)設(shè)置5個(gè)主分片和一組從分片(即每個(gè)主分片有一個(gè)從分片對(duì)應(yīng)),但是從分
    片沒有被啟用(主從分片在同一個(gè)節(jié)點(diǎn)上沒有意義),因此集群健康值顯示為黃色(yellow)
  19. Elasticsearch中refresh和flush是什么
    Refresh:
    當(dāng)我們向ES發(fā)送請(qǐng)求的時(shí)候,我們發(fā)現(xiàn)es貌似可以在我們發(fā)請(qǐng)求的同時(shí)進(jìn)行搜索。而這個(gè)實(shí)時(shí)建索
    引并可以被搜索的過程實(shí)際上是一次es 索引提交(commit)的過程,如果這個(gè)提交的過程直接將
    數(shù)據(jù)寫入磁盤(fsync)必然會(huì)影響性能,所以es中設(shè)計(jì)了一種機(jī)制,即:先將index-buffer中文檔
    (document)解析完成的segment寫到filesystem cache之中,這樣避免了比較損耗性能的io操
    作,又可以使document可以被搜索。以上從index-buffer中取數(shù)據(jù)到filesystem cache中的過程叫
    做refresh。
    es默認(rèn)的refresh間隔時(shí)間是1s,這也是為什么ES可以進(jìn)行近乎實(shí)時(shí)的搜索
    Flush :
    我們可能已經(jīng)意識(shí)到如果數(shù)據(jù)在filesystem cache之中是很有可能在意外的故障中丟失。這個(gè)時(shí)候
    就需要一種機(jī)制,可以將對(duì)es的操作記錄下來,來確保當(dāng)出現(xiàn)故障的時(shí)候,保留在filesystem的數(shù)
    據(jù)不會(huì)丟失,并在重啟的時(shí)候可以從這個(gè)記錄中將數(shù)據(jù)恢復(fù)過來。elasticsearch提供了translog來
    記錄這些操作。當(dāng)向elasticsearch發(fā)送創(chuàng)建document索引請(qǐng)求的時(shí)候,document數(shù)據(jù)會(huì)先進(jìn)入
    到index buffer之后,與此同時(shí)會(huì)將操作記錄在translog之中,當(dāng)發(fā)生refresh時(shí)(數(shù)據(jù)從index
    buffer中進(jìn)入filesystem cache的過程)translog中的操作記錄并不會(huì)被清除,而是當(dāng)數(shù)據(jù)從
    filesystem cache中被寫入磁盤之后才會(huì)將translog中清空。而從filesystem cache寫入磁盤的過程
    就是flush。
  20. 如何提升Elasticsearch的查詢效率
    調(diào)優(yōu)Filesystem Cache性能的方法:
    要讓 ES 性能好,最佳的情況下,就是機(jī)器的內(nèi)存,至少可以容納總數(shù)據(jù)量的一半。索引數(shù)據(jù)占用
    的內(nèi)存最好控制在留給Filesystem Cache的內(nèi)存容量中。盡量將所有索引數(shù)據(jù)加載到內(nèi)存中, 這樣
    搜索的時(shí)候可以從內(nèi)存中搜索索引速度極快.
    冷熱分離方法:
    將熱門數(shù)據(jù)寫一個(gè)索引,冷門數(shù)據(jù)單獨(dú)寫一個(gè)索引,這樣在熱門數(shù)據(jù)被預(yù)熱(即寫入Filesystem
    Cache)后,不會(huì)被冷數(shù)據(jù)給沖刷掉。
    數(shù)據(jù)預(yù)熱方法:
    對(duì)于熱門的搜索詞,后臺(tái)系統(tǒng)可以定時(shí)自己去搜索一下,這樣,熱門數(shù)據(jù)就會(huì)刷到Filesystem
    Cache中,后面用戶實(shí)際來搜索熱詞時(shí)就是直接從內(nèi)存中搜索了
  21. 如何提高Elasticsearch的查詢命中率
    加入擴(kuò)展詞詞典ext.dic
    主要有兩項(xiàng):生詞擴(kuò)展和同義詞擴(kuò)展
    生詞擴(kuò)展:把網(wǎng)絡(luò)用語(yǔ)、公司名稱等詞語(yǔ)放入詞典中
    同義詞擴(kuò)展:如我們平常用的iphone,當(dāng)輸入“蘋果”的時(shí)候,我們也是期待能查出手機(jī)的。
    加入停止詞詞典stop.dic
    把 了、啊、哦、的、之類的語(yǔ)氣詞放入停止詞詞典;把數(shù)據(jù)篩選過濾
  22. RabbitMQ的應(yīng)用場(chǎng)景
    異步處理
    很多時(shí)候,用戶不想也不需要立即處理消息。消息隊(duì)列提供了異步處理機(jī)制,允許用戶把一個(gè)消息
    放入隊(duì)列,但并不立即處理它。想向隊(duì)列中放入多少消息就放多少,然后在需要的時(shí)候再去處理它
    們。
    應(yīng)用解耦
    在項(xiàng)目啟動(dòng)之初來預(yù)測(cè)將來項(xiàng)目會(huì)碰到什么需求,是極其困難的。消息系統(tǒng)在處理過程中間插入了
    一個(gè)隱含的、基于數(shù)據(jù)的接口層,兩邊的處理過程都要實(shí)現(xiàn)這一接口。這允許你獨(dú)立的擴(kuò)展或修改
    兩邊的處理過程,只要確保它們遵守同樣的接口約束
    流量消峰
    主要可以用來抗高并發(fā)的寫入, 防止數(shù)據(jù)庫(kù)因?yàn)楦卟l(fā)寫入宕機(jī)
  23. RabbitMQ的底層架構(gòu)
    Broker:它提供一種傳輸服務(wù),它的角色就是維護(hù)一條從生產(chǎn)者到消費(fèi)者的路線,保證數(shù)據(jù)能按照指定的
    方式進(jìn)行傳輸,
    Exchange:消息交換機(jī),它指定消息按什么規(guī)則,路由到哪個(gè)隊(duì)列。
    Queue:消息的載體,每個(gè)消息都會(huì)被投到一個(gè)或多個(gè)隊(duì)列。
    Binding:綁定,它的作用就是把exchange和queue按照路由規(guī)則綁定起來.
    Routing Key:路由關(guān)鍵字,exchange根據(jù)這個(gè)關(guān)鍵字進(jìn)行消息投遞。
    vhost:虛擬主機(jī),一個(gè)broker里可以有多個(gè)vhost,用作不同用戶的權(quán)限分離。
    Producer:消息生產(chǎn)者,就是投遞消息的程序.
    Consumer:消息消費(fèi)者,就是接受消息的程序.
    Channel:消息通道,在客戶端的每個(gè)連接里,可建立多個(gè)channel.
  24. RabbitMQ如何保證消息的可靠性
    可靠性是保證消息不丟失,分為發(fā)送消息不丟失和消費(fèi)消息不丟失兩種 :
    發(fā)送不丟失有confirm和return機(jī)制
    消費(fèi)不丟失可以用ack手動(dòng)確認(rèn)機(jī)制
  25. RabbitMQ如何保證避免消息重復(fù)消費(fèi)
    讓每個(gè)消息攜帶一個(gè)全局的唯一ID,即可保證消息的冪等性,具體消費(fèi)過程為:
    消費(fèi)者獲取到消息后先根據(jù)id去查詢r(jià)edis是否存在該消息。
    如果不存在,則正常消費(fèi),消費(fèi)完畢后寫入redis。
    如果存在,則證明消息被消費(fèi)過,直接丟棄。
  26. RabbitMQ的死信隊(duì)列
    死信:是RabbitMQ中的一種消息機(jī)制,當(dāng)消息在隊(duì)列的存活時(shí)間超過設(shè)置的TTL時(shí)間或者消息隊(duì)列的消
    息數(shù)量已經(jīng)超過最大隊(duì)列長(zhǎng)度。這樣的消息被認(rèn)為是死亡的信息也就是死信.
    死信消息,會(huì)被RabbitMQ自動(dòng)重新投遞到另一個(gè)交換機(jī)上(Exchange),這個(gè)交換機(jī)往往被稱為
    DLX(dead-letter-exchange)“死信交換機(jī)”,然后交換機(jī)根據(jù)綁定規(guī)則轉(zhuǎn)發(fā)到對(duì)應(yīng)的隊(duì)列上,監(jiān)聽該隊(duì)列
    就可以被重新消費(fèi)。
  27. RabbitMQ如何基于死信隊(duì)列實(shí)現(xiàn)延遲隊(duì)列以及存在的問題
    RabbitMQ中沒有延遲隊(duì)列的功能, 但是可以借助延時(shí)消息, 死信, 死信隊(duì)列來實(shí)現(xiàn)延遲隊(duì)列的功能
    第一. 給隊(duì)列發(fā)送消息給消息設(shè)置一個(gè)超時(shí)時(shí)間, 超過這個(gè)時(shí)間沒有被消費(fèi)掉這個(gè)消息就會(huì)被認(rèn)為是死信,
    這個(gè)隊(duì)列不設(shè)置消費(fèi)方.
    第二. 隊(duì)列中的所有消息, 到達(dá)超時(shí)時(shí)間都會(huì)成為死信, 會(huì)被RabbitMQ發(fā)送到死信交換器
    第三. 死信交換器中的數(shù)據(jù)會(huì)被RabbitMQ發(fā)送到死信隊(duì)列
    第四. 接收方監(jiān)聽器監(jiān)聽死信隊(duì)列. 這樣從里面消費(fèi)的消息都是超時(shí)后的消息, 也就是先了延遲隊(duì)列的功
    能.
  28. Zookeeper的應(yīng)用場(chǎng)景
    可以做為dubbo的注冊(cè)中心
    可以做分布式鎖
    可以為dubbo提供負(fù)載均衡功能
    分布式協(xié)調(diào)/通知
  29. Zookeeper的存儲(chǔ)數(shù)據(jù)的結(jié)構(gòu)
    zookeeper的數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)是一個(gè)DataTree數(shù)據(jù)結(jié)構(gòu)。
    其內(nèi)部是一個(gè)Map<String, DataNode> nodes的數(shù)據(jù)結(jié)構(gòu),其中key是path,DataNode是真正保存數(shù)
    據(jù)的核心數(shù)據(jù)結(jié)構(gòu)。
  30. Zookeeper的節(jié)點(diǎn)的類型
    永久節(jié)點(diǎn) : 無序但是客戶端和zookeeper服務(wù)器斷開連接后不會(huì)被自動(dòng)刪除
    永久有序節(jié)點(diǎn) : 有序, 并且客戶端和zookeeper服務(wù)器斷開連接后不會(huì)被自動(dòng)刪除
    臨時(shí)節(jié)點(diǎn) : 無序, 客戶端和zookeeper服務(wù)器斷開連接后會(huì)被自動(dòng)刪除
    臨時(shí)有序節(jié)點(diǎn) : 有序, 客戶端和zookeeper服務(wù)器斷開連接后會(huì)被自動(dòng)刪除
  31. Zookeeper的集群架構(gòu)
    Zookeeper集群采用選舉機(jī)制, 也就是多臺(tái)zookeeper之間會(huì)互相進(jìn)行投票, 從而選出主機(jī)leader, 其他的
    都是備機(jī)flower.
    主備之間使用心跳檢測(cè)技術(shù), 備機(jī)每隔一段時(shí)間會(huì)ping主機(jī), 主機(jī)返回pong給備機(jī), 認(rèn)為主機(jī)存活. 如果主
    機(jī)不返回pong,則認(rèn)為主機(jī)宕機(jī), 這個(gè)時(shí)候其他備機(jī)會(huì)再次執(zhí)行選舉機(jī)制, 選舉出新的主機(jī)leader來替代老
    主機(jī)工作.
    Zookeeper集群一旦超過半數(shù)機(jī)器宕機(jī), 則整個(gè)集群不提供服務(wù), 將失去作用, 所以建議zookeeper集群服
    務(wù)器數(shù)量為奇數(shù)臺(tái).
  32. Zookeeper如何實(shí)現(xiàn)分布式鎖
    使用zookeeper創(chuàng)建臨時(shí)序列節(jié)點(diǎn)來實(shí)現(xiàn)分布式鎖,適用于順序執(zhí)行的程序,大體思路就是創(chuàng)建臨時(shí)序
    列節(jié)點(diǎn),找出最小的序列節(jié)點(diǎn),獲取分布式鎖,程序執(zhí)行完成之后此序列節(jié)點(diǎn)消失,通過watch來監(jiān)控
    節(jié)點(diǎn)的變化,從剩下的節(jié)點(diǎn)的找到最小的序列節(jié)點(diǎn),獲取分布式鎖,執(zhí)行相應(yīng)處理,依次類推……
  33. 闡述一下你理解的微服務(wù)架構(gòu)
    微服務(wù)架構(gòu)是一種架構(gòu)模式,它提倡將單一應(yīng)用程序劃分成一組小的服務(wù),服務(wù)之間相互協(xié)調(diào)、互相配
    合,為用戶提供最終價(jià)值。每個(gè)服務(wù)運(yùn)行在其獨(dú)立的進(jìn)程中,服務(wù)和服務(wù)之間采用輕量級(jí)的通信機(jī)制相
    互溝通(通常是基于HTTP的Restful API).每個(gè)服務(wù)都圍繞著具體的業(yè)務(wù)進(jìn)行構(gòu)建,并且能夠被獨(dú)立的部
    署到生產(chǎn)環(huán)境、類生產(chǎn)環(huán)境等。另外,應(yīng)盡量避免統(tǒng)一的、集中的服務(wù)管理機(jī)制.這樣實(shí)現(xiàn)了易擴(kuò)展,易維
    護(hù), 松耦合的特點(diǎn).
  34. 闡述一下SpringCloud中常用的組件
    注冊(cè)中心Eureka : 所有微服務(wù)啟動(dòng)后都要注冊(cè)到Eureka中
    遠(yuǎn)程調(diào)用Feign : 底層使用http協(xié)議, 發(fā)送請(qǐng)求給被調(diào)用方, 執(zhí)行后返回結(jié)果
    接口負(fù)載均衡Ribbon : 如果被調(diào)用的微服務(wù)是集群, Ribbion起到了負(fù)載均衡的效果
    服務(wù)網(wǎng)關(guān)Gateway : 所有外部訪問微服務(wù)的請(qǐng)求都要經(jīng)過網(wǎng)關(guān), 網(wǎng)關(guān)根據(jù)訪問的url路徑來轉(zhuǎn)發(fā)請(qǐng)求到具體
    服務(wù).
    配置中心Config : 統(tǒng)一管理所有微服務(wù)的配置文件.
    熔斷器Hystrix : 并發(fā)量超過微服務(wù)可以承受的極限, 可以進(jìn)行熔斷或者降級(jí).
  35. Eureka的工作機(jī)制
    服務(wù)啟動(dòng)后向Eureka注冊(cè),Eureka Server會(huì)將注冊(cè)信息向其他Eureka Server進(jìn)行同步,當(dāng)服務(wù)消費(fèi)者
    要調(diào)用服務(wù)提供者,則向服務(wù)注冊(cè)中心獲取服務(wù)提供者地址,然后會(huì)將服務(wù)提供者地址緩存在本地,下
    次再調(diào)用時(shí),則直接從本地緩存中取,完成一次調(diào)用。
    當(dāng)服務(wù)注冊(cè)中心Eureka Server檢測(cè)到服務(wù)提供者因?yàn)殄礄C(jī)、網(wǎng)絡(luò)原因不可用時(shí),則在服務(wù)注冊(cè)中心將服
    務(wù)置為DOWN狀態(tài),并把當(dāng)前服務(wù)提供者狀態(tài)向訂閱者發(fā)布,訂閱過的服務(wù)消費(fèi)者更新本地緩存。
    服務(wù)提供者在啟動(dòng)后,周期性(默認(rèn)30秒)向Eureka Server發(fā)送心跳,以證明當(dāng)前服務(wù)是可用狀態(tài)。
    Eureka Server在一定的時(shí)間(默認(rèn)90秒)未收到客戶端的心跳,則認(rèn)為服務(wù)宕機(jī),注銷該實(shí)例。
  36. Ribbon如何實(shí)現(xiàn)負(fù)載均衡的
    調(diào)用方微服務(wù)到Eureka中根據(jù)被調(diào)用的服務(wù)名獲取被調(diào)用服務(wù)器地址ip和端口號(hào)列表
    在調(diào)用方根據(jù)返回的地址列表Rbbion默認(rèn)使用輪詢的策略, 分配請(qǐng)求進(jìn)行逐個(gè)調(diào)用
  37. Hystrix的斷路器以及實(shí)現(xiàn)原理
    Hystrix的斷路器實(shí)現(xiàn)原理采用, 馬丁福勒斷路器原理如下:
    一段時(shí)間內(nèi),失敗率達(dá)到一定閾值(比如50%失敗,或者失敗了50次),斷路器打開,此時(shí)不再請(qǐng)求服
    務(wù)提供者,而是只是快速失敗的方法(斷路方法)
    斷路器打開一段時(shí)間,自動(dòng)進(jìn)入“半開”狀態(tài),此時(shí),斷路器可允許一個(gè)請(qǐng)求方法服務(wù)提供者,如果請(qǐng)求
    調(diào)用成功,則關(guān)閉斷路器,否則繼續(xù)保持?jǐn)嗦菲鞔蜷_狀態(tài)。
    斷路器hystrix是保證了局部發(fā)生的錯(cuò)誤,不會(huì)擴(kuò)展到整個(gè)系統(tǒng),從而保證系統(tǒng)的即使出現(xiàn)局部問題也不
    會(huì)造成系統(tǒng)雪崩。
  38. Eureka和Zookeeper實(shí)現(xiàn)注冊(cè)中心的區(qū)別
    Zookeeper保證的是CP(一致性和分區(qū)容錯(cuò)性)
    zookeeper對(duì)一致性的要求要高于可用性。
    Eureka保證的是AP(可用性和分區(qū)容錯(cuò)性)
    Eureka看明白了這一點(diǎn), 因此在設(shè)計(jì)時(shí)就優(yōu)先保證可用性。Eureka各個(gè)節(jié)點(diǎn)都是平等的,幾個(gè)節(jié)點(diǎn)掛掉
    不會(huì)影響正常節(jié)點(diǎn)的工作,剩余的節(jié)點(diǎn)依然可以提供注冊(cè)和查詢服務(wù)。而Eureka的客戶端在向某個(gè)
    Eureka注冊(cè)時(shí),如果發(fā)現(xiàn)連接失敗,則會(huì)自動(dòng)切換至其他節(jié)點(diǎn),只要有一臺(tái)Eureka還在, 就能保住注冊(cè)
    服務(wù)的可用性,只不過查到的信息可能不是最新的
  39. 分布式項(xiàng)目中如何解決分布式事務(wù)的問題
    首先盡量不要使用分布式事務(wù), 因?yàn)闀?huì)降低代碼執(zhí)行效率, 盡量保證業(yè)務(wù)的原子性和冪等性, 不使用分布式
    事務(wù)最好.
    某些業(yè)務(wù)必須用, 則可以使用分布式事務(wù)框架LCN或者阿里的Seata解決
  40. 闡述一下SpringCloud Alibaba中常用的組件
    Nacos(配置中心 + 注冊(cè)中心)
    Nacos實(shí)現(xiàn)了服務(wù)的配置中心與服務(wù)注冊(cè)發(fā)現(xiàn)的功能,Nacos可以通過可視化的配置降低相關(guān)的學(xué)
    習(xí)與維護(hù)成本,實(shí)現(xiàn)動(dòng)態(tài)的配置管理與分環(huán)境的配置中心控制。 同時(shí)Nacos提供了基于http/RCP的
    服務(wù)注冊(cè)與發(fā)現(xiàn)功能
    Sentinel (分布式流控)
    Sentinel是面向分布式微服務(wù)架構(gòu)的輕量級(jí)高可用的流控組件,以流量作為切入點(diǎn),從流量控制,
    熔斷降級(jí),系統(tǒng)負(fù)載保護(hù)等維度幫助用戶保證服務(wù)的穩(wěn)定性。常用與實(shí)現(xiàn)限流、熔斷降級(jí)等策略
    Dubbo (遠(yuǎn)程過程調(diào)用)
    Dubbo已經(jīng)在圈內(nèi)很火了,SpringCloud Alibaba基于上面提到的Nacos服務(wù)注冊(cè)中心也同樣整合了
    Dubbo。
    RocketMQ (消息隊(duì)列)
    RocketMQ基于Java的高性能、高吞吐量的消息隊(duì)列,在SpringCloud Alibaba生態(tài)用于實(shí)現(xiàn)消息驅(qū)
    動(dòng)的業(yè)務(wù)開發(fā),常見的消息隊(duì)列有Kafka、RocketMQ、RabbitMQ等
    Seata (分布式事物)
    既然是微服務(wù)的產(chǎn)品,那么肯定會(huì)用到分布式事物。Seata就是阿里巴巴開源的一個(gè)高性能分布式
    事物的解決方案。
  41. zuul和gateway區(qū)別?
    目前zuul已經(jīng)被gateway取代
    Gateway比zuul功能更加強(qiáng)大, gateway內(nèi)部實(shí)現(xiàn)了限流, 負(fù)載均衡等,但是也限制了僅適用于
    SpringCould套件, zuul在其他微服務(wù)架構(gòu)下也可以使用, 但是內(nèi)部沒有實(shí)現(xiàn)限流, 負(fù)載均衡等功能
    Zuul僅支持同步, gateway支持異步, 所以gateway性能更好
  42. springCloud和Dubbo區(qū)別?
    沒有可比性, dubbo只是底層使用了RPC遠(yuǎn)程過程調(diào)用規(guī)范的一個(gè)遠(yuǎn)程調(diào)用技術(shù). 而SpringCloud框架集
    里面有很多子項(xiàng)目, SpringCloud中有注冊(cè)中心, 配置中心, 遠(yuǎn)程調(diào)用, 接口間負(fù)載均衡, 熔斷器, 網(wǎng)關(guān)等, 可
    以對(duì)服務(wù)進(jìn)行監(jiān)控, 治理, 配置等有著全套解決方案.
  43. 分布式事務(wù)和分布式任務(wù)如何實(shí)現(xiàn)?
    分布式事務(wù)遵循CAP定理, 可以使用2pc兩階段提交, 或者TCC基于補(bǔ)償機(jī)制實(shí)現(xiàn), 又或者可以使用基于消
    息最終一致性解決方案等.
    具體使用起來也可以使用LCN或者阿里巴巴的Seata框架實(shí)現(xiàn)
    分布式任務(wù)可以使用當(dāng)當(dāng)網(wǎng)的ElasticJob分布式任務(wù)框架實(shí)現(xiàn)
  44. redis與mysql怎么保證數(shù)據(jù)的一致?
    采用延時(shí)雙刪策略:
    先刪除緩存;
    再寫數(shù)據(jù)庫(kù);
    休眠500毫秒(根據(jù)具體的業(yè)務(wù)時(shí)間來定);
    再次刪除緩存。
    那么,這個(gè)500毫秒怎么確定的,具體該休眠多久呢?
    需要評(píng)估自己的項(xiàng)目的讀數(shù)據(jù)業(yè)務(wù)邏輯的耗時(shí)。這么做的目的,就是確保讀請(qǐng)求結(jié)束,寫請(qǐng)求可以
    刪除讀請(qǐng)求造成的緩存臟數(shù)據(jù)。
    當(dāng)然,這種策略還要考慮 redis 和數(shù)據(jù)庫(kù)主從同步的耗時(shí)。最后的寫數(shù)據(jù)的休眠時(shí)間:則在讀數(shù)據(jù)
    業(yè)務(wù)邏輯的耗時(shí)的基礎(chǔ)上,加上幾百ms即可。比如:休眠1秒。
    雙刪失敗如何處理?
    設(shè)置緩存數(shù)據(jù)的過期時(shí)間
  45. 延遲刪除是怎么解決數(shù)據(jù)一致性
    延時(shí)雙刪的方案思路是,為了避免更新數(shù)據(jù)庫(kù)的時(shí)候,其他線程從緩存中讀取不到數(shù)據(jù),就在更新完數(shù)
    據(jù)庫(kù)之后,在sleep一段時(shí)間,然后再刪除緩存。
    sleep的時(shí)間要對(duì)業(yè)務(wù)讀寫緩存的時(shí)間做出評(píng)估,sleep時(shí)間大于讀寫緩存的時(shí)間即可。
  46. 什么是跨域問題? SpringBoot如何解決跨域問題?
    跨域問題:
    瀏覽器廠商在生產(chǎn)瀏覽器的時(shí)候, 瀏覽器內(nèi)部已經(jīng)內(nèi)置了同源策略, 也就是要求當(dāng)前頁(yè)面所在的url地
    址和發(fā)送請(qǐng)求目標(biāo)的url地址中, 協(xié)議, 域名, 端口號(hào)不可以有變化, 任意一項(xiàng)發(fā)生改變, 服務(wù)器雖然可
    以接收請(qǐng)求返回響應(yīng), 但是瀏覽器認(rèn)為不安全, 不接受響應(yīng)的數(shù)據(jù). 這就是跨域問題.
    解決方案:
    SpringMvc已經(jīng)內(nèi)置了跨域解決方案, 在controller類上加入@CrossOrigin注解就可以解決
    底層原理就是在響應(yīng)頭中加入Access-Control-Allow-Origin: * 設(shè)置
  47. Zookeeper 集群節(jié)點(diǎn)為什么要部署成奇數(shù)
    Zookeeper集群中只要有超過半數(shù)機(jī)器不工作,那么整個(gè)集群都是不可用的. 當(dāng)宕掉幾個(gè)zookeeper節(jié)點(diǎn)
    服務(wù)器之后,剩下的個(gè)數(shù)必須大于宕掉的個(gè)數(shù),也就是剩下的節(jié)點(diǎn)服務(wù)數(shù)必須大于n/2,這樣zookeeper
    集群才可以繼續(xù)使用,無論奇偶數(shù)都可以選舉leader。例如 : 5臺(tái)zookeeper節(jié)點(diǎn)機(jī)器最多宕掉2臺(tái),還
    可以繼續(xù)使用,因?yàn)槭O?臺(tái)大于5/2。至于為什么最好為奇數(shù)個(gè)節(jié)點(diǎn)?這樣是為了以最大容錯(cuò)服務(wù)器個(gè)
    數(shù)的條件下,能節(jié)省資源。比如,最大容錯(cuò)為2的情況下,對(duì)應(yīng)的zookeeper服務(wù)數(shù),奇數(shù)為5,而偶數(shù)
    為6,也就是6個(gè)zookeeper服務(wù)的情況下最多能宕掉2個(gè)服務(wù),所以從節(jié)約資源的角度看,沒必要部署
    6(偶數(shù))個(gè)zookeeper服務(wù)節(jié)點(diǎn)
  48. Zookeeper腦裂問題和解決方案?
    什么是腦裂:
    腦裂(Split-Brain) 就是比如當(dāng)你的集群里面有3個(gè)節(jié)點(diǎn),它們都知道在這個(gè) cluster 里需要選舉出一
    個(gè) master。那么當(dāng)它們3個(gè)之間的通信完全沒有問題的時(shí)候,就會(huì)達(dá)成共識(shí),選出其中一個(gè)作為
    master。但是如果它們之間的通信出了問題,其中一個(gè)節(jié)點(diǎn)網(wǎng)絡(luò)抖動(dòng)斷開好長(zhǎng)時(shí)間, 那么剩下的兩
    個(gè)結(jié)點(diǎn)都會(huì)覺得現(xiàn)在沒有 master,所以又會(huì)選舉出一個(gè) master,當(dāng)網(wǎng)絡(luò)恢復(fù)后集群里面就會(huì)有兩
    個(gè) master。兩個(gè)master都會(huì)爭(zhēng)搶資源, 集群就會(huì)混亂出現(xiàn)問題.
    解決Split-Brain腦裂的問題方案:
    法定人數(shù)方式 : 比如3個(gè)節(jié)點(diǎn)的集群,集群可以容忍1個(gè)節(jié)點(diǎn)失效,這時(shí)候還能選舉出1個(gè)
    lead,集群還可用。這是zookeeper防止"腦裂"默認(rèn)采用的方法。
    采用Redundant communications (冗余通信)方式:集群中采用多種通信方式,防止一種通
    信方式失效導(dǎo)致集群中的節(jié)點(diǎn)無法通信。
    Fencing (共享資源) 方式:比如能看到共享資源就表示在集群中,能夠獲得共享資源的鎖的就
    是Leader,看不到共享資源的,就不在集群中。
  49. 什么是冪等性(Idempotence)及用在那里?
    冪等性是能夠以同樣的方式做兩次,而最終結(jié)果將保持不變,就好像它只做了一次的特性。
    用法:在遠(yuǎn)程服務(wù)或數(shù)據(jù)源中使用冪等性,以便當(dāng)它多次接收指令時(shí),只處理一次。
  50. 什么是熔斷?什么是服務(wù)降級(jí)?
    熔斷
    服務(wù)熔斷的作用類似于我們家用的保險(xiǎn)絲,當(dāng)某服務(wù)出現(xiàn)不可用或響應(yīng)超時(shí)的情況時(shí),為了防止整
    個(gè)系統(tǒng)出現(xiàn)雪崩,暫時(shí)停止對(duì)該服務(wù)的調(diào)用。
    降級(jí)
    服務(wù)降級(jí)是從整個(gè)系統(tǒng)的負(fù)荷情況出發(fā)和考慮的,對(duì)某些負(fù)荷會(huì)比較高的情況,為了預(yù)防某些功能
    (業(yè)務(wù)場(chǎng)景)出現(xiàn)負(fù)荷過載或者響應(yīng)慢的情況,在其內(nèi)部暫時(shí)舍棄對(duì)一些非核心的接口和數(shù)據(jù)的請(qǐng)
    求,而直接返回一個(gè)提前準(zhǔn)備好的fallback(退路)錯(cuò)誤處理信息。這樣,雖然提供的是一個(gè)有損
    的服務(wù),但卻保證了整個(gè)系統(tǒng)的穩(wěn)定性和可用性。
  51. dubbo支持的協(xié)議有哪些
    支持 : dubbo協(xié)議, rmi協(xié)議, hessian協(xié)議, http協(xié)議, webservice協(xié)議, thrift協(xié)議, memcached協(xié)議,
    redis協(xié)議
    dubbo協(xié)議(默認(rèn))
    連接個(gè)數(shù):單連接
    連接方式:長(zhǎng)連接
    傳輸協(xié)議:TCP
    傳輸方式:NIO 異步傳輸
    序列化:Hessian 二進(jìn)制序列化
    適用范圍:傳入傳出參數(shù)數(shù)據(jù)包較小(建議小于100K),消費(fèi)者比提供者個(gè)數(shù)多,單一消費(fèi)
    者無法壓滿提供者,盡量不要用 dubbo 協(xié)議傳輸大文件或超大字符串。
    適用場(chǎng)景:常規(guī)遠(yuǎn)程服務(wù)方法調(diào)用
    rmi協(xié)議
    連接個(gè)數(shù):多連接
    連接方式:短連接
    傳輸協(xié)議:TCP
    傳輸方式:同步傳輸
    序列化:Java 標(biāo)準(zhǔn)二進(jìn)制序列化
    適用范圍:傳入傳出參數(shù)數(shù)據(jù)包大小混合,消費(fèi)者與提供者個(gè)數(shù)差不多,可傳文件。
    適用場(chǎng)景:常規(guī)遠(yuǎn)程服務(wù)方法調(diào)用,與原生RMI服務(wù)互操作
    hessian協(xié)議
    連接個(gè)數(shù):多連接
    連接方式:短連接
    傳輸協(xié)議:HTTP
    傳輸方式:同步傳輸
    序列化:Hessian二進(jìn)制序列化
    適用范圍:傳入傳出參數(shù)數(shù)據(jù)包較大,提供者比消費(fèi)者個(gè)數(shù)多,提供者壓力較大,可傳文件。
    適用場(chǎng)景:頁(yè)面?zhèn)鬏?#xff0c;文件傳輸,或與原生hessian服務(wù)互操作
    http協(xié)議
    連接個(gè)數(shù):多連接
    連接方式:短連接
    傳輸協(xié)議:HTTP
    傳輸方式:同步傳輸
    序列化:表單序列化
    適用范圍:傳入傳出參數(shù)數(shù)據(jù)包大小混合,提供者比消費(fèi)者個(gè)數(shù)多,可用瀏覽器查看,可用表
    單或URL傳入?yún)?shù),暫不支持傳文件。
    適用場(chǎng)景:需同時(shí)給應(yīng)用程序和瀏覽器 JS 使用的服務(wù)。
    WebService協(xié)議
    連接個(gè)數(shù):多連接
    連接方式:短連接
    傳輸協(xié)議:HTTP
    傳輸方式:同步傳輸
    序列化:SOAP 文本序列化
    適用場(chǎng)景:系統(tǒng)集成,跨語(yǔ)言調(diào)用
  52. dubbo的連接方式有幾種
    無注冊(cè)中心, 直接連接
    在開發(fā)階段, 服務(wù)提供方?jīng)]有必要部署集群, 所以采用服務(wù)調(diào)用方直接連接服務(wù)提供方更方便測(cè)試與
    開發(fā)
    采用Zookeeper作為注冊(cè)中心連接
    在線上部署階段使用, 對(duì)于某些并發(fā)訪問壓力大的服務(wù)器節(jié)點(diǎn)可以部署集群, 這時(shí)dubbo的服務(wù)提
    供方服務(wù)器集群可以使用zookeeper來管理.
    分組連接
    當(dāng)一個(gè)接口有多種實(shí)現(xiàn)時(shí),可以用 group 區(qū)分。
  53. dubbo的負(fù)載均衡策略有哪些
    Random LoadBalance 隨機(jī), 按權(quán)重設(shè)置隨機(jī)概率(默認(rèn))
    RoundRobin LoadBalance 輪詢, 按權(quán)重設(shè)置輪詢比率
    LeastActive LoadBalance 最少活躍調(diào)用數(shù), 相同活躍數(shù)的隨機(jī)
    ConsistentHash LoadBalance 一致性Hash, 相同參數(shù)的請(qǐng)求總是發(fā)到同一提供者
  54. dubbo的序列化有哪些, 推薦哪種
    Hessian 序列化:是修改過的 hessian lite,默認(rèn)啟用, 推薦使用.
    json 序列化:使用 FastJson 庫(kù)
    java 序列化:JDK 提供的序列化,性能不理想
    dubbo 序列化:未成熟的高效 java 序列化實(shí)現(xiàn),不建議在生產(chǎn)環(huán)境使用

十、設(shè)計(jì)模式面試 【2道】

  1. 談一談你了解的設(shè)計(jì)模式有哪些?
    大致按照模式的應(yīng)用目標(biāo)分類,設(shè)計(jì)模式可以分為創(chuàng)建型模式、結(jié)構(gòu)型模式和行為型模式。
    創(chuàng)建型模式 : 是對(duì)對(duì)象創(chuàng)建過程的各種問題和解決方案的總結(jié),包括各種工廠模式(Factory、Abstract
    Factory)、單例模式(Singleton)、構(gòu)建器模式(Builder)、原型模式(ProtoType)。
    結(jié)構(gòu)型模式 : 是針對(duì)軟件設(shè)計(jì)結(jié)構(gòu)的總結(jié),關(guān)注于類、對(duì)象繼承、組合方式的實(shí)踐經(jīng)驗(yàn)。常見的結(jié)構(gòu)型
    模式,包括橋接模式(Bridge)、適配器模式(Adapter)、裝飾者模式(Decorator)、代理模式
    (Proxy)、組合模式(Composite)、外觀模式(Facade)、享元模式(Flyweight)等。
    行為型模式 : 是從類或?qū)ο笾g交互、職責(zé)劃分等角度總結(jié)的模式。比較常見的行為型模式有策略模式
    (Strategy)、解釋器模式(Interpreter)、命令模式(Command)、觀察者模式(Observer)、迭
    代器模式(Iterator)、模板方法模式(Template Method)、訪問者模式(Visitor)
  2. 設(shè)計(jì)模式開發(fā)中的應(yīng)用!
    單例模式: 例如: 配置類config的對(duì)象只能有一個(gè)
    工廠模式: 例如: 使用BeanFactory工廠創(chuàng)建對(duì)象, 不用自己去new對(duì)象
    代理模式: 例如: spring中的aop底層實(shí)現(xiàn)就是動(dòng)態(tài)代理
    適配器模式: 例如: SpringMvc中的HandlerInterceptorAdapter就是適配器模式
    建造者模式: 例如: mybatis中的SqlsessionFactoryBuilder就是建造者模式, 遵循了單一職責(zé)原則, 只做一
    件事.

十一、 數(shù)據(jù)結(jié)構(gòu) 【19道】

  1. 什么是空間和時(shí)間復(fù)雜度?
    時(shí)間復(fù)雜度 :
    (1)時(shí)間頻度 一個(gè)算法執(zhí)行所耗費(fèi)的時(shí)間,從理論上是不能算出來的,必須上機(jī)運(yùn)行測(cè)試才能知道。
    但我們不可能也沒有必要對(duì)每個(gè)算法都上機(jī)測(cè)試,只需知道哪個(gè)算法花費(fèi)的時(shí)間多,哪個(gè)算法花費(fèi)的時(shí)
    間少就可以了。并且一個(gè)算法花費(fèi)的時(shí)間與算法中語(yǔ)句的執(zhí)行次數(shù)成正比例,哪個(gè)算法中語(yǔ)句執(zhí)行次數(shù)
    多,它花費(fèi)時(shí)間就多。一個(gè)算法中的語(yǔ)句執(zhí)行次數(shù)稱為語(yǔ)句頻度或時(shí)間頻度。記為T(n)。
    (2)時(shí)間復(fù)雜度在剛才提到的時(shí)間頻度中,n稱為問題的規(guī)模,當(dāng)n不斷變化時(shí),時(shí)間頻度T(n)也會(huì)不斷
    變化。但有時(shí)我們想知道它變化時(shí)呈現(xiàn)什么規(guī)律。為此,我們引入時(shí)間復(fù)雜度概念。 一般情況下,算法
    中基本操作重復(fù)執(zhí)行的次數(shù)是問題規(guī)模n的某個(gè)函數(shù),用T(n)表示,若有某個(gè)輔助函數(shù)f(n),使得當(dāng)n趨近
    于無窮大時(shí),T(n)/f(n)的極限值為不等于零的常數(shù),則稱f(n)是T(n)的同數(shù)量級(jí)函數(shù)。記作T(n)=O(f(n)),
    稱O(f(n)) 為算法的漸進(jìn)時(shí)間復(fù)雜度,簡(jiǎn)稱時(shí)間復(fù)雜度。
    空間復(fù)雜度 :
    一個(gè)程序的空間復(fù)雜度是指運(yùn)行完一個(gè)程序所需內(nèi)存的大小。利用程序的空間復(fù)雜度,可以對(duì)程序的運(yùn)
    行所需要的內(nèi)存多少有個(gè)預(yù)先估計(jì)。一個(gè)程序執(zhí)行時(shí)除了需要存儲(chǔ)空間和存儲(chǔ)本身所使用的指令、常
    數(shù)、變量和輸入數(shù)據(jù)外,還需要一些對(duì)數(shù)據(jù)進(jìn)行操作的工作單元和存儲(chǔ)一些為現(xiàn)實(shí)計(jì)算所需信息的輔助
    空間。程序執(zhí)行時(shí)所需存儲(chǔ)空間包括以下兩部分。
    (1)固定部分。這部分空間的大小與輸入/輸出的數(shù)據(jù)的個(gè)數(shù)多少、數(shù)值無關(guān)。主要包括指令空間(即
    代碼空間)、數(shù)據(jù)空間(常量、簡(jiǎn)單變量)等所占的空間。這部分屬于靜態(tài)空間。
    (2)可變空間,這部分空間的主要包括動(dòng)態(tài)分配的空間,以及遞歸棧所需的空間等。這部分的空間大小
    與算法有關(guān)。
    一個(gè)算法所需的存儲(chǔ)空間用f(n)表示。S(n)=O(f(n)) 其中n為問題的規(guī)模,S(n)表示空間復(fù)雜度。
  2. 常見的數(shù)據(jù)結(jié)構(gòu)有哪些?
    數(shù)組, 鏈表, 隊(duì)列, 堆, 棧, 樹, 散列表, 圖
  3. 鏈表的數(shù)據(jù)結(jié)構(gòu)的特點(diǎn)
    鏈表使用不連續(xù)內(nèi)存空間, 空間利用率高
    鏈表插入刪除效率高, 查詢修改效率慢
    鏈表占用空間大小不固定, 可以擴(kuò)展
  4. 棧數(shù)據(jù)結(jié)構(gòu)的特點(diǎn)
    棧是一種操作受限的線性表,只允許從一端插入和刪除數(shù)據(jù)。擁有后進(jìn)先出的特點(diǎn)
    棧的插入和刪除只能在一個(gè)位置上進(jìn)行的表,棧只有進(jìn)棧、出棧兩種操作。前者相當(dāng)于插入,后者相當(dāng)
    于刪除最后的元素。
    從底層看,棧就是CPU寄存器里的某個(gè)指針?biāo)赶虻囊黄瑑?nèi)存區(qū)域
  5. 隊(duì)列數(shù)據(jù)結(jié)構(gòu)的特點(diǎn)
    隊(duì)列也是一種操作受限的數(shù)據(jù)結(jié)構(gòu),只能從隊(duì)尾的一端進(jìn)行插入,隊(duì)頭的一端進(jìn)行刪除。先進(jìn)先出
    FIFO。雙端隊(duì)列不受這種限制,兩端都能進(jìn)行插入和刪除。
  6. 說一說什么是跳表?Redis為什么用跳表實(shí)現(xiàn)有序集合?
    Redis中的有序集合是通過跳表來實(shí)現(xiàn)的,還用到了散列表,它支持的核心操作有:插入一個(gè)數(shù)據(jù)、刪除
    一個(gè)數(shù)據(jù)、查找一個(gè)數(shù)據(jù)、按照區(qū)間查找數(shù)據(jù)、迭代輸出有序序列。
    按照區(qū)間來查找數(shù)據(jù),這個(gè)操作紅黑樹的效率沒有跳表高,其他幾個(gè)操作紅黑樹都可以完成,時(shí)間復(fù)雜
    度都一樣。按照區(qū)間來查找,跳表可以做到O(logn)的時(shí)間復(fù)雜度定位區(qū)間的起點(diǎn),然后在原始鏈表中的
    順序往后遍歷即可,非常高效。
    跳表使用空間換時(shí)間,通過構(gòu)建多級(jí)索引來提高查詢的效率,實(shí)現(xiàn)基于鏈表的二分查找,跳表是一個(gè)動(dòng)
    態(tài)數(shù)據(jù)結(jié)構(gòu),支持快速的插入、刪除、查找操作,時(shí)間復(fù)雜度都是O(logn)。
    跳表的空間復(fù)雜度是O(n),通過改變索引構(gòu)建策略
  7. 散列表的數(shù)據(jù)結(jié)構(gòu)特點(diǎn)
    哈希表的查找效率主要取決于構(gòu)造哈希表時(shí)選取的哈希函數(shù)和處理沖突的方法。
    在各種查找方法中,平均査找長(zhǎng)度與結(jié)點(diǎn)個(gè)數(shù)n無關(guān)的查找方法是哈希表查找法。
    哈希函數(shù)取值是否均勻是評(píng)價(jià)哈希函數(shù)好壞的標(biāo)準(zhǔn)。
    哈希存儲(chǔ)方法只能存儲(chǔ)數(shù)據(jù)元素的值,不能存儲(chǔ)數(shù)據(jù)元素之間的關(guān)系。
  8. 二叉樹數(shù)據(jù)數(shù)據(jù)結(jié)構(gòu)特點(diǎn)
    每個(gè)結(jié)點(diǎn)最多有兩棵子樹,所以二叉樹中不存在度大于2的結(jié)點(diǎn)。注意不是只有兩棵子樹,而是最多有。
    沒有子樹或者有一棵子樹都是可以的。
    左子樹和右子樹是有順序的,次序不能任意顛倒
    即使樹中某結(jié)點(diǎn)只有一棵子樹,也要區(qū)分它是左子樹還是右子樹。
  9. 圖數(shù)據(jù)結(jié)構(gòu)特點(diǎn)
    無向圖 : 每個(gè)節(jié)點(diǎn)都沒有方向,邊上可能有權(quán)重
    有向圖 : 每個(gè)節(jié)點(diǎn)是有方向的的
    有向無環(huán)圖 : 可以描述任務(wù)之間的關(guān)系
  10. 堆數(shù)據(jù)結(jié)構(gòu)特點(diǎn)
    將根節(jié)點(diǎn)最大的堆叫大頂堆或者大根堆,根節(jié)點(diǎn)最小的堆叫小頂堆或小根堆。
    常見的堆有二叉堆,斐波拉契堆。
    如果是大頂堆,常見操作及時(shí)間復(fù)雜度:
    查找最大值:o(1)
    刪除最大值:o(logn)
    添加值:o(1)或o(logn)
  11. 大頂堆和小頂堆的區(qū)別?
    大頂堆 : 根結(jié)點(diǎn)(亦稱為堆頂)的關(guān)鍵字是堆里所有結(jié)點(diǎn)關(guān)鍵字中最大者,稱為大頂堆。大根堆要求根
    節(jié)點(diǎn)的關(guān)鍵字既大于或等于左子樹的關(guān)鍵字值,又大于或等于右子樹的關(guān)鍵字值。
    小頂堆 : 根結(jié)點(diǎn)(亦稱為堆頂)的關(guān)鍵字是堆里所有結(jié)點(diǎn)關(guān)鍵字中最小者,稱為小頂堆。小根堆要求根
    節(jié)點(diǎn)的關(guān)鍵字既小于或等于左子樹的關(guān)鍵字值,又小于或等于右子樹的關(guān)鍵字值。
  12. 說一說常見的排序算法和對(duì)應(yīng)的時(shí)間復(fù)雜度
  13. 用Java代碼實(shí)現(xiàn)冒泡排序和快速排序
package 冒泡排序;
import java.util.Arrays;
/**
* 冒泡排序
* @author mmz
*/
public class BubbleSort {
public static void BubbleSort(int[] arr) {
int temp;//定義一個(gè)臨時(shí)變量
for(int i=0;i<arr.length-1;i++){//冒泡趟數(shù)
for(int j=0;j<arr.length-i-1;j++){
if(arr[j+1]<arr[j]){
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
public static void main(String[] args) {
int arr[] = new int[]{1,6,2,2,5};
BubbleSort.BubbleSort(arr);
System.out.println(Arrays.toString(arr));
}
}
// 快速排序
public class QuickSort{
public static void quickSort(int[] arr,int low,int high){
int i,j,temp,t;
if(low>high){
return;
}
i=low;
j=high;
//temp就是基準(zhǔn)位
temp = arr[low];
while (i<j) {
//先看右邊,依次往左遞減
while (temp<=arr[j]&&i<j) {
j--;
}
//再看左邊,依次往右遞增
while (temp>=arr[i]&&i<j) {
i++;
}
//如果滿足條件則交換
if (i<j) {
t = arr[j];
arr[j] = arr[i];
arr[i] = t;
}
}
//最后將基準(zhǔn)為與i和j相等位置的數(shù)字交換
arr[low] = arr[i];
arr[i] = temp;
//遞歸調(diào)用左半數(shù)組
quickSort(arr, low, j-1);
//遞歸調(diào)用右半數(shù)組
quickSort(arr, j+1, high);
}
public static void main(String[] args){
int[] arr = {10,7,2,4,7,62,3,4,2,1,8,9,19};
quickSort(arr, 0, arr.length-1);
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
  1. 100萬(wàn)用戶如何根據(jù)年齡排序?
    可以通過桶排序,基數(shù)排序,計(jì)數(shù)排序
    桶排序:桶排序要把數(shù)據(jù)進(jìn)行劃分到m個(gè)桶內(nèi),希望的是桶內(nèi)數(shù)據(jù)是均勻的,并且桶與桶之間有著天然
    的大小順序。極端情況下時(shí)間復(fù)雜度會(huì)退化為O(nlog n); 比較適合外部排序。在進(jìn)行劃分桶數(shù)據(jù)的時(shí)
    候,可能存在桶數(shù)據(jù)不均勻的情況,可以選擇在多的數(shù)據(jù)桶進(jìn)行繼續(xù)劃分桶,直到桶數(shù)據(jù)可以加載到內(nèi)
    存中為止。
    計(jì)數(shù)排序:把一系列的數(shù)字統(tǒng)計(jì)個(gè)數(shù)放在數(shù)組內(nèi)A。 依次累加,統(tǒng)計(jì)結(jié)果還是在同一個(gè)數(shù)組中存放A。
    臨時(shí)數(shù)組C存放排序后的結(jié)果。 遍歷最初時(shí)的數(shù)據(jù)B,從A中找到該值。 A數(shù)組中的值-1就是數(shù)據(jù)B在臨時(shí)
    數(shù)組C存放的位置。 把A數(shù)組中的值減1. 循環(huán)這個(gè)過程。該計(jì)數(shù)規(guī)則只適合數(shù)據(jù)范圍不大的情景
  2. 深度優(yōu)先和廣度優(yōu)先搜索算法?
    廣度優(yōu)先搜索(Breadth-First-Search),一般簡(jiǎn)稱為 BFS。直觀地講,它其實(shí)就是一種地毯式層層推進(jìn)
    的搜索策略,即先查找離起始頂點(diǎn)最近的,然后是次近的,依次往外搜索。
    visited,布爾數(shù)組,記錄頂點(diǎn)是否已經(jīng)被訪問過,訪問過則為真,沒有訪問過則為假,這里用 0 和 1 表
    示。
    vertex,記錄上一層的頂點(diǎn),也即已經(jīng)被訪問但其相連的頂點(diǎn)還沒有被訪問的頂點(diǎn)。當(dāng)一層的頂點(diǎn)搜索
    完成后,我們還需要通過這一層的頂點(diǎn)來遍歷與其相連的下一層頂點(diǎn),這里我們用隊(duì)列來記錄上一層的
    頂點(diǎn)。
    prev,記錄搜索路徑,保存的是當(dāng)前頂點(diǎn)是從哪個(gè)頂點(diǎn)遍歷過來的,比如 prev[4] = 1,說明頂點(diǎn) 4 是通
    過頂點(diǎn) 1 而被訪問到的。
    深度優(yōu)先搜索(Depth-First-Search),簡(jiǎn)稱 DFS,最直觀的例子就是走迷宮。
    假設(shè)你站在迷宮的某個(gè)分岔路口,你想找到出口。你隨意選擇一個(gè)岔路口來走,走著走著發(fā)現(xiàn)走不通的
    時(shí)候就原路返回到上一個(gè)分岔路口,再選擇另一條路繼續(xù)走,直到找到出口,這種走法就是深度優(yōu)先搜
    索的策略。
    深度優(yōu)先搜索用的是一種比較著名的思想——回溯思想,這種思想非常適合用遞歸來實(shí)現(xiàn)。深度優(yōu)先搜
    索的代碼里面有幾個(gè)和廣度優(yōu)先搜索一樣的部分 visited、prev 和 Print() 函數(shù),它們的作用也都是一樣
    的。此外,還有一個(gè)特殊的 found 變量,標(biāo)記是否找到終止頂點(diǎn),找到之后我們就可以停止遞歸不用再
    繼續(xù)查找了。
  3. 如何快速獲取Top10熱門搜索關(guān)鍵詞?
    使用優(yōu)先級(jí)隊(duì)列實(shí)現(xiàn) : 優(yōu)先級(jí)隊(duì)列,顧名思義,它首先應(yīng)該是一個(gè)隊(duì)列。隊(duì)列最大的特性就是先進(jìn)先
    出。不過,在優(yōu)先級(jí)隊(duì)列中,數(shù)據(jù)的出隊(duì)順序不是先進(jìn)先出,而是按照優(yōu)先級(jí)來,優(yōu)先級(jí)最高的,最先
    出隊(duì)
  4. 單向鏈表反轉(zhuǎn)如何實(shí)現(xiàn)!
    ①.迭代反轉(zhuǎn)鏈表:從當(dāng)前鏈表的首元節(jié)點(diǎn)開始,一直遍歷至鏈表的最后一個(gè)節(jié)點(diǎn),這期間會(huì)逐個(gè)改變所遍歷到
    的節(jié)點(diǎn)的指針域,另其指向前一個(gè)節(jié)點(diǎn)。
public static Node reverse2(Node head) {
if (head == null || head.getNext() == null) {
return head;
}
// 上一結(jié)點(diǎn)等于頭節(jié)點(diǎn)
Node pre = head;
// 當(dāng)前結(jié)點(diǎn)
Node cur = head.getNext();
// 臨時(shí)結(jié)點(diǎn),用于保存當(dāng)前結(jié)點(diǎn)的指針域(即下一結(jié)點(diǎn))
Node tmp;
// 當(dāng)前結(jié)點(diǎn)為null,說明位于尾結(jié)點(diǎn)
while (cur != null) {
//臨時(shí)節(jié)點(diǎn), 保存當(dāng)前節(jié)點(diǎn)下一個(gè)節(jié)點(diǎn)
tmp = cur.getNext();
// 反轉(zhuǎn)指針域的指向
cur.setNext(pre);
// 指針往下移動(dòng)
pre = cur;
cur = tmp;
}
// 最后將原鏈表的頭節(jié)點(diǎn)的指針域置為null,還回新鏈表的頭結(jié)點(diǎn),即原鏈表的尾結(jié)點(diǎn)
head.setNext(null);
return pre;
}

②.遞歸反轉(zhuǎn)鏈表:從鏈表的尾節(jié)點(diǎn)開始,依次向前遍歷,遍歷過程依次改變各節(jié)點(diǎn)的指向,即另其指向前一個(gè)
節(jié)點(diǎn)。

public static Node Reverse1(Node head) {
// head看作是前一結(jié)點(diǎn),head.getNext()是當(dāng)前結(jié)點(diǎn),reHead是反轉(zhuǎn)后新鏈表的頭結(jié)點(diǎn)
if (head == null || head.getNext() == null) {
// 若為空鏈或者當(dāng)前結(jié)點(diǎn)在尾結(jié)點(diǎn),則直接還回
return head;
}
// 先反轉(zhuǎn)后續(xù)節(jié)點(diǎn)head.getNext()
Node reHead = Reverse1(head.getNext());
// 將當(dāng)前結(jié)點(diǎn)的指針域指向前一結(jié)點(diǎn)
head.getNext().setNext(head);
// 前一結(jié)點(diǎn)的指針域令為null;
head.setNext(null);
// 反轉(zhuǎn)后新鏈表的頭結(jié)點(diǎn)
return reHead;
}
③.頭插法反轉(zhuǎn)鏈表:在原有鏈表的基礎(chǔ)上,依次將位于鏈表頭部的節(jié)點(diǎn)摘下,然后采用從頭部插入的方式生成
一個(gè)新鏈表,則此鏈表即為原鏈表的反轉(zhuǎn)。```java
public ListNode reverseList(ListNode head) {
ListNode dum = new ListNode();
ListNode pre = head;
while (pre!=null){
ListNode pNext = pre.next;
pre.next = dum.next;
dum.next = pre;
pre = pNext;
}
head = dum.next;
return head;
}
  1. 如何判斷鏈表是否有環(huán)?
    使用追趕的方法,設(shè)定兩個(gè)指針slow、fast
    從頭指針開始,每次fast指針前進(jìn)1步, slow指針前進(jìn)2步。
    如存在環(huán),則兩者相遇;如不存在環(huán),fast遇到NULL退出
  2. 如何找到單向鏈表的中間元素
    設(shè)定兩個(gè)指針slow、fast
    從頭指針開始,每次fast指針前進(jìn)1步, slow指針前進(jìn)2步
    當(dāng)fast指針走到鏈表結(jié)尾位置, slow指針?biāo)幬恢玫脑鼐褪侵虚g元素.

十二、 工具使用 【3道】

  1. 在Linux中如何查看tomcat日志, 命令是什么?
    tail -f tomcat日志所在路徑
  2. maven推送自己寫的工具包項(xiàng)目到公司maven私服供其他組員使用的命令?
    mvn deploy 可以推送到公司內(nèi)部的私服服務(wù)器,
    其他組員maven的settings.xml中可以配置公司私服的地址,
    然后項(xiàng)目的pom文件中寫上這個(gè)jar包的坐標(biāo), 就會(huì)自動(dòng)從公司私服下載這個(gè)依賴包, 項(xiàng)目中就可以直接使
    用.
  3. 使用maven項(xiàng)目如何打包部署
    使用mvn package命令進(jìn)行打包
    War包項(xiàng)目打包后將打包好的文件上傳到服務(wù)器tomcat的webapps目錄, 重啟tomcat
    Springboot項(xiàng)目打包后是jar包, 將打包好的文件上傳到服務(wù)器, 執(zhí)行java -jar xxx.jar啟動(dòng)運(yùn)行項(xiàng)目.
http://www.risenshineclean.com/news/3355.html

相關(guān)文章:

  • 智達(dá)世通建設(shè)集團(tuán)有限公司網(wǎng)站廣州市新聞發(fā)布
  • 開發(fā)做網(wǎng)站公司itme收錄優(yōu)美圖片官網(wǎng)
  • 做視頻發(fā)哪個(gè)網(wǎng)站賺錢百度數(shù)據(jù)庫(kù)
  • 西湖專業(yè)網(wǎng)站設(shè)計(jì)公司網(wǎng)站策劃書的撰寫流程
  • 網(wǎng)站定制文章列表項(xiàng)怎么做盤古搜索
  • shopify可以用來做B2B網(wǎng)站嗎百度網(wǎng)頁(yè)版電腦版入口
  • 做門窗投標(biāo)網(wǎng)站seo課程在哪培訓(xùn)好
  • 公司名詞解釋百度關(guān)鍵詞排名優(yōu)化
  • web網(wǎng)站開發(fā)完整教程線下推廣公司
  • wordpress安裝在vps百度seo公司興田德潤(rùn)
  • 平面設(shè)計(jì)主要學(xué)什么哪些軟件seo產(chǎn)品推廣
  • 網(wǎng)站設(shè)計(jì)與制作教程1百度搜索引擎優(yōu)化怎么做
  • 網(wǎng)站logo如何做鏈接免費(fèi)b2b網(wǎng)站推廣有哪些
  • 做國(guó)際網(wǎng)站要多少錢友情鏈接你會(huì)回來感謝我
  • 做pc端網(wǎng)站什么開頭必應(yīng)站長(zhǎng)平臺(tái)
  • 網(wǎng)站出現(xiàn)的的問題搜索引擎優(yōu)化的完整過程
  • 做ppt好的網(wǎng)站有哪些方面汕頭網(wǎng)站建設(shè)推廣
  • 有哪些國(guó)外網(wǎng)站做的好的效果圖培訓(xùn)網(wǎng)站有哪些
  • 渭南建網(wǎng)站seo首頁(yè)關(guān)鍵詞優(yōu)化
  • 有人知道做網(wǎng)站嗎?廣告公司排名
  • 高清做視頻在線觀看網(wǎng)站網(wǎng)絡(luò)開發(fā)
  • 網(wǎng)站建設(shè)收費(fèi)標(biāo)準(zhǔn)域名查詢 站長(zhǎng)查詢
  • 公司兩個(gè)網(wǎng)站如何都備案專業(yè)培訓(xùn)
  • 網(wǎng)站做多個(gè)單頁(yè)鏈接學(xué)校網(wǎng)站模板
  • 做化妝刷的外貿(mào)網(wǎng)站長(zhǎng)春網(wǎng)站優(yōu)化體驗(yàn)
  • 網(wǎng)站數(shù)據(jù)分析指標(biāo)武漢網(wǎng)站推廣公司排名
  • 網(wǎng)站設(shè)置價(jià)格錯(cuò)誤不愿意發(fā)貨軟文發(fā)布平臺(tái)
  • 簡(jiǎn)單php企業(yè)網(wǎng)站源碼網(wǎng)絡(luò)廣告策劃方案范文
  • 2018做網(wǎng)站用什么開發(fā)上海百網(wǎng)優(yōu)seo優(yōu)化公司
  • 網(wǎng)站維護(hù) 公司簡(jiǎn)介谷歌seo軟件