JAVA 常見問題

JVM

說一下 jvm 的主要組成部分?及其作用寞忿?

JVM包括類加載子系統(tǒng)、堆顶岸、方法區(qū)腔彰、棧、本地方法棧辖佣、程序計數(shù)器霹抛、直接內(nèi)存、垃圾回收器卷谈、執(zhí)行引擎杯拐。
1、類加載子系統(tǒng)
類加載子系統(tǒng)負責加載class信息世蔗,加載的類信息存放于方法區(qū)中端逼。
2、直接內(nèi)存
直接內(nèi)存是在Java堆外的污淋、直接向系統(tǒng)申請的內(nèi)存空間顶滩。訪問直接內(nèi)存的速度會高于Java堆。出于性能的考慮寸爆,讀寫頻繁的場合可能會考慮使用直接內(nèi)存礁鲁。
3盐欺、垃圾回收器
垃圾回收器可以對堆、方法區(qū)仅醇、直接內(nèi)存進行回收冗美。
4、執(zhí)行引擎
執(zhí)行引擎負責執(zhí)行虛擬機的字節(jié)碼析二,虛擬機會使用即時編譯技術(shù)將方法編譯成機器碼后再執(zhí)行墩衙。

image
  1. 程序計數(shù)器

【指向當前線程所執(zhí)行的字節(jié)碼的行號】,其實就是一小塊內(nèi)存甲抖,記錄著當前程序運行到哪了漆改。字節(jié)碼解釋器的工作就是通過改變這個計數(shù)器的值來選取下一條需要執(zhí)行的字節(jié)碼指令(字節(jié)碼指令是什么?)准谚。分支挫剑,循環(huán),跳轉(zhuǎn)柱衔,異常處理樊破,線程回復等都需要依賴這個計數(shù)器來完成。
由于Java的多線程是通過線程輪流切換完成的唆铐,一個線程沒有執(zhí)行完時就需要一個東西記錄它執(zhí)行到哪了哲戚,下次搶占到了CPU資源時再從這開始,這個東西就是程序計數(shù)器艾岂,正是因為這樣顺少,所以它也是“線程私有”的內(nèi)存。
如果一個線程執(zhí)行一個主要方法王浴,這個計數(shù)器記錄的是正在執(zhí)行的虛擬機字節(jié)碼指令的地址;如果正在執(zhí)行的是一個本地方法脆炎,這個計數(shù)器的值則為空,此內(nèi)存區(qū)域是唯一一個在Java的虛擬機規(guī)范中沒有規(guī)定任何OutOfMemoryError異常情況的區(qū)域氓辣。

  1. Java虛擬機棧

與程序計數(shù)器一樣秒裕,Java的虛擬機棧也是線程私有的,虛擬機棧描述的是Java的方法執(zhí)行的內(nèi)存模型钞啸,方法每個執(zhí)行在同時的創(chuàng)建33都會一個棧楨用于存儲局部變量表几蜻,操作數(shù)棧,動態(tài)鏈接体斩,方法出口等信息梭稚,下圖為棧楨結(jié)構(gòu)圖:


image

通常所說的JVM里的堆和棧里這個棧就是Java的虛擬機棧,或者說是Java的虛擬機棧中的局部變量表部分硕勿。
局部變量表存放了編譯期可知的各種基本數(shù)據(jù)類型哨毁,對象引用(僅限局部變量的,不包含成員變量的)源武。其中每個局部變量空間(Slot)有32位扼褪,所以long和double類型的數(shù)據(jù)會占用兩個局部變量空間想幻,其他類型包括對象引用占用一個。對象引用調(diào)用的是存在堆中的對象话浇,這個引用可以是對象的起始地址或者是指向?qū)ο蟮木浔嗵骸>植孔兞勘硭璧膬?nèi)存在編譯期就已經(jīng)確定了也就是進入這個方法時就已經(jīng)確定了,運行期間不會更改幔崖。
操作數(shù)棧則存儲方法內(nèi)一些進行了運算操作后的結(jié)果食店。
動態(tài)鏈接,在方法內(nèi)調(diào)用接口赏寇,通過字面量鏈接到具體的實現(xiàn)類吉嫩,實現(xiàn)Java的動態(tài)特性。
方法出口(返回地址)嗅定,return或者發(fā)生Exception等自娩。
如果方法methodOne方法調(diào)用了methodTwo,那么methodOne就會先入棧創(chuàng)建一個棧楨渠退,接著methodTwo再入棧成為棧頂(假設(shè)沒有其他的方法執(zhí)行)忙迁,methodTwo執(zhí)行完先出棧,接著methodOne執(zhí)行完出棧碎乃。
在使用遞歸的情況下姊扔,如果線程請求的棧的深度超過虛擬機所允許棧的深度就會拋出StackOverflowError;但是大部分虛擬機棧的深度都可以動態(tài)擴展梅誓,HotSpot中使用XSS可以設(shè)置棧的深度恰梢,如果擴展時無法請求到足夠的內(nèi)存就會拋出OutOfMemoryError。

  1. 本地方法棧

本地方法棧和虛擬機棧相似证九,區(qū)別就是虛擬機為虛擬機棧執(zhí)行Java服務(wù)(字節(jié)碼服務(wù))删豺,而本地方法棧為虛擬機使用到的Native方法服務(wù)。本地方法棧中使用的語言愧怜,使用方式,數(shù)據(jù)結(jié)構(gòu)沒有強制要求妈拌。

  1. Java堆

堆是JVM里最大的一塊內(nèi)存區(qū)域,被所有線程共享,在虛擬機啟動時創(chuàng)建峭跳,此區(qū)域的目的就是存放對象實例和數(shù)組唱矛,幾乎所有的對象實例都在這分配(隨著JIT的發(fā)展已經(jīng)不是那么絕對了)的.java堆是垃圾收集管理的主要區(qū)域,由于現(xiàn)在收集器基本都采用分代收集方法培愁,所以Java的堆中還可以分為新生代著摔,老年代,永久代.1.8之后取消了永久代;其中新生代又劃分為Eden空間定续,F(xiàn)rom Survivor空間谍咆,To Survivor空間禾锤。無論怎么劃分都是為了更好的回收,分配摹察,利用內(nèi)存恩掷。下圖為1.8后的內(nèi)存模型
根據(jù)的Java虛擬機規(guī)范,Java的堆可以處于物理不連續(xù)的空間中供嚎,只要邏輯連續(xù)即可黄娘。在實現(xiàn)時,既可以實現(xiàn)成固定大小的也可以是可擴展的(通過-Xmx和-Xms控制)克滴,如果堆中沒有足夠的內(nèi)存完成實例分配逼争,并且堆也無法得到擴展時,將會拋出的OutOfMemoryError異常劝赔。

JDK8 從永久代到元空間

  1. 方法區(qū)

方法區(qū)也是一個線程共享的區(qū)域誓焦,存儲已被虛擬機加載的類信息,常量(final)望忆,靜態(tài)變量(static)罩阵,JIT(即時編譯器)編譯后的代碼等數(shù)據(jù)。
Java虛擬機規(guī)范把方法區(qū)描述為堆的一個邏輯部分启摄,其實堆和方法區(qū)可以看成數(shù)據(jù)部分稿壁;虛擬機棧和程序計數(shù)器可以看成指令部分;方法區(qū)存儲一些不會變更的數(shù)據(jù)歉备,之前熱點上使用GC分代收集管理方法區(qū)傅是,所以方法區(qū)也被稱為永久代(本質(zhì)上兩者不等價),但是現(xiàn)在已經(jīng)使用Native Memory來代替永久代了蕾羊。
虛擬機對方法區(qū)規(guī)范非常寬松喧笔,除了和Java的堆一樣不需要連續(xù)的內(nèi)存和可以選擇固定大小意外,還可以選擇不實現(xiàn)垃圾回收龟再。垃圾回收行為在這個區(qū)域比較少見但還是有必要的书闸,主要是針對常量池回收和類型的卸載。

5.1運行時常量池

運行時常量池是方法區(qū)的一部分利凑,用于存放編譯期生成的各種字面量和符號引用浆劲,運行時常量池相對于類常量池另外一個特性就是具備動態(tài)性,運行期間可能將新的常量放入池中哀澈。

說一下堆棧的區(qū)別牌借?

隊列和棧是什么?有什么區(qū)別割按?

什么是雙親委派模型膨报?

當需要加載一個類的時候,子類加載器并不會馬上去加載,而是依次去請求父類加載器加載现柠,一直往上請求到最高類加載器:啟動類加載器院领。當啟動類加載器加載不了的時候,依次往下讓子類加載器進行加載晒旅。當達到最底下的時候栅盲,如果還是加載不到該類,就會出現(xiàn)ClassNotFound的情況废恋。

好處:保證了程序的安全性谈秫。例子:比如我們重新寫了一個String類,加載的時候并不會去加載到我們自己寫的String類鱼鼓,因為當請求上到最高層的時候拟烫,啟動類加載器發(fā)現(xiàn)自己能夠加載String類,因此就不會加載到我們自己寫的String類了迄本。

說一下類加載的執(zhí)行過程硕淑?

  1. 加載:將java源代碼編譯后的.class字節(jié)碼文件以二進制流的方式加載進內(nèi)存
  2. 連接:
  • 驗證:驗證加載進來的二進制流是否符合虛擬機的規(guī)范,不會危害的虛擬機自身的安全
  • 準備:給類變量(靜態(tài)變量)賦予初始值嘉赎,基本數(shù)據(jù)/引用類型數(shù)據(jù)
  • 解析:將字符串引用轉(zhuǎn)換為直接引用
  1. 初始化:變量賦予初始值置媳、執(zhí)行靜態(tài)語句塊、執(zhí)行構(gòu)造函數(shù)等等公条。

怎么判斷對象是否可以被回收拇囊?

  1. 引用計數(shù)算法(已被淘汰的算法)
    給對象中添加一個引用計數(shù)器,每當有一個地方引用它時,計數(shù)器值就加1;當引用失效時,計數(shù)器值就減1;任何時刻計數(shù)器為0的對象就是不可能再被使用的。
    目前主流的java虛擬機都摒棄掉了這種算法靶橱,最主要的原因是它很難解決對象
    之間相互循環(huán)引用的問題寥袭。盡管該算法執(zhí)行效率很高

  2. 可達性分析算法
    目前主流的編程語言(java,C#等)的主流實現(xiàn)中,都是稱通過可達性分析(Reachability Analysis)來判定對象是否存活的。這個算法的基本思路就是通過一系列的稱為“GC Roots”的對象作為起始點,從這些節(jié)點開始向下搜索,搜索所走過的路徑稱為引用鏈(Reference Chain),當一個對象到GC Roots沒有任何引用鏈相連(用圖論的話來說,就是從GC Roots到這個對象不可達)時,則證明此對象是不可用的关霸。如下圖所示传黄,對象object 5、object 6队寇、object 7雖然互相有關(guān)聯(lián),但是它們到GC Roots是不可達的,所以它們將會被判定為是可回收的對象膘掰。


    image

在Java語言中,可作為GC Roots的對象包括下面幾種:

  • 虛擬機棧(棧幀中的本地變量表)中引用的對象。
  • 方法區(qū)中類靜態(tài)屬性引用的對象佳遣。
  • 方法區(qū)中常量引用的對象炭序。
  • 本地方法棧中JNI(即一般說的Native方法)引用的對象

被GC判斷為”垃圾”的對象一定會回收嗎?
即使在可達性分析算法中不可達的對象,也并非是“非死不可”的,這時候它們暫時處于“緩刑”階段,要真正宣告一個對象死亡,至少要經(jīng)歷兩次標記過程:如果對象在進行可達性分析后發(fā)現(xiàn)沒有與GC Roots相連接的引用鏈,那它將會被第一次標記并且進行一次篩選,篩選的條件是此對象是否有必要執(zhí)行finalize()方法。當對象沒有覆蓋finalize()方法,或者finalize()方法已經(jīng)被虛擬機調(diào)用過,虛擬機將這兩種情況都視為“沒有必要執(zhí)行”苍日。(即意味著直接回收)

如果這個對象被判定為有必要執(zhí)行finalize()方法,那么這個對象將會放置在一個叫做F-Queue的隊列之中,并在稍后由一個由虛擬機自動建立的、低優(yōu)先級的Finalizer線程去執(zhí)行它窗声。這里所謂的“執(zhí)行”是指虛擬機會觸發(fā)這個方法,但并不承諾會等待它運行結(jié)束,這樣做的原因是,如果一個對象在finalize()方法中執(zhí)行緩慢,或者發(fā)生了死循環(huán)(更極端的情況),將很可能會導致F-Queue隊列中其他對象永久處于等待,甚至導致整個內(nèi)存回收系統(tǒng)崩潰相恃。

finalize()方法是對象逃脫死亡命運的最后一次機會,稍后GC將對F-Queue中的對象進行第二次小規(guī)模的標記,如果對象要在finalize()中成功拯救自己——只要重新與引用鏈上的任何一個對象建立關(guān)聯(lián)即可,譬如把自己(this關(guān)鍵字)賦值給某個類變量或者對象的成員變量,那在第二次標記時它將被移除出“即將回收”的集合;如果對象這時候還沒有逃脫,那基本上它就真的被回收了。

java 中都有哪些引用類型笨觅?

  • 強引用(strong reference)
    就是指在程序代碼之中普遍存在的,類似“Object obj=new Object()” 這類的引用,只要強引用還存在,垃圾收集器永遠不會回收掉被引用的對象實例拦耐。

  • 軟引用(soft reference)
    一些有用但是并非必需耕腾,用軟引用關(guān)聯(lián)的對象,系統(tǒng)將要發(fā)生OOM之前杀糯,這些對象就會被回收扫俺。

  • 弱引用(weak reference)
    弱引用(weakreference)是一些有用(程度比軟引用更低)但是并非必需,用弱引用關(guān)聯(lián)的對象固翰,只能生存到下一次垃圾回收之前狼纬,GC發(fā)生時,不管內(nèi)存夠不夠骂际,都會被回收疗琉。

  • 虛引用(phantom reference)
    虛引用(phantomreference)幽靈引用,最弱歉铝,被垃圾回收的時候收到一個通知
    一個對象 實例是否有虛引用的存在,完全不會對其生存時間構(gòu)成影響,也無法通過虛引用 來取得一個對象實例盈简。為一個對象設(shè)置虛引用關(guān)聯(lián)的唯一目的就是能在這個對象 實例被收集器回收時收到一個系統(tǒng)通知。

說一下 jvm 有哪些垃圾回收算法太示?

  1. 標記清除算法
    分為標記和清除兩個階段柠贤。由于標記清除算法在清理對象所占用的內(nèi)存空間后,并沒有整理可用的內(nèi)存空間类缤,因此如果內(nèi)存中可被回收的小對象過多臼勉,則會引起內(nèi)存碎片化的問題。
  2. 復制算法
  3. 標記整理法
    標記同1呀非。標記完成后將存活的對象移到內(nèi)存的另一端坚俗,然后清除該端的對象并釋放內(nèi)存。
  4. 分代收集算法
  5. 分區(qū)收集算法

說一下 jvm 有哪些垃圾回收器岸裙?

詳細介紹一下 CMS 垃圾回收器猖败?

新生代垃圾回收器和老生代垃圾回收器都有哪些?有什么區(qū)別降允?

  1. Serial垃圾收集器:單線程恩闻,復制算法
  2. ParNew垃圾收集器:多線程,復制算法
  3. Parrallel Scavenge垃圾收集器:多線程剧董,復制算法
  4. Serial Old垃圾收集器:單線程幢尚,標記整理算法
  5. Parrallel Old垃圾收集器:多線程,標記整理算法
  6. CMS垃圾收集器
    CMS是為老年代設(shè)計的垃圾收集器翅楼,其主目的是使用最短的垃圾回收停頓時間完成垃圾回收尉剩,基于多線程的標記清除算法實現(xiàn),以便在多線程并發(fā)環(huán)境下以最短的垃圾收集停頓時間提高系統(tǒng)的穩(wěn)定性毅臊。
    6.1 初始標記
    標記和GC Roots直接關(guān)聯(lián)的對象理茎,需要暫停所有工作線程。
    6.2 并發(fā)標記
    和用戶線程一起工作,執(zhí)行GC Roots跟蹤標記過程皂林,不需要暫停工作線程朗鸠。
    6.3 重新標記
    在并發(fā)標記過程中用戶線程繼續(xù)執(zhí)行,導致在垃圾回收過程中部分的對象狀態(tài)發(fā)生變化础倍,未來保證這部分對象的狀態(tài)正確性烛占,需要對其重新標記并暫停工作線程。
    6.4 并發(fā)清除
    和用戶線程一起工作沟启,執(zhí)行清除GC Roots不可達對象的任務(wù)忆家,不需要暫停工作線程。
  7. G1垃圾收集器
    將內(nèi)存劃分為大小固定的幾個獨立區(qū)域美浦,獨立使用這些區(qū)域的內(nèi)存資源并且跟蹤這些區(qū)域的垃圾收集進度弦赖。同時后臺維護一個優(yōu)先級列表,在垃圾回收過程中根據(jù)系統(tǒng)允許的最長垃圾收集時間浦辨,優(yōu)先回收垃圾最多的區(qū)域蹬竖。
  • 基于標記整理算法,不產(chǎn)生內(nèi)存碎片
  • 可以精確地控制停頓時間流酬,在不犧牲吞吐量的前提下币厕,實現(xiàn)最短停頓垃圾回收。

簡述分代垃圾回收器是怎么工作的芽腾?

1旦装、新生代復制算法
2、老年代標記整理算法

說一下 jvm 調(diào)優(yōu)的工具摊滔?

常用的 jvm 調(diào)優(yōu)的參數(shù)都有哪些阴绢?

XX比X的穩(wěn)定性更差,并且版本更新不會進行通知和說明艰躺。

  1. -Xms

s為strating呻袭,表示堆內(nèi)存起始大小

  1. -Xmx

x為max,表示最大的堆內(nèi)存

(一般來說-Xms和-Xmx的設(shè)置為相同大小腺兴,因為當heap自動擴容時左电,會發(fā)生內(nèi)存抖動,影響程序的穩(wěn)定性)

  1. -Xmn

n為new页响,表示新生代大小

(-Xss:規(guī)定了每個線程虛擬機棧(堆棧)的大新ㄗ恪)

  1. -XX:SurvivorRator=8

表示堆內(nèi)存中新生代、老年代和永久代的比為8:1:1

  1. -XX:PretenureSizeThreshold=3145728

表示當創(chuàng)建(new)的對象大于3M的時候直接進入老年代

  1. -XX:MaxTenuringThreshold=15

表示當對象的存活的年齡(minor gc一次加1)大于多少時闰蚕,進入老年代

  1. -XX:-DisableExplicirGC

表示是否(+表示是栈拖,-表示否)打開GC日志


JAVA基礎(chǔ)

==和equals的區(qū)別

  1. 功能不同
    "=="是判斷兩個變量或?qū)嵗遣皇侵赶蛲粋€內(nèi)存空間。
    "equals"是判斷兩個變量或?qū)嵗赶虻膬?nèi)存空間的值是不是相同没陡。
  2. 定義不同
    "equals"在JAVA中是一個方法辱魁。
    "=="在JAVA中只是一個運算符合烟瞧。

抽象類和接口的區(qū)別

含有abstract修飾符的class即為抽象類,abstract 類不能創(chuàng)建實例對象染簇。含有abstract方法的類必須定義為abstract class,abstract class類中的方法不必是抽象的强岸。abstract class類中定義抽象方法必須在具體(Concrete)子類中實現(xiàn)锻弓,所以,不能有抽象構(gòu)造方法或抽象靜態(tài)方法蝌箍。如果子類沒有實現(xiàn)抽象父類中的所有抽象方法青灼,那么子類也必須定義為abstract類型。
接口(interface)可以說成是抽象類的一種特例妓盲,接口中的所有方法都必須是抽象的杂拨。接口中的方法定義默認為public abstract類型,接口中的成員變量類型默認為public static final悯衬。

下面比較一下兩者的語法區(qū)別:

  1. 抽象類可以有構(gòu)造方法弹沽,接口中不能有構(gòu)造方法。
  2. 抽象類中可以有普通成員變量筋粗,接口中沒有普通成員變量
  3. 抽象類中可以包含非抽象的普通方法策橘,接口中的所有方法必須都是抽象的,不能有非抽象的普通方法娜亿。
  4. 抽象類中的抽象方法的訪問類型可以是public丽已,protected,但接口中的抽象方法只能是public類型的买决,并且默認即為public abstract類型沛婴。
  5. 抽象類中可以包含靜態(tài)方法,接口中不能包含靜態(tài)方法
  6. 抽象類和接口中都可以包含靜態(tài)成員變量督赤,抽象類中的靜態(tài)成員變量的訪問類型可以任意嘁灯,但接口中定義的變量只能是public static final類型,并且默認即為public static final類型够挂。
  7. 一個類可以實現(xiàn)多個接口旁仿,但只能繼承一個抽象類。

子類與父類初始化順序

父類靜態(tài)代碼塊 > 子類靜態(tài)代碼塊 > 父類普通成員變量和代碼塊 > 子類普通成員變量和代碼塊 > 父類構(gòu)造函數(shù) > 子類構(gòu)造函數(shù)

JAVA中的IO流可以分為幾種孽糖?

  1. 按流的方向分類:
    1. 輸入流:數(shù)據(jù)流向是數(shù)據(jù)源到程序(以InputStream枯冈、Reader結(jié)尾的流)。
    2. 輸出流:數(shù)據(jù)流向是程序到目的地(以O(shè)utputStream办悟、Writer結(jié)尾的流)尘奏。
      特別注意:輸入/輸出流的劃分是相對于程序而言的,而不是相對于數(shù)據(jù)源的病蛉。
  2. 按處理的數(shù)據(jù)單元分類:
    1. 字節(jié)流:以字節(jié)為單位獲取數(shù)據(jù)炫加,命名上以Stream結(jié)尾的流一般是字節(jié)流瑰煎,如FileInputStream、FileOutputStream俗孝。字節(jié)流可以處理任何一切形式的數(shù)據(jù)源酒甸,包括音頻,視頻赋铝,圖片插勤,純文本,Word革骨,Excel等等农尖。
    2. 字符流:以字符為單位獲取數(shù)據(jù),命名上以Reader/Writer結(jié)尾的流一般是字符流良哲,如FileReader盛卡、FileWriter。字符流只能處理字符串筑凫,純文本等滑沧。
  3. 按處理對象不同分類:
    1. 節(jié)點流:可以直接從數(shù)據(jù)源或目的地讀寫數(shù)據(jù),如FileInputStream漏健、FileReader嚎货、DataInputStream等。
    2. 處理流:不直接連接到數(shù)據(jù)源或目的地蔫浆,是”處理流的流”殖属。通過對其他流的處理提高程序的性能,如BufferedInputStream瓦盛、BufferedReader等洗显。處理流也叫包裝流。
      節(jié)點流處于IO操作的第一線原环,所有操作必須通過它們進行;處理流可以對節(jié)點流進行包裝挠唆,提高性能或提高程序的靈活性。沒有節(jié)點流嘱吗,處理流發(fā)揮不了任何作用掘鄙。

BIO麦萤、NIO确垫、AIO有什么區(qū)別

  • BIO (Blocking I/O): 同步阻塞I/O模式公黑,數(shù)據(jù)的讀取寫入必須阻塞在一個線程內(nèi)等待其完成。在活動連接數(shù)不是特別高(小于單機1000)的情況下绕德,這種模型是比較不錯的患膛,可以讓每一個連接專注于自己的 I/O 并且編程模型簡單,也不用過多考慮系統(tǒng)的過載耻蛇、限流等問題踪蹬。線程池本身就是一個天然的漏斗胞此,可以緩沖一些系統(tǒng)處理不了的連接或請求。但是跃捣,當面對十萬甚至百萬級連接的時候漱牵,傳統(tǒng)的 BIO 模型是無能為力的。因此枝缔,我們需要一種更高效的 I/O 處理模型來應(yīng)對更高的并發(fā)量布疙。
  • NIO (New I/O): NIO是一種同步非阻塞的I/O模型,在Java 1.4 中引入了NIO框架愿卸,對應(yīng) java.nio 包,提供了 Channel , Selector截型,Buffer等抽象趴荸。NIO中的N可以理解為Non-blocking,不單純是New宦焦。它支持面向緩沖的发钝,基于通道的I/O操作方法。 NIO提供了與傳統(tǒng)BIO模型中的 Socket 和 ServerSocket 相對應(yīng)的 SocketChannel 和 ServerSocketChannel 兩種不同的套接字通道實現(xiàn),兩種通道都支持阻塞和非阻塞兩種模式波闹。阻塞模式使用就像傳統(tǒng)中的支持一樣酝豪,比較簡單,但是性能和可靠性都不好精堕;非阻塞模式正好與之相反孵淘。對于低負載、低并發(fā)的應(yīng)用程序歹篓,可以使用同步阻塞I/O來提升開發(fā)速率和更好的維護性瘫证;對于高負載、高并發(fā)的(網(wǎng)絡(luò))應(yīng)用庄撮,應(yīng)使用 NIO 的非阻塞模式來開發(fā)
  • AIO (Asynchronous I/O): AIO 也就是 NIO 2背捌。在 Java 7 中引入了 NIO 的改進版 NIO 2,它是異步非阻塞的IO模型。異步 IO 是基于事件和回調(diào)機制實現(xiàn)的洞斯,也就是應(yīng)用操作之后會直接返回毡庆,不會堵塞在那里,當后臺處理完成烙如,操作系統(tǒng)會通知相應(yīng)的線程進行后續(xù)的操作么抗。AIO 是異步IO的縮寫,雖然 NIO 在網(wǎng)絡(luò)操作中厅翔,提供了非阻塞的方法乖坠,但是 NIO 的 IO 行為還是同步的。對于 NIO 來說刀闷,我們的業(yè)務(wù)線程是在 IO 操作準備好時熊泵,得到通知仰迁,接著就由這個線程自行進行 IO 操作,IO操作本身是同步的顽分。


    image
  • IO:一個連接一個線程徐许,客戶端有連接請求時服務(wù)器端就需要啟動一個線程進行處理。線程開銷大卒蘸。
  • 偽異步 IO:將請求連接放入線程池雌隅,一對多,但線程還是很寶貴的資源缸沃。
  • NIO:一個請求一個線程恰起,但客戶端發(fā)送的連接請求都會注冊到多路復用器上,多路復用器輪詢到連接有 I/O 請求時才啟動一個線程進行處理趾牧。
  • AIO:一個有效請求一個線程检盼,客戶端的 I/O 請求都是由 OS 先完成了再通知服務(wù)器應(yīng)用去啟動線程進行處理,
  • BIO 是面向流的翘单,NIO 是面向緩沖區(qū)的吨枉;BIO 的各種流是阻塞的。而 NIO 是非阻塞的哄芜;BIO的 Stream 是單向的貌亭,而 NIO 的 channel 是雙向的。
  • NIO 的特點:事件驅(qū)動模型认臊、單線程處理多任務(wù)圃庭、非阻塞 I/O,I/O 讀寫不再阻塞美尸,而是返回 0冤议、基于 block 的傳輸比基于流的傳輸更高效、更高級的 IO 函數(shù) zero-copy师坎、IO 多路復用大大提高了 Java 網(wǎng)絡(luò)應(yīng)用的可伸縮性和實用性恕酸。基于 Reactor 線程模型胯陋。
    在 Reactor 模式中蕊温,事件分發(fā)器等待某個事件或者可應(yīng)用或個操作的狀態(tài)發(fā)生,事件分發(fā)器就把這個事件傳給事先注冊的事件處理函數(shù)或者回調(diào)函數(shù)遏乔,由后者來做實際的讀寫操作义矛。如在 Reactor 中實現(xiàn)讀:注冊讀就緒事件和相應(yīng)的事件處理器、事件分發(fā)器等待事件盟萨、事件到來凉翻,激活分發(fā)器,分發(fā)器調(diào)用事件對應(yīng)的處理器捻激、事件處理器完成實際的讀操作制轰,處理讀到的數(shù)據(jù)前计,注冊新的事件,然后返還控制權(quán)垃杖。

容器

Colletion和Collections有什么區(qū)別

Collection是集合體系的最頂層男杈,包含了集合體系的共性
Collections是一個工具類,方法都是用于操作Collection

List调俘、Set伶棒、Map之間的區(qū)別

image

List 可重復

  • ArrayList: 基于數(shù)組實現(xiàn),增刪慢彩库,查詢快肤无,線程不安全
  • Vector:基于數(shù)組實現(xiàn),增刪慢骇钦,查詢快舅锄,線程安全
    Vector的數(shù)據(jù)結(jié)構(gòu)和ArrayList是一樣的,不同的是Vector支持線程同步司忱,即同一時刻只允許一個線程對Vector進行寫操作。因為需要在Vector實例進行加鎖和釋放鎖畴蹭,其讀寫效率要比ArrayList低坦仍。
  • LinkedList:基于雙向鏈表實現(xiàn),增刪快叨襟,查詢慢繁扎,線程不安全

Queue

  • ArrayBlockingQueue:基于數(shù)組結(jié)構(gòu)實現(xiàn)的有界阻塞隊列
  • LinkedBlockingQueue:基于鏈表數(shù)據(jù)結(jié)構(gòu)實現(xiàn)的有界阻塞隊列
  • PriorityBlockingQueue:支持優(yōu)先級排序的無界阻塞隊列
  • DelayQueue:支持延遲操作的無界阻塞隊列
  • SynchronouesQueue:用于線程同步的阻塞隊列
  • LinkedTransferQueue:基于鏈表數(shù)據(jù)結(jié)構(gòu)實現(xiàn)的無界阻塞隊列
  • LinkedBlockingQueue:基于鏈表數(shù)據(jù)結(jié)構(gòu)實現(xiàn)的雙向阻塞隊列

Set 不可重復

  • HashSet:HashMap實現(xiàn),無序糊闽。先判斷元素hashcode梳玫,如果相同再判斷equals
  • TreeSet:二叉樹實現(xiàn)。自定義的數(shù)據(jù)類型必須實現(xiàn)Comparable接口右犹,并且覆寫其中的compareTo函數(shù)才可以按照預(yù)定義的順序存儲提澎。如果是升序排序,則this對象小于指定對象的情況下念链,返回-1盼忌。降序反之。
  • LinkHashSet:繼承HashSet掂墓,HashMap實現(xiàn)數(shù)據(jù)存儲谦纱,雙向鏈表記錄順序

Map

  • HashMap 數(shù)組+鏈表存儲結(jié)構(gòu),線程不安全
    [HashMap解析]http://www.reibang.com/p/1675d386f1af

  • ConcurrentHashMap:
    1.7之前采用segment分段鎖君编。
    1.8之后采用Synchronized+CAS跨嘉,同時引入了紅黑樹。取消segments字段吃嘿,直接采用transient volatile HashEntry<K,V>[] table保存數(shù)據(jù)祠乃,采用table數(shù)組元素作為鎖梦重,從而實現(xiàn)了對每一行數(shù)據(jù)進行加鎖,并發(fā)控制使用Synchronized和CAS來操作
    將原先table數(shù)組+單向鏈表的數(shù)據(jù)結(jié)構(gòu)跳纳,變更為table數(shù)組+單向鏈表+紅黑樹的結(jié)構(gòu).

  • HashTable: 線程安全忍饰。他是遺留類,他的常用功能和hashmap類似寺庄。不同的是他繼承自Dictionary類艾蓝。同一時刻,只能有一個線程寫HashTable斗塘,并發(fā)性不如ConcurrentMap赢织。

  • TreeMap:基于二叉樹結(jié)構(gòu)。其Key必須實現(xiàn)comparable接口或者自定義的比較器馍盟。

  • LinkedHashMap:繼承HashMap于置,使用鏈表保存插入順序

怎么確保一個集合不能被修改?

  • Collections. unmodifiableCollection(Collection c) 方法創(chuàng)建的集合贞岭。
  • 使用Arrays.asList創(chuàng)建的集合八毯。

多線程

并行和并發(fā)有什么區(qū)別?

你吃飯吃到一半,電話來了瞄桨,你一直到吃完了以后才去接话速,這就說明你不支持并發(fā)也不支持并行。
你吃飯吃到一半芯侥,電話來了泊交,你停了下來接了電話,接完后繼續(xù)吃飯柱查,這說明你支持并發(fā)廓俭。
你吃飯吃到一半,電話來了唉工,你一邊打電話一邊吃飯研乒,這說明你支持并行。

進程和線程有什么區(qū)別

進程是資源分配的最小單位酵紫,線程是CPU調(diào)度的最小單位

sleep和wait的區(qū)別

  • sleep屬于Thread類告嘲,wait屬于Object類
  • sleep方法暫停執(zhí)行的指定時間,讓出CPU給其他線程奖地,但其監(jiān)控狀態(tài)依然保持橄唬,在指定的時間過后又會自動恢復運行狀態(tài)。
  • 調(diào)用sleep過程中参歹,線程不會釋放對象鎖仰楚;調(diào)用wait方法時,線程會釋放對象鎖,進入等待此對象的等待鎖池僧界,只有針對此對象調(diào)用notify方法后侨嘀,該線程才能進入對象鎖池準備獲取對象鎖,并進入運行狀態(tài)捂襟。

start與run的區(qū)別

用start方法來啟動線程咬腕,真正實現(xiàn)了多線程運行,這時無需等待run方法體代碼執(zhí)行完畢而直接繼續(xù)執(zhí)行下面的代碼葬荷。通過調(diào)用Thread類的start()方法來啟動一個線程涨共,這時此線程處于就緒(可運行)狀態(tài),并沒有運行宠漩,一旦得到cpu時間片举反,就開始執(zhí)行run()方法,這里方法run()稱為線程體扒吁,它包含了要執(zhí)行的這個線程的內(nèi)容火鼻,run方法運行結(jié)束,此線程隨即終止雕崩。

創(chuàng)建線程有哪幾種方式魁索?

  • 繼承Thread類創(chuàng)建線程類
  • 通過Runnable接口創(chuàng)建線程類
  • 通過Callable和Future創(chuàng)建線程

創(chuàng)建線程的三種方式的對比:
采用實現(xiàn)Runnable、Callable接口的方式創(chuàng)見多線程時盼铁,

  • 優(yōu)勢:線程類只是實現(xiàn)了Runnable接口或Callable接口蛾默,還可以繼承其他類。
    在這種方式下捉貌,多個線程可以共享同一個target對象,所以非常適合多個相同線程來處理同一份資源的情況冬念,從而可以將CPU趁窃、代碼和數(shù)據(jù)分開,形成清晰的模型急前,較好地體現(xiàn)了面向?qū)ο蟮乃枷搿?/li>
  • 劣勢:編程稍微復雜醒陆,如果要訪問當前線程,則必須使用Thread.currentThread()方法裆针。

使用繼承Thread類的方式創(chuàng)建多線程時

  • 優(yōu)勢:編寫簡單刨摩,如果需要訪問當前線程,則無需使用Thread.currentThread()方法世吨,直接使用this即可獲得當前線程澡刹。
  • 劣勢:線程類已經(jīng)繼承了Thread類,所以不能再繼承其他父類耘婚。

說一下 runnable 和 callable 有什么區(qū)別罢浇?

  • Callable規(guī)定的方法是call(),Runnable規(guī)定的方法是run().
  • Callable的任務(wù)執(zhí)行后可返回值,而Runnable的任務(wù)是不能返回值得
  • call方法可以拋出異常,run方法不可以
  • 運行Callable任務(wù)可以拿到一個Future對象嚷闭,F(xiàn)uture 表示異步計算的結(jié)果攒岛。它提供了檢查計算是否完成的方法,以等待計算的完成胞锰,并獲取計算的結(jié)果灾锯。計算完成后只能使用 get 方法來獲取結(jié)果,如果線程沒有執(zhí)行完嗅榕,F(xiàn)uture.get()方法可能會阻塞當前線程的執(zhí)行顺饮;如果線程出現(xiàn)異常,F(xiàn)uture.get()會throws InterruptedException或者ExecutionException誊册;如果線程已經(jīng)取消领突,會跑出CancellationException。取消由cancel 方法來執(zhí)行案怯。isDone確定任務(wù)是正常完成還是被取消了君旦。一旦計算完成,就不能再取消計算嘲碱。如果為了可取消性而使用 Future 但又不提供可用的結(jié)果金砍,則可以聲明Future<?> 形式類型、并返回 null 作為底層任務(wù)的結(jié)果麦锯。

創(chuàng)建線程池有哪幾種方式恕稠?

  • newFixedThreadPool:定長線程池,每當提交一個任務(wù)就創(chuàng)建一個線程扶欣,直到達到線程池的最大數(shù)量鹅巍,這時線程數(shù)量不再變化,當線程發(fā)生錯誤結(jié)束時料祠,線程池會補充一個新的線程
  • newCachedThreadPool:可緩存的線程池骆捧,如果線程池的容量超過了任務(wù)數(shù),自動回收空閑線程髓绽,任務(wù)增加時可以自動添加新線程敛苇,線程池的容量不限制
  • newScheduledThreadPool:定長線程池,可執(zhí)行周期性的任務(wù)
  • newSingleThreadExecutor: 單線程的線程池顺呕,線程異常結(jié)束枫攀,會創(chuàng)建一個新的線程,能確保任務(wù)按提交順序執(zhí)行
  • newSingleThreadScheduledExecutor: 單線程可執(zhí)行周期性任務(wù)的線程池
  • newWorkStealingPool:任務(wù)竊取線程池株茶,不保證執(zhí)行順序来涨,適合任務(wù)耗時差異較大。

線程池中 submit()和 execute()方法有什么區(qū)別启盛?

  • execute() 參數(shù) Runnable 扫夜;submit() 參數(shù) (Runnable) 或 (Runnable 和 結(jié)果 T) 或 (Callable)
  • execute() 沒有返回值;而 submit() 有返回值
  • submit() 的返回值 Future 調(diào)用get方法時,可以捕獲處理異常

什么是死鎖笤闯?怎么防止死鎖堕阔?

死鎖的四個條件

  1. 互斥條件:進程對于所分配到的資源具有排它性昆婿,即一個資源只能被一個進程占用生宛,直到被該進程釋放
  2. 請求和保持條件:一個進程因請求被占用資源而發(fā)生阻塞時灼芭,對已獲得的資源保持不放露该。
  3. 不剝奪條件:任何一個資源在沒被該進程釋放之前馁痴,任何其他進程都無法對他剝奪占用
  4. 循環(huán)等待條件:當發(fā)生死鎖時黔漂,所等待的進程必定會形成一個環(huán)路(類似于死循環(huán))订雾,造成永久阻塞晴玖。

怎么避免死鎖

  1. 避免嵌套鎖
  2. 只鎖需要的部分
  3. 避免無限期等待

ThreadLocal 是什么晶默?有哪些使用場景谨娜?

  1. 介紹

在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal為解決多線程程序的并發(fā)問題提供了一種新的思路磺陡。使用這個工具類可以很簡潔地編寫出優(yōu)美的多線程程序趴梢。
ThreadLocal并不是一個Thread,而是Thread的局部變量币他,也許把它命名為ThreadLocalVariable更容易讓人理解一些坞靶。
在JDK5.0中,ThreadLocal已經(jīng)支持泛型蝴悉,該類的類名已經(jīng)變?yōu)門hreadLocal<T>彰阴。API方法也相應(yīng)進行了調(diào)整,新版本的API方法分別是void set(T value)拍冠、T get()以及T initialValue()尿这。

  1. 作用

ThreadLocal是解決線程安全問題一個很好的思路,它通過為每個線程提供一個獨立的變量副本解決了變量并發(fā)訪問的沖突問題庆杜。在很多情況下妻味,ThreadLocal比直接使用synchronized同步機制解決線程安全問題更簡單,更方便欣福,且結(jié)果程序擁有更高的并發(fā)性。

  1. ThreadLocal的應(yīng)用場景焦履?

在Java的多線程編程中拓劝,為保證多個線程對共享變量的安全訪問,通常會使用synchronized來保證同一時刻只有一個線程對共享變量進行操作嘉裤。這種情況下可以將類變量放到ThreadLocal類型的對象中郑临,使變量在每個線程中都有獨立拷貝,不會出現(xiàn)一個線程讀取變量時而被另一個線程修改的現(xiàn)象屑宠。最常見的ThreadLocal使用場景為用來解決數(shù)據(jù)庫連接厢洞、Session管理等。在下面會例舉幾個場景。

經(jīng)典的使用場景是為每個線程分配一個 JDBC 連接 Connection躺翻。這樣就可以保證每個線程的都在各自的 Connection 上進行數(shù)據(jù)庫的操作丧叽,不會出現(xiàn) A 線程關(guān)了 B線程正在使用的 Connection; 還有 Session 管理 等問題公你。

  1. ThreadLocal 與 Synchronized區(qū)別

相同:ThreadLocal和線程同步機制都是為了解決多線程中相同變量的訪問沖突問題踊淳。
不同:Synchronized同步機制采用了“以時間換空間”的方式,僅提供一份變量陕靠,讓不同的線程排隊訪問迂尝;而ThreadLocal采用了“以空間換時間”的方式,每一個線程都提供了一份變量剪芥,因此可以同時訪問而互不影響垄开。
以時間換空間->即枷鎖方式,某個區(qū)域代碼或變量只有一份節(jié)省了內(nèi)存税肪,但是會形成很多線程等待現(xiàn)象溉躲,因此浪費了時間而節(jié)省了空間。
以空間換時間->為每一個線程提供一份變量寸认,多開銷一些內(nèi)存签财,但是呢線程不用等待,可以一起執(zhí)行而相互之間沒有影響偏塞。

小結(jié):ThreadLocal是解決線程安全問題一個很好的思路唱蒸,它通過為每個線程提供一個獨立的變量副本解決了變量并發(fā)訪問的沖突問題。在很多情況下灸叼,ThreadLocal比直接使用synchronized同步機制解決線程安全問題更簡單神汹,更方便,且結(jié)果程序擁有更高的并發(fā)性古今。

說一下 synchronized 底層實現(xiàn)原理屁魏?(待補充)

synchronized關(guān)鍵字作用于Java對象、方法捉腥、代碼塊提供線程安全的操作氓拼。它屬于獨占式的悲觀鎖,同時屬于可重入鎖抵碟。

  • 在它修飾對象時桃漾,同一時刻只能有一個線程對該對象進行訪問。
  • 在它修飾方法拟逮、代碼塊時撬统,同一時刻只能有一個線程執(zhí)行該方法或者代碼塊。

synchronized敦迄、volatile 恋追、Lock凭迹、ReentrantLock 區(qū)別是什么?

  1. 并發(fā)編程中的三個概念:
  • 原子性:即一個操作或者多個操作要么全部執(zhí)行并且執(zhí)行的過程不會被任何因素打斷苦囱,要么就都不執(zhí)行嗅绸。
  • 可見性:是指當多個線程訪問同一個變量時,一個線程修改了這個變量的值沿彭,其他線程能夠立即看得到修改的值朽砰。
  • 有序性:即程序執(zhí)行的順序按照代碼的先后順序執(zhí)行。
  1. 指令重排序

一般來說喉刘,處理器為了提高程序運行效率瞧柔,可能會對輸入代碼進行優(yōu)化,它不保證程序中各個語句的執(zhí)行先后順序同代碼中的順序一致睦裳,但是它會保證程序最終執(zhí)行結(jié)果和代碼順序執(zhí)行的結(jié)果是一致的造锅。

  1. 在java內(nèi)存模型中,也會存在緩存一致性問題和指令重排序的問題廉邑。

Java內(nèi)存模型規(guī)定所有的變量都是存在主存當中(類似于前面說的物理內(nèi)存)哥蔚,每個線程都有自己的工作內(nèi)存(java棧中的幀)(類似于高速緩存)。線程對變量的所有操作都必須在工作內(nèi)存中進行蛛蒙,而不能直接對主存進行操作糙箍。并且每個線程不能訪問其他線程的工作內(nèi)存。
Java內(nèi)存模型只保證了基本讀取和賦值是原子性操作牵祟,如果要實現(xiàn)更大范圍操作的原子性深夯,可以通過synchronized和Lock來實現(xiàn)。

  1. 同步的概念:

Java中的同步是指通過人為的控制和調(diào)度诺苹,保證共享資源在多線程訪問下是安全的咕晋,即保證結(jié)果是正確的。

volatile

  • volatile 是一個類型修飾符收奔。volatile 的作用是作為指令關(guān)鍵字掌呜,確保本條指令不會因編譯器的優(yōu)化而省略.
    volatile 的特性保證了不同線程對這個變量進行操作時的可見性,即一個線程修改了某個變量的值坪哄,這新值對其他線程來說是立即可見的质蕉。(實現(xiàn)可見性)
    禁止進行指令重排序。(實現(xiàn)有序性)
  • volatile 只能保證對單次讀/寫的原子性翩肌。i++ 這種操作不能保證原子性模暗。
    關(guān)于volatile 原子性可以理解為把對volatile變量的單個讀/寫,看成是使用同一個鎖對這些單個讀/寫操作做了同步摧阅。
  • volatile沒辦法保證對變量的操作的原子性。保證原子性操作:采用synchronized绷蹲,采用Lock棒卷,采用AtomicInteger顾孽。使用volatile必須具備以下2個條件【保證原子性】:1)對變量的寫操作不依賴于當前值。2)該變量沒有包含在具有其他變量的不變式中比规。

volatile 與 synchronized對比:

  1. volatile本質(zhì)是在告訴jvm當前變量在寄存器中的值是不確定的,需要從主存中讀取,synchronized則是鎖定當前變量,只有當前線程可以訪問該變量,其他線程被阻塞住.
  2. volatile僅能使用在變量級別,synchronized則可以使用在變量,方法.
  3. volatile僅能實現(xiàn)變量的修改可見性,而synchronized則可以保證變量的修改可見性和原子性.
      《Java編程思想》上說若厚,定義long或double變量時,如果使用volatile關(guān)鍵字蜒什,就會獲得(簡單的賦值與返回操作)原子性测秸。
  4. volatile不會造成線程的阻塞,而synchronized可能會造成線程的阻塞.
  5. 當一個域的值依賴于它之前的值時,volatile就無法工作了灾常,如n=n+1,n++等霎冯。如果某個域的值受到其他域的值的限制,那么volatile也無法工作钞瀑,如Range類的lower和upper邊界沈撞,必須遵循lower<=upper的限制。
  6. 使用volatile而不是synchronized的唯一安全的情況是類中只有一個可變的域雕什。

synchronized和Lock區(qū)別

  1. Lock是一個接口缠俺,而synchronized是Java中的關(guān)鍵字,synchronized是內(nèi)置的語言實現(xiàn)贷岸;
  2. synchronized在發(fā)生異常時壹士,會自動釋放線程占有的鎖,因此不會導致死鎖現(xiàn)象發(fā)生偿警;而Lock在發(fā)生異常時躏救,如果沒有主動通過unLock()去釋放鎖,則很可能造成死鎖現(xiàn)象户敬,因此使用Lock時需要在finally塊中釋放鎖落剪;
  3. Lock可以讓等待鎖的線程響應(yīng)中斷,而synchronized卻不行尿庐,使用synchronized時忠怖,等待的線程會一直等待下去,不能夠響應(yīng)中斷抄瑟;
  4. synchronized不需要用戶去手動釋放鎖凡泣,當synchronized方法或者synchronized代碼塊執(zhí)行完之后,系統(tǒng)會自動讓線程釋放對鎖的占用皮假;而Lock則必須要用戶去手動釋放鎖鞋拟,如果沒有主動釋放鎖,就有可能導致出現(xiàn)死鎖現(xiàn)象惹资。
    通過Lock可以知道有沒有成功獲取鎖贺纲,而synchronized卻無法辦到。
  5. Lock可以提高多個線程進行讀操作的效率褪测。
  6. 在性能上來說猴誊,如果競爭資源不激烈潦刃,兩者的性能是差不多的,而當競爭資源非常激烈時(即有大量線程同時競爭)懈叹,此時Lock的性能要遠遠優(yōu)于synchronized乖杠。所以說,在具體使用時要根據(jù)適當情況選擇澄成。

synchronized和ReentrantLock區(qū)別

相似點:

這兩種同步方式有很多相似之處胧洒,它們都是加鎖方式同步,而且都是阻塞式的同步墨状,也就是說當如果一個線程獲得了對象鎖卫漫,進入了同步塊,其他訪問該同步塊的線程都必須阻塞在同步塊外面等待歉胶,而進行線程阻塞和喚醒的代價是比較高的(操作系統(tǒng)需要在用戶態(tài)與內(nèi)核態(tài)之間來回切換汛兜,代價很高,不過可以通過對鎖優(yōu)化進行改善)通今。

功能區(qū)別:

這兩種方式最大區(qū)別就是對于Synchronized來說粥谬,它是java語言的關(guān)鍵字,是原生語法層面的互斥辫塌,需要jvm實現(xiàn)漏策。而ReentrantLock它是JDK 1.5之后提供的API層面的互斥鎖,需要lock()和unlock()方法配合try/finally語句塊來完成

便利性:

很明顯Synchronized的使用比較方便簡潔臼氨,并且由編譯器去保證鎖的加鎖和釋放掺喻,而ReenTrantLock需要手工聲明來加鎖和釋放鎖,為了避免忘記手工釋放鎖造成死鎖储矩,所以最好在finally中聲明釋放鎖感耙。

鎖的細粒度和靈活度:

很明顯ReenTrantLock優(yōu)于Synchronized

性能的區(qū)別:

在Synchronized優(yōu)化以前,synchronized的性能是比ReenTrantLock差很多的持隧,但是自從Synchronized引入了偏向鎖即硼,輕量級鎖(自旋鎖)后,兩者的性能就差不多了屡拨,在兩種方法都可用的情況下只酥,官方甚至建議使用synchronized,其實synchronized的優(yōu)化我感覺就借鑒了ReenTrantLock中的CAS技術(shù)呀狼。都是試圖在用戶態(tài)就把加鎖問題解決裂允,避免進入內(nèi)核態(tài)的線程阻塞。

ReentrantLock

由于ReentrantLock是java.util.concurrent包下提供的一套互斥鎖哥艇,相比Synchronized绝编,ReentrantLock類提供了一些高級功能,主要有以下3項:

  1. 等待可中斷,持有鎖的線程長期不釋放的時候十饥,正在等待的線程可以選擇放棄等待怎棱,這相當于Synchronized來說可以避免出現(xiàn)死鎖的情況。通過lock.lockInterruptibly()來實現(xiàn)這個機制绷跑。
  2. 公平鎖,多個線程等待同一個鎖時凡资,必須按照申請鎖的時間順序獲得鎖砸捏,Synchronized鎖非公平鎖,ReentrantLock默認的構(gòu)造函數(shù)是創(chuàng)建的非公平鎖隙赁,可以通過參數(shù)true設(shè)為公平鎖垦藏,但公平鎖表現(xiàn)的性能不是很好。
    公平鎖伞访、非公平鎖的創(chuàng)建方式:
//創(chuàng)建一個非公平鎖掂骏,默認是非公平鎖
Lock lock = new ReentrantLock();
Lock lock = new ReentrantLock(false);
 
//創(chuàng)建一個公平鎖,構(gòu)造傳參true
Lock lock = new ReentrantLock(true);
  1. 鎖綁定多個條件厚掷,一個ReentrantLock對象可以同時綁定對個對象弟灼。ReenTrantLock提供了一個Condition(條件)類,用來實現(xiàn)分組喚醒需要喚醒的線程們冒黑,而不是像synchronized要么隨機喚醒一個線程要么喚醒全部線程田绑。

對象拷貝

為什么要使用克隆抡爹?

如何實現(xiàn)對象克卵谇?

深拷貝和淺拷貝區(qū)別是什么冬竟?


Java Web

jsp 和 servlet 有什么區(qū)別欧穴?

session 和 cookie 有什么區(qū)別?

  1. cookie
    由于HTTP是一種無狀態(tài)的協(xié)議泵殴,服務(wù)器單從網(wǎng)絡(luò)連接上無從知道客戶身份涮帘。怎么辦呢?就給客戶端們頒發(fā)一個通行證吧袋狞,每人一個焚辅,無論誰訪問都必須攜帶自己通行證。這樣服務(wù)器就能從通行證上確認客戶身份了苟鸯。這就是Cookie的工作原理同蜻。
    Cookie實際上是一小段的文本信息≡绱Γ客戶端請求服務(wù)器湾蔓,如果服務(wù)器需要記錄該用戶狀態(tài),就使用response向客戶端瀏覽器頒發(fā)一個Cookie砌梆∧穑客戶端瀏覽器會把Cookie保存起來贬循。當瀏覽器再請求該網(wǎng)站時,瀏覽器把請求的網(wǎng)址連同該Cookie一同提交給服務(wù)器桃序。服務(wù)器檢查該Cookie杖虾,以此來辨認用戶狀態(tài)。服務(wù)器還可以根據(jù)需要修改Cookie的內(nèi)容媒熊。
  2. session
    Session是另一種記錄客戶狀態(tài)的機制奇适,不同的是Cookie保存在客戶端瀏覽器中,而Session保存在服務(wù)器上芦鳍∪峦客戶端瀏覽器訪問服務(wù)器的時候,服務(wù)器把客戶端信息以某種形式記錄在服務(wù)器上柠衅。這就是Session皮仁。客戶端瀏覽器再次訪問時只需要從該Session中查找該客戶的狀態(tài)就可以了菲宴。
    如果說Cookie機制是通過檢查客戶身上的“通行證”來確定客戶身份的話贷祈,那么Session機制就是通過檢查服務(wù)器上的“客戶明細表”來確認客戶身份。Session相當于程序在服務(wù)器上建立的一份客戶檔案喝峦,客戶來訪的時候只需要查詢客戶檔案表就可以了付燥。

提示:Session的使用比Cookie方便,但是過多的Session存儲在服務(wù)器內(nèi)存中愈犹,會對服務(wù)器造成壓力键科。

  1. 區(qū)別
  • cookie數(shù)據(jù)存放在客戶的瀏覽器上,session數(shù)據(jù)放在服務(wù)器上.
  • cookie不是很安全漩怎,別人可以分析存放在本地的COOKIE并進行COOKIE欺騙考慮到安全應(yīng)當使用session勋颖。
  • 設(shè)置cookie時間可以使cookie過期。但是使用session-destory()勋锤,我們將會銷毀會話饭玲。
  • session會在一定時間內(nèi)保存在服務(wù)器上。當訪問增多叁执,會比較占用你服務(wù)器的性能考慮到減輕服務(wù)器性能方面茄厘,應(yīng)當使用cookie。
  • 單個cookie保存的數(shù)據(jù)不能超過4K谈宛,很多瀏覽器都限制一個站點最多保存20個cookie次哈。(Session對象沒有對存儲的數(shù)據(jù)量的限制,其中可以保存更為復雜的數(shù)據(jù)類型)

注意:
1.session很容易失效,用戶體驗很差;
2.雖然cookie不安全,但是可以加密 ;
3.cookie也分為永久和暫時存在的;
4.瀏覽器 有禁止cookie功能 ,但一般用戶都不會設(shè)置;
5.一定要設(shè)置失效時間,要不然瀏覽器關(guān)閉就消失了;
例如:
記住密碼功能就是使用永久cookie寫在客戶端電腦吆录,下次登錄時窑滞,自動將cookie信息附加發(fā)送給服務(wù)端。
application是全局性信息,是所有用戶共享的信息哀卫,如可以記錄有多少用戶現(xiàn)在登錄過本網(wǎng)站丽涩,并把該信息展示個所有用戶萄唇。
兩者最大的區(qū)別在于生存周期汞窗,一個是IE啟動到IE關(guān)閉.(瀏覽器頁面一關(guān) ,session就消失了)屎勘,一個是預(yù)先設(shè)置的生存周期,或永久的保存于本地的文件共啃。(cookie)

說一下 session 的工作原理鼓寺?

如果客戶端禁止 cookie 能實現(xiàn) session 還能用嗎?

一般默認情況下勋磕,在會話中,服務(wù)器存儲 session 的 sessionid 是通過 cookie 存到瀏覽器里敢靡。

如果瀏覽器禁用了 cookie挂滓,瀏覽器請求服務(wù)器無法攜帶 sessionid,服務(wù)器無法識別請求中的用戶身份啸胧,session失效赶站。

但是可以通過其他方法在禁用 cookie 的情況下,可以繼續(xù)使用session:

  • 通過url重寫纺念,把 sessionid 作為參數(shù)追加的原 url 中贝椿,后續(xù)的瀏覽器與服務(wù)器交互中攜帶 sessionid 參數(shù)。
  • 服務(wù)器的返回數(shù)據(jù)中包含 sessionid陷谱,瀏覽器發(fā)送請求時烙博,攜帶 sessionid 參數(shù)。
  • 通過 Http 協(xié)議其他 header 字段烟逊,服務(wù)器每次返回時設(shè)置該 header 字段信息渣窜,瀏覽器中 js 讀取該 header 字段,請求服務(wù)器時宪躯,js設(shè)置攜帶該 header 字段乔宿。

spring mvc 和 struts 的區(qū)別是什么?

如何避免 sql 注入访雪?

什么是 XSS 攻擊详瑞,如何避免?

什么是 CSRF 攻擊臣缀,如何避免坝橡?


異常

throw 和 throws 的區(qū)別?

  • throw:

表示方法內(nèi)拋出某種異常對象
如果異常對象是非 RuntimeException 則需要在方法申明時加上該異常的拋出 即需要加上 throws 語句 或者 在方法體內(nèi) try catch 處理該異常精置,否則編譯報錯
執(zhí)行到 throw 語句則后面的語句塊不再執(zhí)行

  • throws:

方法的定義上使用 throws 表示這個方法可能拋出某種異常
需要由方法的調(diào)用者進行異常處理

final驳庭、finally、finalize 有什么區(qū)別?

final可以用來修飾類饲常、方法蹲堂、變量,分別有不同的意義所在贝淤,final修飾的class代表不可繼續(xù)擴展柒竞,final修飾的變量代表不可修改,final修飾的方法代表不可重寫播聪。

finally則是java保證某一段重點代碼一定要被執(zhí)行的修飾符朽基,例如:我們需要用try塊讓JDBC保證連接,保證unlock鎖等動作

finalize是基礎(chǔ)類java.lang.Object的一個方法离陶,它的設(shè)計目的是為了保證對象在垃圾回收之前完成特定資源的回收

try-catch-finally 中哪個部分可以省略稼虎?

try-catch-finally 中,如果 catch 中 return 了招刨,finally 還會執(zhí)行嗎霎俩?

常見的異常類有哪些?


網(wǎng)絡(luò)

http 響應(yīng)碼 301 和 302 代表的是什么沉眶?有什么區(qū)別打却?

  • 301 Moved Permanently

被請求的資源已永久移動到新位置,并且將來任何對此資源的引用都應(yīng)該使用本響應(yīng)返回的若干個 URI 之一谎倔。如果可能柳击,擁有鏈接編輯功能的客戶端應(yīng)當自動把請求的地址修改為從服務(wù)器反饋回來的地址。除非額外指定片习,否則這個響應(yīng)也是可緩存的捌肴。

  • 302 Found

請求的資源現(xiàn)在臨時從不同的 URI 響應(yīng)請求。由于這樣的重定向是臨時的藕咏,客戶端應(yīng)當繼續(xù)向原有地址發(fā)送以后的請求哭靖。只有在Cache-Control或Expires中進行了指定的情況下,這個響應(yīng)才是可緩存的侈离。

forward 和 redirect 的區(qū)別试幽?

tcp三次握手

image

字段 含義
URG 緊急指針是否有效。為1卦碾,表示某一位需要被優(yōu)先處理
ACK 確認號是否有效铺坞,一般置為1。
PSH 提示接收端應(yīng)用程序立即從TCP緩沖區(qū)把數(shù)據(jù)讀走洲胖。
RST 對方要求重新建立連接济榨,復位。
SYN 請求建立連接绿映,并在其序列號的字段進行序列號的初始值設(shè)定擒滑。建立連接腐晾,設(shè)置為1
FIN 希望斷開連接。

image

一次握手:建立連接時丐一,客戶端發(fā)送syn包(syn=x)到服務(wù)器藻糖,并進入SYN_SENT狀態(tài),等待服務(wù)器確認库车;SYN:同步序列編號(Synchronize Sequence Numbers)巨柒。

第二次握手:服務(wù)器收到syn包,必須確認客戶的SYN(ack=x+1)柠衍,同時自己也發(fā)送一個SYN包(syn=y)洋满,即SYN+ACK包,此時服務(wù)器進入SYN_RECV狀態(tài)珍坊;

第三次握手:客戶端收到服務(wù)器的SYN+ACK包牺勾,向服務(wù)器發(fā)送確認包ACK(ack=y+1),此包發(fā)送完畢阵漏,客戶端和服務(wù)器進入ESTABLISHED(TCP連接成功)狀態(tài)驻民,完成三次握手。

tcp 為什么要三次握手袱饭,兩次不行嗎?為什么呛占?

TCP,UDP區(qū)別虑乖?

  • TCP 是可靠通信協(xié)議, 而 UDP 是不可靠通信協(xié)議晾虑。

TCP 的可靠性含義: 接收方收到的數(shù)據(jù)是完整疹味, 有序, 無差錯的帜篇。
UDP 不可靠性含義: 接收方接收到的數(shù)據(jù)可能存在部分丟失糙捺, 順序也不一定能保證。
UDP 和 TCP 協(xié)議都是基于同樣的互聯(lián)網(wǎng)基礎(chǔ)設(shè)施笙隙, 且都基于 IP 協(xié)議實現(xiàn)洪灯, 互聯(lián)網(wǎng)基礎(chǔ)設(shè)施中對于數(shù)據(jù)包的發(fā)送過程是會發(fā)生丟包現(xiàn)象的, 為什么 TCP 就可以實現(xiàn)可靠傳輸竟痰, 而 UDP 不行签钩?

TCP 協(xié)議為了實現(xiàn)可靠傳輸, 通信雙方需要判斷自己已經(jīng)發(fā)送的數(shù)據(jù)包是否都被接收方收到坏快, 如果沒收到铅檩, 就需要重發(fā)。 為了實現(xiàn)這個需求莽鸿, 很自然地就會引出序號(sequence number) 和 確認號(acknowledgement number) 的使用昧旨。

發(fā)送方在發(fā)送數(shù)據(jù)包(假設(shè)大小為 10 byte)時拾给, 同時送上一個序號( 假設(shè)為 500),那么接收方收到這個數(shù)據(jù)包以后兔沃, 就可以回復一個確認號(510 = 500 + 10) 告訴發(fā)送方 “我已經(jīng)收到了你的數(shù)據(jù)包蒋得, 你可以發(fā)送下一個數(shù)據(jù)包, 序號從 510 開始” 粘拾。

這樣發(fā)送方就可以知道哪些數(shù)據(jù)被接收到窄锅,哪些數(shù)據(jù)沒被接收到, 需要重發(fā)缰雇。

說一下 tcp 粘包是怎么產(chǎn)生的入偷?

  1. TCP粘包是什么?
    粘包發(fā)生在發(fā)送或接收緩沖區(qū)中械哟;應(yīng)用程序從緩沖區(qū)中取數(shù)據(jù)是整個緩沖區(qū)中有多少取多少疏之;那么就有可能第一個數(shù)據(jù)的尾部和第二個數(shù)據(jù)的頭部同時存在緩沖區(qū),而TCP是流式的暇咆,數(shù)據(jù)無邊界锋爪,這時發(fā)生粘包。


    image
  2. TCP粘包的產(chǎn)生
    2.1 發(fā)送方產(chǎn)生粘包
    采用TCP協(xié)議傳輸數(shù)據(jù)的客戶端與服務(wù)器經(jīng)常是保持一個長連接的狀態(tài)(一次連接發(fā)一次數(shù)據(jù)不存在粘包)爸业,雙方在連接不斷開的情況下其骄,可以一直傳輸數(shù)據(jù);但當發(fā)送的數(shù)據(jù)包過于的小時扯旷,那么TCP協(xié)議默認的會啟用Nagle算法拯爽,將這些較小的數(shù)據(jù)包進行合并發(fā)送(緩沖區(qū)數(shù)據(jù)發(fā)送是一個堆壓的過程);這個合并過程就是在發(fā)送緩沖區(qū)中進行的钧忽,也就是說數(shù)據(jù)發(fā)送出來它已經(jīng)是粘包的狀態(tài)了毯炮;


    image

    2.2 接收方產(chǎn)生粘包
    接收方采用TCP協(xié)議接收數(shù)據(jù)時的過程是這樣的:數(shù)據(jù)到底接收方,從網(wǎng)絡(luò)模型的下方傳遞至傳輸層耸黑,傳輸層的TCP協(xié)議處理是將其放置接收緩沖區(qū)桃煎,然后由應(yīng)用層來主動獲取(C語言用recv大刊、read等函數(shù))为迈;這時會出現(xiàn)一個問題,就是我們在程序中調(diào)用的讀取數(shù)據(jù)函數(shù)不能及時的把緩沖區(qū)中的數(shù)據(jù)拿出來缺菌,而下一個數(shù)據(jù)又到來并有一部分放入的緩沖區(qū)末尾曲尸,等我們讀取數(shù)據(jù)時就是一個粘包;(放數(shù)據(jù)的速度 > 應(yīng)用層拿數(shù)據(jù)速度)


    image
  3. TCP粘包解決方案
    目前應(yīng)用最廣泛的是在消息的頭部添加數(shù)據(jù)包長度男翰,接收方根據(jù)消息長度進行接收另患;在一條TCP連接上,數(shù)據(jù)的流式傳輸在接收緩沖區(qū)里是有序的蛾绎,其主要的問題就是第一個包的包尾與第二個包的包頭共存接收緩沖區(qū)昆箕,所以根據(jù)長度讀取是十分合適的鸦列;

1.解決發(fā)送方粘包
(1)發(fā)送產(chǎn)生是因為Nagle算法合并小數(shù)據(jù)包,那么可以禁用掉該算法鹏倘;
(2)TCP提供了強制數(shù)據(jù)立即傳送的操作指令push薯嗤,當填入數(shù)據(jù)后調(diào)用操作指令就可以立即將數(shù)據(jù)發(fā)送,而不必等待發(fā)送緩沖區(qū)填充自動發(fā)送纤泵;
(3)數(shù)據(jù)包中加頭骆姐,頭部信息為整個數(shù)據(jù)的長度(最廣泛最常用);
2.解決接收方粘包
(1)解析數(shù)據(jù)包頭部信息捏题,根據(jù)長度來接收玻褪;
(2)自定義數(shù)據(jù)格式:在數(shù)據(jù)中放入開始、結(jié)束標識公荧;解析時根據(jù)格式抓取數(shù)據(jù)带射,缺點是數(shù)據(jù)內(nèi)不能含有開始或結(jié)束標識;
(3)短連接傳輸循狰,建立一次連接只傳輸一次數(shù)據(jù)就關(guān)閉窟社;(不推薦)

OSI 的七層模型都有哪些?

get 和 post 請求有哪些區(qū)別绪钥?

如何實現(xiàn)跨域灿里?

說一下 JSONP 實現(xiàn)原理?

--

設(shè)計模式

  1. 設(shè)計模式7個原則
  • 單一職責原則
    單一職責原則又稱單一功能原則程腹,它規(guī)定一個類只有一個職責匣吊。如果有多個職責(功能)被設(shè)計在一個類中,這個類就違反了單一職責原則跪楞。
  • 開閉原則
    開閉原則規(guī)定軟件中的對象(類缀去、模塊侣灶、函數(shù)等)對擴展開放甸祭,對修改開閉,這意味著一個實體允許在不改變其源代碼的前提下改變其行為褥影,該特性在產(chǎn)品化的環(huán)境下是特別有價值的池户,在這種環(huán)境下,改變源代碼需要經(jīng)過代碼審查凡怎、單元測試等過程校焦,以確保產(chǎn)品的使用質(zhì)量。遵循這個原則的代碼在擴展時不會發(fā)生改變统倒,因此不需要經(jīng)歷上述過程寨典。
  • 里氏替換原則
    里氏替換原則是對開閉原則的補充,規(guī)定了在任意父類可以出現(xiàn)的地方房匆,子類都一定可以出現(xiàn)耸成。實現(xiàn)開閉原則的關(guān)鍵是抽象化报亩,父類與子類的繼承關(guān)系就是抽象化的具體表現(xiàn),所以里氏替換原則是對實現(xiàn)抽象化的具體步驟規(guī)范井氢。
  • 依賴倒換原則
    依賴倒換原則指程序要依賴于對象(比如JAVA中的抽象類和接口)弦追,而不依賴于具體的實現(xiàn)。簡單地說花竞,就是基于抽象進行編程劲件,不要求對實現(xiàn)進行編程,這就降低了模塊之間的耦合度约急。
  • 接口隔離原則
    接口隔離原則指通過將不同的功能定義在不同的接口中來實現(xiàn)接口的隔離零远,這樣就避免了其他類在依賴該接口時(接口上定義的功能)依賴其不需要的接口,可減少接口之前的依賴冗余性和復雜性烤宙。
  • 合成遍烦、聚合復用原則
    合成、聚合復用原則指通過一個在新的對象引入(注入)已有的對象以達到累的功能復用和擴展的目的躺枕。它的設(shè)計原則是要盡量使用合成或聚合服猪,而不要使用繼承來擴展類的功能。
  • 迪米特法則
    迪米特法則指一個對象盡可能少地與其他對象發(fā)生相互作用拐云,即一個對象對其他對象應(yīng)該有盡可能少的了解或依賴罢猪。其核心思想在于降低模塊之間的耦合度,提高模塊的內(nèi)聚性叉瘩。迪米特法則容易使系統(tǒng)模塊之間功能獨立膳帕,使得各個模塊的獨立運行變得更簡單,同時使得各個模塊之間的組合變得更容易薇缅。
  1. 三大類設(shè)計模式
  • 創(chuàng)建型模式

工廠模式
抽象工廠模式
單例模式

懶漢模式->雙重校驗鎖
餓漢模式

建造者模式
原型模式

  • 結(jié)構(gòu)性模式

適配器模式
橋接模式
過濾器模式
組合模式
裝飾器模式
外觀模式
亨元模式
代理模式

  • 行為型模式

責任鏈模式
命令模式
解釋器模式
迭代器模式
中介者模式
備忘錄模式
觀察則模式
狀態(tài)模式
策略模式
模板模式
訪問者模式


Spring

為什么要使用 spring危彩?

解釋一下什么是 aop?

解釋一下什么是 ioc泳桦?

Inversion of Control

Spring的控制反轉(zhuǎn)指一個對象依賴的其他對象會在容器的初始化完成后主動將其依賴的對象傳遞給它汤徽,而不需要這個對象自己創(chuàng)建或者查找其依賴的對象。Spring中的實例對象可以使全局唯一的單例模式灸撰,也可以在每次需要時都重新生成一個新的實例谒府,具體可以哪種方式創(chuàng)建Bean的生命周期決定,通過protoType屬性來定義浮毯。

spring 有哪些主要模塊完疫?

  1. 核心容器層
  • Spring-Beans
  • Spring-Core
  • Spring-Context
  • SpEL
    SpEL模塊提供了豐富的表達式語言支持,用于在運行過程中查詢和操作對象實例债蓝。SpEL在JSP 2.1表達式語言規(guī)范的基礎(chǔ)上進行了擴展壳鹤,支持set、get方法饰迹、屬性賦值芳誓、方法調(diào)用讯嫂、訪問數(shù)組集合、索引內(nèi)容兆沙、邏輯算術(shù)運算欧芽、明明變量、基于名稱在Spring IoC容器檢索對象葛圃,同時支持列表的投影千扔、選擇和聚合等功能。
  1. 數(shù)據(jù)訪問層
  • JDBC
  • ORM(Object Relational Mapping)
    ORM模塊提供了對象關(guān)系映射API的集成库正,包括JPA曲楚、JDO和Hibernate等∪旆基于該模塊龙誊,ORM框架能很容易地和Spring的其他功能整合,例如事務(wù)管理喷楣。
  • OXM
    OXM模塊提供了對OXM實現(xiàn)的支持趟大,比如JAXB、Castor铣焊、XML Beans逊朽、JiBX、XStream等曲伊。
  • JMS
    JMS模塊包含消息的生產(chǎn)叽讳、消費功能。從Spring4.1開始坟募,Spring集成了Spring-Messaging模塊岛蚤,用于實現(xiàn)對消息隊列的支持。
  • 事務(wù)處理
  1. web應(yīng)用層
  • Web
    Web模塊不但提供了面向Web應(yīng)用的基本功能懈糯,還提供了HTTP客戶端及Spring遠程調(diào)用中與Web相關(guān)的部分涤妒。
    Web模塊基于Servlet監(jiān)聽器初始化IoC容器。
  • Web-MVC
    Web-MVC模塊為Web應(yīng)用提供了模型視圖控制和REST API服務(wù)的實現(xiàn)昂利。Spring的MVC框架使數(shù)據(jù)模型和視圖分離届腐,數(shù)據(jù)模型負責數(shù)據(jù)的業(yè)務(wù)邏輯铁坎,視圖負責數(shù)據(jù)的展示蜂奸。同時,Web-MVC可與Spring框架的其他模塊方便地集成硬萍。
  • Web-Socket
  • Web-Portlet
  1. 其他重要模塊
  • AOP
  • Aspects
  • Instrumentation
  • Messaging
  • Test

spring 常用的注入方式有哪些扩所?

  1. 構(gòu)造方法注入
  2. set注入
  3. 注解注入

spring 中的 bean 是線程安全的嗎?

結(jié)論: 不是線程安全的

Spring容器中的Bean是否線程安全朴乖,容器本身并沒有提供Bean的線程安全策略祖屏,因此可以說Spring容器中的Bean本身不具備線程安全的特性助赞,但是具體還是要結(jié)合具體scope的Bean去研究。
Spring 的 bean 作用域(scope)類型:

  1. singleton:單例袁勺,默認作用域雹食。
  2. prototype:原型,每次創(chuàng)建一個新對象期丰。
  3. request:請求群叶,每次Http請求創(chuàng)建一個新對象,適用于WebApplicationContext環(huán)境下钝荡。
  4. session:會話街立,同一個會話共享一個實例,不同會話使用不用的實例埠通。
  5. global-session:全局會話赎离,所有會話共享一個實例。

線程安全這個問題端辱,要從單例與原型Bean分別進行說明梁剔。
原型Bean

對于原型Bean,每次創(chuàng)建一個新對象,也就是線程之間并不存在Bean共享舞蔽,自然是不會有線程安全的問題憾朴。

單例Bean

對于單例Bean,所有線程都共享一個單例實例Bean,因此是存在資源的競爭。
如果單例Bean,是一個無狀態(tài)Bean喷鸽,也就是線程中的操作不會對Bean的成員執(zhí)行查詢以外的操作熔恢,那么這個單例Bean是線程安全的岔帽。比如Spring mvc 的 Controller、Service、Dao等蜕窿,這些Bean大多是無狀態(tài)的,只關(guān)注于方法本身狰贯。

注:
有狀態(tài)就是有數(shù)據(jù)存儲功能
無狀態(tài)就是不會保存數(shù)據(jù)

spring 支持幾種 bean 的作用域歼跟?

見上邊問題

spring 自動裝配 bean 有哪些方式?

  • no:默認方式声登,手動裝配方式狠鸳,需要通過ref設(shè)定bean的依賴關(guān)系
  • byName:根據(jù)bean的名字進行裝配,當一個bean的名稱和其他bean的屬性一致悯嗓,則自動裝配
  • byType:根據(jù)bean的類型進行裝配件舵,當一個bean的屬性類型與其他bean的屬性的數(shù)據(jù)類型一致,則自動裝配
  • constructor:根據(jù)構(gòu)造器進行裝配脯厨,與 byType 類似铅祸,如果bean的構(gòu)造器有與其他bean類型相同的屬性,則進行自動裝配
  • autodetect:如果有默認構(gòu)造器,則以constructor方式進行裝配临梗,否則以byType方式進行裝配

spring 事務(wù)實現(xiàn)方式有哪些涡扼?

Spring提供了編程式事務(wù)和聲明式事務(wù)兩種實現(xiàn)方式。

  • 編程式事務(wù)允許用戶在代碼中精確定義事務(wù)的邊界盟庞,
  • 聲明式事務(wù)(基于AOP)有助于用戶將操作與事務(wù)規(guī)則進行解耦吃沪。

簡單地說,編程式事務(wù)侵入到了業(yè)務(wù)代碼里面什猖,但是提供了更加詳細的事務(wù)管理巷波;
而聲明式事務(wù)由于基于AOP,所以既能起到事務(wù)管理的作用卸伞,又可以不影響業(yè)務(wù)代碼的具體實現(xiàn)抹镊。

說一下 spring 的事務(wù)隔離?

spring 有五大隔離級別

  • 默認值為 ISOLATION_DEFAULT(使用數(shù)據(jù)庫的設(shè)置)荤傲,其他四個隔離級別和數(shù)據(jù)庫的隔離級別一致 (越往下隔離級別越高垮耳,花費越大):
  • read uncommited 未提交讀:是最低的事務(wù)隔離級別。事務(wù)未提交前遂黍,數(shù)據(jù)就可被其他事務(wù)讀取 --> 會造成:臟讀终佛、不可重復讀、幻讀
  • read commited 提交讀:一個事務(wù)提交后才能被其他事務(wù)讀取到雾家,SQL server 的默認級別 --> 會造成:不可重復讀铃彰、幻讀
  • repeatable read 可重復讀:保證多次讀取同一個數(shù)據(jù)時,其值都和事務(wù)開始時候的內(nèi)容是一致芯咧,禁止讀取到別的事務(wù)未提交的數(shù)據(jù)牙捉,MySQL 的默認級別 --> 會造成: 幻讀。
  • serializable 序列化:這是花費最高代價但最可靠的事務(wù)隔離級別敬飒。事務(wù)被處理為順序執(zhí)行邪铲。該隔離級別能防止臟讀、不可重復讀无拗、幻讀带到。
  • 臟讀:表示一個事務(wù)能夠讀取另一個事務(wù)中還未提交的數(shù)據(jù)。比如英染,某個事務(wù)嘗試插入記錄 A揽惹,此時該事務(wù)還未提交,然后另一個事務(wù)嘗試讀取到了記錄 A四康。因為這個記錄 A還沒有提交那么另外一個事務(wù)讀取到的這個數(shù)據(jù)我們稱之為臟數(shù)據(jù)搪搏。依據(jù)臟數(shù)據(jù)所做的操作肯能是不正確的。
  • 不可重復讀:指在一個事務(wù)內(nèi)箭养,多次讀同一數(shù)據(jù)慕嚷,但不一樣哥牍。例如毕泌,事務(wù)1 讀取 記錄A喝检, 事務(wù)1 還沒有執(zhí)行結(jié)束;此時另外一個 事務(wù)2 也訪問 記錄A撼泛,并修改了記錄A挠说。 那么在事務(wù)1 第兩次讀取記錄A時,讀到的數(shù)據(jù)可能是不一樣的愿题。這種情況被稱為是不可重復讀损俭。
  • 幻象讀:指同一個事務(wù)內(nèi)多次查詢返回的結(jié)果集不一樣。比如同一個事務(wù) A 第一次查詢時候有 n 條記錄潘酗,但是第二次同等條件下查詢卻有 n+1 條記錄杆兵,這就好像產(chǎn)生了幻覺。發(fā)生幻讀的原因也是另外一個事務(wù)新增或者刪除或者修改了第一個事務(wù)結(jié)果集里面的數(shù)據(jù)仔夺,同一個記錄的數(shù)據(jù)內(nèi)容被修改了琐脏,所有數(shù)據(jù)行的記錄就變多或者變少了。

說一下 spring mvc 運行流程缸兔?

image

執(zhí)行流程:

  1. 用戶向服務(wù)器發(fā)送請求日裙,請求被 Spring 前端控制 Servelt DispatcherServlet 捕獲(捕獲)
  2. DispatcherServlet對請求 URL進行解析,得到請求資源標識符(URI)惰蜜。然后根據(jù)該 URI昂拂,調(diào)用 HandlerMapping獲得該Handler配置的所有相關(guān)的對象(包括 Handler對象以及 Handler對象對應(yīng)的攔截器),最后以 HandlerExecutionChain對象的形式返回抛猖;(查找 handler)
  3. DispatcherServlet 根據(jù)獲得的 Handler格侯,選擇一個合適的 HandlerAdapter。 提取Request 中的模型數(shù)據(jù)财著,填充 Handler 入?yún)⒀唬_始執(zhí)行 Handler(Controller), Handler執(zhí)行完成后,向 DispatcherServlet 返回一個 ModelAndView 對象(執(zhí)行 handler)
  4. DispatcherServlet 根據(jù)返回的 ModelAndView瓢宦,選擇一個適合的 ViewResolver(必須是已經(jīng)注冊到 Spring 容器中的 ViewResolver) (選擇 ViewResolver)
  5. 通過 ViewResolver 結(jié)合 Model 和 View碎连,來渲染視圖,DispatcherServlet 將渲染結(jié)果返回給客戶端。(渲染返回)

快速記憶技巧:

核心控制器捕獲請求驮履、查找Handler鱼辙、執(zhí)行Handler、選擇ViewResolver,通過ViewResolver渲染視圖并返回

spring mvc 有哪些組件玫镐?

@RequestMapping 的作用是什么倒戏?

@Autowired 的作用是什么?


Spring Boot/Spring Cloud

什么是 spring boot恐似?

為什么要用 spring boot杜跷?

spring boot 核心配置文件是什么?

spring boot 配置文件有哪幾種類型?它們有什么區(qū)別葛闷?

spring boot 有哪些方式可以實現(xiàn)熱部署憋槐?

jpa 和 hibernate 有什么區(qū)別?

什么是 spring cloud淑趾?

spring cloud 斷路器的作用是什么阳仔?

spring cloud 的核心組件有哪些?


Hibernate

為什么要使用 hibernate扣泊?

什么是 ORM 框架近范?

對象-關(guān)系映射(Object-Relational Mapping,簡稱ORM)延蟹,面向?qū)ο蟮拈_發(fā)方法是當今企業(yè)級應(yīng)用開發(fā)環(huán)境中的主流開發(fā)方法评矩,關(guān)系數(shù)據(jù)庫是企業(yè)級應(yīng)用環(huán)境中永久存放數(shù)據(jù)的主流數(shù)據(jù)存儲系統(tǒng)。對象和關(guān)系數(shù)據(jù)是業(yè)務(wù)實體的兩種表現(xiàn)形式阱飘,業(yè)務(wù)實體在內(nèi)存中表現(xiàn)為對象稚照,在數(shù)據(jù)庫中表現(xiàn)為關(guān)系數(shù)據(jù)。內(nèi)存中的對象之間存在關(guān)聯(lián)和繼承關(guān)系俯萌,而在數(shù)據(jù)庫中果录,關(guān)系數(shù)據(jù)無法直接表達多對多關(guān)聯(lián)和繼承關(guān)系。因此咐熙,對象-關(guān)系映射(ORM)系統(tǒng)一般以中間件的形式存在弱恒,主要實現(xiàn)程序?qū)ο蟮疥P(guān)系數(shù)據(jù)庫數(shù)據(jù)的映射。

hibernate 中如何在控制臺查看打印的 sql 語句棋恼?

hibernate 有幾種查詢方式返弹?

hibernate 實體類可以被定義為 final 嗎?

在 hibernate 中使用 Integer 和 int 做映射有什么區(qū)別爪飘?

hibernate 是如何工作的义起?

get()和 load()的區(qū)別?

說一下 hibernate 的緩存機制师崎?

hibernate 對象有哪些狀態(tài)默终?

在 hibernate 中 getCurrentSession 和 openSession 的區(qū)別是什么?

hibernate 實體類必須要有無參構(gòu)造函數(shù)嗎犁罩?為什么齐蔽?


Mybatis

mybatis 中 #{}和 ${}的區(qū)別是什么?

mybatis 有幾種分頁方式床估?

RowBounds 是一次性查詢?nèi)拷Y(jié)果嗎含滴?為什么?

mybatis 邏輯分頁和物理分頁的區(qū)別是什么丐巫?

mybatis 是否支持延遲加載谈况?延遲加載的原理是什么勺美?

說一下 mybatis 的一級緩存和二級緩存?

mybatis 和 hibernate 的區(qū)別有哪些碑韵?

mybatis 有哪些執(zhí)行器(Executor)赡茸?

mybatis 分頁插件的實現(xiàn)原理是什么?

mybatis 如何編寫一個自定義插件泼诱?


RabbitMQ

rabbitmq 的使用場景有哪些坛掠?

rabbitmq 有哪些重要的角色赊锚?

rabbitmq 有哪些重要的組件治筒?

rabbitmq 中 vhost 的作用是什么?

rabbitmq 的消息是怎么發(fā)送的舷蒲?

rabbitmq 怎么保證消息的穩(wěn)定性耸袜?

rabbitmq 怎么避免消息丟失?

要保證消息持久化成功的條件有哪些牲平?

rabbitmq 持久化有什么缺點堤框?

rabbitmq 有幾種廣播類型?

rabbitmq 怎么實現(xiàn)延遲消息隊列纵柿?

rabbitmq 集群有什么用蜈抓?

rabbitmq 節(jié)點的類型有哪些?

rabbitmq 集群搭建需要注意哪些問題昂儒?

rabbitmq 每個節(jié)點是其他節(jié)點的完整拷貝嗎沟使?為什么?

rabbitmq 集群中唯一一個磁盤節(jié)點崩潰了會發(fā)生什么情況渊跋?

rabbitmq 對集群節(jié)點停止順序有要求嗎腊嗡?


Kafka

kafka 可以脫離 zookeeper 單獨使用嗎?為什么拾酝?

kafka 有幾種數(shù)據(jù)保留的策略燕少?

kafka 同時設(shè)置了 7 天和 10G 清除數(shù)據(jù),到第五天的時候消息達到了 10G蒿囤,這個時候 kafka 將如何處理客们?

什么情況會導致 kafka 運行變慢?

使用 kafka 集群需要注意什么材诽?


Zookeeper

zookeeper 是什么镶摘?

zookeeper 都有哪些功能?

zookeeper 有幾種部署模式岳守?

zookeeper 怎么保證主從節(jié)點的狀態(tài)同步凄敢?

集群中為什么要有主節(jié)點?

集群中有 3 臺服務(wù)器湿痢,其中一個節(jié)點宕機涝缝,這個時候 zookeeper 還可以使用嗎扑庞?

說一下 zookeeper 的通知機制?


MySql

數(shù)據(jù)庫的三范式是什么拒逮?

一張自增表里面總共有 7 條數(shù)據(jù)罐氨,刪除了最后 2 條數(shù)據(jù),重啟 mysql 數(shù)據(jù)庫滩援,又插入了一條數(shù)據(jù)栅隐,此時 id 是幾?

一般情況下玩徊,我們創(chuàng)建的表的類型是InnoDB租悄,如果新增一條記錄(不重啟mysql的情況下),這條記錄的id是8恩袱;但是如果重啟(文中提到的)MySQL的話泣棋,這條記錄的ID是6。因為InnoDB表只把自增主鍵的最大ID記錄到內(nèi)存中畔塔,所以重啟數(shù)據(jù)庫或者對表OPTIMIZE操作潭辈,都會使最大ID丟失。

但是澈吨,如果我們使用表的類型是MylSAM把敢,那么這條記錄的ID就是8。因為MylSAM表會把自增主鍵的最大ID記錄到數(shù)據(jù)文件里面谅辣,重啟MYSQL后修赞,自增主鍵的最大ID也不會丟失。

注:如果在這7條記錄里面刪除的是中間的幾個記錄(比如刪除的是3,4兩條記錄)屈藐,重啟MySQL數(shù)據(jù)庫后榔组,insert一條記錄后,ID都是8联逻。因為內(nèi)存或者數(shù)據(jù)庫文件存儲都是自增主鍵最大ID

如何獲取當前數(shù)據(jù)庫版本搓扯?

說一下 ACID 是什么?

char 和 varchar 的區(qū)別是什么包归?

float 和 double 的區(qū)別是什么锨推?

mysql 的內(nèi)連接、左連接公壤、右連接有什么區(qū)別换可?

mysql 索引是怎么實現(xiàn)的?

  1. 按表列屬性分類:
  • 單列索引
    以表的單個列字段創(chuàng)建的索引
  • 聯(lián)合索引
    以表的多個列字段組合創(chuàng)建的索引厦幅,在查詢條件使用索引的從左字段順序才會生效沾鳄,遵循最左匹配原則。

單列索引和聯(lián)合索引又包括:

  • 普通索引
    非主鍵确憨,非唯一列的索引
  • 主鍵索引
    基于該表主鍵自動生成成的索引译荞,如果未給表定義主鍵瓤的,會查找該表中是否存在非空、整形吞歼、唯一索引作為其主鍵(可通過select _rowid from 表名查看)圈膏,若都不滿足會隱式生成一個rowid作為主鍵(無法直接查到)
  • 唯一索引
    基于表的唯一列生成的索引,允許為空值
  • 全文索引
    將存儲于數(shù)據(jù)庫中的整本書或整篇文章中任意內(nèi)容信息查找出來篙骡,如大量級的文字中如like %關(guān)鍵字%稽坤,普通索引的效率與全文索引相比是非常低的。
  1. 按數(shù)據(jù)結(jié)構(gòu)分類:
  • B+tree索引
    b+tree基于平衡二叉樹的一種多路平衡查找樹糯俗,所有記錄都按照順序存放在葉子節(jié)點中尿褪,各個葉子節(jié)點直接通過鏈表相連。與b樹不同的是:1叶骨、非葉子節(jié)點只存儲鍵值信息茫多。2祈匙、所有葉子節(jié)點之間都有一個鏈指針忽刽。3、數(shù)據(jù)記錄都存放在葉子節(jié)點中夺欲。
  • hash索引
    基于hash表結(jié)構(gòu)實現(xiàn)的索引跪帝,mysql中只有MEMORY/HEAP和NDB存儲引擎支持;
    InnoDB引擎支持自適應(yīng)hash索引,但是是數(shù)據(jù)庫自身創(chuàng)建使用的些阅,而不能進行人為定義伞剑。當二級索引被頻繁的訪問時,便會自動創(chuàng)建自適應(yīng)哈希索引;
    通過 命令SHOW ENGINE INNODB STATUS可查看自適應(yīng)hash索引的使用情況;
    通過 命令SHOW VARIABLES LIKE '%ap%hash_index' 查看是否打開自適應(yīng)hash索引市埋。

對比:

  • 由于hash索引是比較其hash值黎泣,hash索引只能進行等值查找而不能進行范圍查找
  • hash索引無法進行排序:原因同上
    -> 不支持最左匹配原則,復合索引時合并一起計算hash值
  • hash索引的檢索效率很高可以一次定位缤谎,但是當發(fā)生大量hash碰撞的時候抒倚,鏈表變長,hash索引效率上是不如b+tree的
  • 由于存在hash碰撞的問題坷澡,當需要獲得總數(shù)時候托呕,hash 索引在任何時候都不能避免表掃描
  • T-tree索引
  • R-tree索引
  1. 按存儲結(jié)構(gòu)分類:
  • 聚簇索引(聚集索引)
    InnoDB的聚簇索引實際上是在同一個BTree結(jié)構(gòu)中同時存儲了索引和整行數(shù)據(jù),通過該索引查詢可以直接獲取查詢數(shù)據(jù)行频敛。
    聚簇索引不是一種單獨的索引類型项郊,而是一種數(shù)據(jù)的存儲方式,聚簇索引的順序斟赚,就是數(shù)據(jù)在硬盤上的物理順序着降。
    在mysql通常聚簇索引是主鍵的同義詞,每張表只包含一個聚簇索引(其他數(shù)據(jù)庫不一定)拗军。
  • 輔助索引(非聚集索引任洞,次級索引厌殉,二級索引)
    非聚集索引在BTree的葉子節(jié)點中保存了索引列和主鍵。如果查詢列不在該索引內(nèi)侈咕,只能查到其主鍵值公罕,還需要回表操作查詢聚簇索引進行查詢。

聚簇索引的優(yōu)點:

  • 可以把相關(guān)數(shù)據(jù)保存在一起耀销,如:實現(xiàn)電子郵箱時楼眷,可以根據(jù)用戶ID來聚集數(shù)據(jù),這樣只需要從磁盤讀取>- 少量的數(shù)據(jù)頁就能獲取某個用戶全部郵件熊尉,如果沒有使用聚集索引罐柳,則每封郵件都可能導致一次磁盤IO
    數(shù)據(jù)訪問更快,聚集索引將索引和數(shù)據(jù)保存在同一個btree中狰住,因此從聚集索引中獲取數(shù)據(jù)通常比在非聚集索引中查找要快
  • 使用覆蓋索引掃描的查詢可以直接使用頁節(jié)點中的主鍵值

聚簇索引的缺點:

  • 聚簇數(shù)據(jù)最大限度地提高了IO密集型應(yīng)用的性能张吉,但如果數(shù)據(jù)全部放在內(nèi)存中,則訪問的順序就沒有那么重要了催植,聚集索引也沒有什么優(yōu)勢了
  • 插入速度嚴重依賴于插入順序肮蛹,按照主鍵的順序插入是加載數(shù)據(jù)到innodb表中速度最快的方式,但如果不是按照主鍵順序加載數(shù)據(jù)创南,那么在加載完成后最好使用optimize table命令重新組織一下表
  • 更新聚集索引列的代價很高伦忠,因為會強制innodb將每個被更新的行移動到新的位置
  • 基于聚集索引的表在插入新行,或者主鍵被更新導致需要移動行的時候稿辙,可能面臨頁分裂的問題昆码,當行的主鍵值要求必須將這一行插入到某個已滿的頁中時,存儲引擎會將該頁分裂成兩個頁面來容納該行邻储,這就是一次頁分裂操作赋咽,頁分裂會導致表占用更多的磁盤空間
  • 聚集索引可能導致全表掃描變慢,尤其是行比較稀疏吨娜,或者由于頁分裂導致數(shù)據(jù)存儲不連續(xù)的時候
  • 二級索引可能比想象的更大脓匿,因為在二級索引的葉子節(jié)點包含了引用行的主鍵列。
  • 二級索引訪問需要兩次索引查找萌壳,而不是一次

怎么驗證 mysql 的索引是否滿足需求亦镶?

說一下數(shù)據(jù)庫的事務(wù)隔離?

說一下 mysql 常用的引擎袱瓮?

  1. MyISAM存儲引擎:不支持事務(wù)缤骨、也不支持外鍵,優(yōu)勢是訪問速度快尺借,對事務(wù)完整性沒有 要求或者以select绊起,insert為主的應(yīng)用基本上可以用這個引擎來創(chuàng)建表
    支持3種不同的存儲格式,分別是:靜態(tài)表燎斩;動態(tài)表虱歪;壓縮表
  • 靜態(tài)表:表中的字段都是非變長字段蜂绎,這樣每個記錄都是固定長度的,優(yōu)點存儲非常迅速笋鄙,容易緩存师枣,出現(xiàn)故障容易恢復;缺點是占用的空間通常比動態(tài)表多(因為存儲時會按照列的寬度定義補足空格)ps:在取數(shù)據(jù)的時候萧落,默認會把字段后面的空格去掉践美,如果不注意會把數(shù)據(jù)本身帶的空格也會忽略。
  • 動態(tài)表:記錄不是固定長度的找岖,這樣存儲的優(yōu)點是占用的空間相對較少陨倡;缺點:頻繁的更新、刪除數(shù)據(jù)容易產(chǎn)生碎片许布,需要定期執(zhí)行OPTIMIZE TABLE或者myisamchk-r命令來改善性能
  • 壓縮表:因為每個記錄是被單獨壓縮的兴革,所以只有非常小的訪問開支
  1. InnoDB存儲引擎*
    該存儲引擎提供了具有提交、回滾和崩潰恢復能力的事務(wù)安全蜜唾。但是對比MyISAM引擎杂曲,寫的處理效率會差一些,并且會占用更多的磁盤空間以保留數(shù)據(jù)和索引灵妨。
    InnoDB存儲引擎的特點:支持自動增長列解阅,支持外鍵約束

  2. MEMORY存儲引擎
    Memory存儲引擎使用存在于內(nèi)存中的內(nèi)容來創(chuàng)建表落竹。每個memory表只實際對應(yīng)一個磁盤文件泌霍,格式是.frm。memory類型的表訪問非常的快述召,因為它的數(shù)據(jù)是放在內(nèi)存中的朱转,并且默認使用HASH索引,但是一旦服務(wù)關(guān)閉积暖,表中的數(shù)據(jù)就會丟失掉藤为。
    MEMORY存儲引擎的表可以選擇使用BTREE索引或者HASH索引,兩種不同類型的索引有其不同的使用范圍

Hash索引優(yōu)點:
Hash 索引結(jié)構(gòu)的特殊性夺刑,其檢索效率非常高缅疟,索引的檢索可以一次定位搅轿,不像B-Tree 索引需要從根節(jié)點到枝節(jié)點稽煤,最后才能訪問到頁節(jié)點這樣多次的IO訪問,所以 Hash 索引的查詢效率要遠高于 B-Tree 索引合陵。
Hash索引缺點: 那么不精確查找呢沼填,也很明顯桅咆,因為hash算法是基于等值計算的,所以對于“l(fā)ike”等范圍查找hash索引無效坞笙,不支持岩饼;
Memory類型的存儲引擎主要用于哪些內(nèi)容變化不頻繁的代碼表荚虚,或者作為統(tǒng)計操作的中間結(jié)果表,便于高效地對中間結(jié)果進行分析并得到最終的統(tǒng)計結(jié)果籍茧,版述。對存儲引擎為memory的表進行更新操作要謹慎,因為數(shù)據(jù)并沒有實際寫入到磁盤中寞冯,所以一定要對下次重新啟動服務(wù)后如何獲得這些修改后的數(shù)據(jù)有所考慮院水。

  1. MERGE存儲引擎
    Merge存儲引擎是一組MyISAM表的組合,這些MyISAM表必須結(jié)構(gòu)完全相同简十,merge表本身并沒有數(shù)據(jù)檬某,對merge類型的表可以進行查詢,更新螟蝙,刪除操作恢恼,這些操作實際上是對內(nèi)部的MyISAM表進行的。

說一下 mysql 的行鎖和表鎖胰默?

說一下樂觀鎖和悲觀鎖场斑?

mysql 問題排查都有哪些手段?

如何做 mysql 的性能優(yōu)化牵署?

Schema?

在數(shù)據(jù)庫中漏隐,schema(發(fā)音 “skee-muh” 或者“skee-mah”,中文叫模式)是數(shù)據(jù)庫的組織和結(jié)構(gòu)奴迅,schemas 和schemata都可以作為復數(shù)形式青责。模式中包含了schema對象,可以是表(table)取具、列(column)脖隶、數(shù)據(jù)類型(data type)、視圖(view)暇检、存儲過程(stored procedures)产阱、關(guān)系(relationships)、主鍵(primary key)块仆、外鍵(foreign key)等构蹬。數(shù)據(jù)庫模式可以用一個可視化的圖來表示,它顯示了數(shù)據(jù)庫對象及其相互之間的關(guān)系.


Redis

redis 是什么悔据?都有哪些使用場景庄敛?

redis 有哪些功能?

redis 和 memecache 有什么區(qū)別蜜暑?

redis 為什么是單線程的铐姚?

  1. Redis為什么這么快
  • 完全基于內(nèi)存,絕大部分請求是純粹的內(nèi)存操作,非骋啵快速之众。數(shù)據(jù)存在內(nèi)存中,類似于HashMap依许,HashMap的優(yōu)勢就是查找和操作的時間復雜度都是O(1)棺禾;
  • 數(shù)據(jù)結(jié)構(gòu)簡單,對數(shù)據(jù)操作也簡單峭跳,Redis中的數(shù)據(jù)結(jié)構(gòu)是專門進行設(shè)計的膘婶;
  • 采用單線程,避免了不必要的上下文切換和競爭條件蛀醉,也不存在多進程或者多線程導致的切換而消耗 CPU悬襟,不用去考慮各種鎖的問題,不存在加鎖釋放鎖操作拯刁,沒有因為可能出現(xiàn)死鎖而導致的性能消耗脊岳;
  • 使用多路I/O復用模型,非阻塞IO垛玻;
  • 使用底層模型不同割捅,它們之間底層實現(xiàn)方式以及與客戶端之間通信的應(yīng)用協(xié)議不一樣,Redis直接自己構(gòu)建了VM 機制 帚桩,因為一般的系統(tǒng)調(diào)用系統(tǒng)函數(shù)的話亿驾,會浪費一定的時間去移動和請求;
  1. 多路 I/O 復用模型
    以上幾點都比較好理解账嚎,下邊我們針對多路 I/O 復用模型進行簡單的探討:
    多路I/O復用模型是利用 select莫瞬、poll、epoll 可以同時監(jiān)察多個流的 I/O 事件的能力醉锄,在空閑的時候乏悄,會把當前線程阻塞掉,當有一個或多個流有 I/O 事件時恳不,就從阻塞態(tài)中喚醒,于是程序就會輪詢一遍所有的流(epoll 是只輪詢那些真正發(fā)出了事件的流)开呐,并且只依次順序的處理就緒的流烟勋,這種做法就避免了大量的無用操作。
    這里“多路”指的是多個網(wǎng)絡(luò)連接筐付,“復用”指的是復用同一個線程卵惦。采用多路 I/O 復用技術(shù)可以讓單個線程高效的處理多個連接請求(盡量減少網(wǎng)絡(luò) IO 的時間消耗),且 Redis 在內(nèi)存中操作數(shù)據(jù)的速度非惩咂荩快沮尿,也就是說內(nèi)存內(nèi)的操作不會成為影響Redis性能的瓶頸,主要由以上幾點造就了 Redis 具有很高的吞吐量。

  2. 那么為什么Redis是單線程的
    我們首先要明白畜疾,上邊的種種分析赴邻,都是為了營造一個Redis很快的氛圍!官方FAQ表示啡捶,因為Redis是基于內(nèi)存的操作姥敛,CPU不是Redis的瓶頸,Redis的瓶頸最有可能是機器內(nèi)存的大小或者網(wǎng)絡(luò)帶寬瞎暑。既然單線程容易實現(xiàn)彤敛,而且CPU不會成為瓶頸,那就順理成章地采用單線程的方案了(畢竟采用多線程會有很多麻煩A硕摹)墨榄。

什么是緩存穿透?怎么解決勿她?

redis 支持的數(shù)據(jù)類型有哪些渠概?

  • String
    一個 key 對應(yīng)一個 value
  • hash
    一個鍵值(key=>value)對集合。
  • List
    Redis 列表是簡單的字符串列表嫂拴,按照插入順序排序播揪。你可以添加一個元素到列表的頭部(左邊)或者尾部(右邊)。
  • Set
    Redis 的 Set 是 string 類型的無序集合筒狠。
    集合是通過哈希表實現(xiàn)的猪狈,所以添加,刪除辩恼,查找的復雜度都是 O(1)雇庙。
  • zset(sorted set:有序集合)
    Redis zset 和 set 一樣也是string類型元素的集合,且不允許重復的成員。
    不同的是每個元素都會關(guān)聯(lián)一個double類型的分數(shù)灶伊。redis正是通過分數(shù)來為集合中的成員進行從小到大的排序疆前。
    zset的成員是唯一的,但分數(shù)(score)卻可以重復。

redis 支持的 java 客戶端都有哪些聘萨?

jedis 和 redisson 有哪些區(qū)別竹椒?

怎么保證緩存和數(shù)據(jù)庫數(shù)據(jù)的一致性?

redis 持久化有幾種方式米辐?

  1. RDB
    RDB持久化是指在指定的時間間隔內(nèi)將內(nèi)存中的數(shù)據(jù)集快照寫入磁盤胸完,實際操作過程是fork一個子進程,先將數(shù)據(jù)集寫入臨時文件翘贮,寫入成功后赊窥,再替換之前的文件,用二進制壓縮存儲狸页。


    image
  2. AOF
    AOF持久化以日志的形式記錄服務(wù)器所處理的每一個寫锨能、刪除操作,查詢操作不會記錄,以文本的方式記錄址遇,可以打開文件看到詳細的操作記錄熄阻。


    image
  3. 二者優(yōu)缺點

RDB存在哪些優(yōu)勢呢?

  • 一旦采用該方式傲隶,那么你的整個Redis數(shù)據(jù)庫將只包含一個文件饺律,這對于文件備份而言是非常完美的。比如跺株,你可能打算每個小時歸檔一次最近24小時的數(shù)據(jù)复濒,同時還要每天歸檔一次最近30天的數(shù)據(jù)。通過這樣的備份策略乒省,一旦系統(tǒng)出現(xiàn)災(zāi)難性故障巧颈,我們可以非常容易的進行恢復。
  • 對于災(zāi)難恢復而言袖扛,RDB是非常不錯的選擇砸泛。因為我們可以非常輕松的將一個單獨的文件壓縮后再轉(zhuǎn)移到其它存儲介質(zhì)上。
  • 性能最大化蛆封。對于Redis的服務(wù)進程而言唇礁,在開始持久化時,它唯一需要做的只是fork出子進程惨篱,之后再由子進程完成這些持久化的工作盏筐,這樣就可以極大的避免服務(wù)進程執(zhí)行IO操作了。
  • 相比于AOF機制砸讳,如果數(shù)據(jù)集很大琢融,RDB的啟動效率會更高。

RDB又存在哪些劣勢呢簿寂?

  • 如果你想保證數(shù)據(jù)的高可用性漾抬,即最大限度的避免數(shù)據(jù)丟失,那么RDB將不是一個很好的選擇常遂。因為系統(tǒng)一旦在定時持久化之前出現(xiàn)宕機現(xiàn)象纳令,此前沒有來得及寫入磁盤的數(shù)據(jù)都將丟失。
  • 由于RDB是通過fork子進程來協(xié)助完成數(shù)據(jù)持久化工作的烈钞,因此泊碑,如果當數(shù)據(jù)集較大時,可能會導致整個服務(wù)器停止服務(wù)幾百毫秒毯欣,甚至是1秒鐘。

AOF的優(yōu)勢有哪些呢臭脓?

  • 該機制可以帶來更高的數(shù)據(jù)安全性酗钞,即數(shù)據(jù)持久性。Redis中提供了3中同步策略,即每秒同步砚作、每修改同步和不同步窘奏。事實上,每秒同步也是異步完成的葫录,其效率也是非常高的着裹,所差的是一旦系統(tǒng)出現(xiàn)宕機現(xiàn)象,那么這一秒鐘之內(nèi)修改的數(shù)據(jù)將會丟失米同。而每修改同步骇扇,我們可以將其視為同步持久化,即每次發(fā)生的數(shù)據(jù)變化都會被立即記錄到磁盤中面粮∩傩ⅲ可以預(yù)見,這種方式在效率上是最低的熬苍。至于無同步稍走,無需多言,我想大家都能正確的理解它柴底。
  • 由于該機制對日志文件的寫入操作采用的是append模式婿脸,因此在寫入過程中即使出現(xiàn)宕機現(xiàn)象,也不會破壞日志文件中已經(jīng)存在的內(nèi)容柄驻。然而如果我們本次操作只是寫入了一半數(shù)據(jù)就出現(xiàn)了系統(tǒng)崩潰問題狐树,不用擔心,在Redis下一次啟動之前凿歼,我們可以通過redis-check-aof工具來幫助我們解決數(shù)據(jù)一致性的問題褪迟。
  • 如果日志過大,Redis可以自動啟用rewrite機制答憔。即Redis以append模式不斷的將修改數(shù)據(jù)寫入到老的磁盤文件中味赃,同時Redis還會創(chuàng)建一個新的文件用于記錄此期間有哪些修改命令被執(zhí)行。因此在進行rewrite切換時可以更好的保證數(shù)據(jù)安全性虐拓。
  • AOF包含一個格式清晰心俗、易于理解的日志文件用于記錄所有的修改操作。事實上蓉驹,我們也可以通過該文件完成數(shù)據(jù)的重建城榛。

AOF的劣勢有哪些呢?

  • 對于相同數(shù)量的數(shù)據(jù)集而言态兴,AOF文件通常要大于RDB文件狠持。RDB 在恢復大數(shù)據(jù)集時的速度比 AOF 的恢復速度要快。
  • 根據(jù)同步策略的不同瞻润,AOF在運行效率上往往會慢于RDB喘垂√鹂蹋總之,每秒同步策略的效率是比較高的正勒,同步禁用策略的效率和RDB一樣高效得院。

二者選擇的標準,就是看系統(tǒng)是愿意犧牲一些性能章贞,換取更高的緩存一致性(aof)祥绞,還是愿意寫操作頻繁的時候,不啟用備份來換取更高的性能鸭限,待手動運行save的時候蜕径,再做備份(rdb)。rdb這個就更有些 eventually consistent的意思了里覆。

redis 怎么實現(xiàn)分布式鎖丧荐?

  1. 如何通過Redis實現(xiàn)分布式鎖:(非完善方法)
    SETNX key value 如果key不存在,則創(chuàng)建并賦值

但是此時我們獲取的key是長期有效的,所以我們應(yīng)該如何解決長期有效的問題呢喧枷?
EXPIRE key seconds

  1. 如何通過Redis實現(xiàn)分布式鎖:(正確方式)

redis 分布式鎖有什么缺陷虹统?

redis 如何做內(nèi)存優(yōu)化?

redis 淘汰策略有哪些隧甚?

redis 常見的性能問題有哪些车荔?該如何解決?


Mongo


Maven

maven插件開發(fā)

插件開發(fā)

Git


ES


工廠--模式戚扳,雙重校驗--拿到封裝鎖

封裝鎖里邊有時間和重入鎖
數(shù)據(jù)庫分布式鎖
版本忧便、更新時間

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市帽借,隨后出現(xiàn)的幾起案子珠增,更是在濱河造成了極大的恐慌,老刑警劉巖砍艾,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蒂教,死亡現(xiàn)場離奇詭異,居然都是意外死亡脆荷,警方通過查閱死者的電腦和手機凝垛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蜓谋,“玉大人梦皮,你說我怎么就攤上這事√一溃” “怎么了剑肯?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長观堂。 經(jīng)常有香客問我退子,道長岖妄,這世上最難降的妖魔是什么型将? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任寂祥,我火速辦了婚禮,結(jié)果婚禮上七兜,老公的妹妹穿的比我還像新娘丸凭。我一直安慰自己,他們只是感情好腕铸,可當我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布惜犀。 她就那樣靜靜地躺著,像睡著了一般狠裹。 火紅的嫁衣襯著肌膚如雪虽界。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天涛菠,我揣著相機與錄音莉御,去河邊找鬼。 笑死俗冻,一個胖子當著我的面吹牛礁叔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播迄薄,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼琅关,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了讥蔽?” 一聲冷哼從身側(cè)響起涣易,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎冶伞,沒想到半個月后新症,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡碰缔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年账劲,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片金抡。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡瀑焦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出梗肝,到底是詐尸還是另有隱情榛瓮,我是刑警寧澤,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布巫击,位于F島的核電站禀晓,受9級特大地震影響精续,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜粹懒,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一重付、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧凫乖,春花似錦确垫、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至导街,卻和暖如春披泪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背搬瑰。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工款票, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人跌捆。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓徽职,卻偏偏與公主長得像,于是被迫代替她去往敵國和親佩厚。 傳聞我的和親對象是個殘疾皇子姆钉,可洞房花燭夜當晚...
    茶點故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 一、多線程抄瓦、并發(fā)及線程的基礎(chǔ)問題 1)Java 中能創(chuàng)建 Volatile 數(shù)組嗎潮瓶? 能,Java 中可以創(chuàng)建 v...
    小菜一碟i閱讀 161評論 0 0
  • 1.請說明Java中方法重載的規(guī)則 1.方法名相同 2.參數(shù)列表中參數(shù)類型不相同 或者 參數(shù)個數(shù)不同 3.與返回值...
    張威先森閱讀 598評論 0 1
  • 從三月份找實習到現(xiàn)在钙姊,面了一些公司毯辅,掛了不少,但最終還是拿到小米煞额、百度思恐、阿里、京東膊毁、新浪胀莹、CVTE、樂視家的研發(fā)崗...
    時芥藍閱讀 42,255評論 11 349
  • 一、JVM內(nèi)幕:Java虛擬機詳解(java se 7規(guī)范) 直接上圖栅螟,再逐步解釋荆秦。 上圖顯示的組件分兩個章節(jié)解釋...
    屈小勇閱讀 1,848評論 6 22
  • 今天感恩節(jié)哎篱竭,感謝一直在我身邊的親朋好友。感恩相遇步绸!感恩不離不棄掺逼。 中午開了第一次的黨會,身份的轉(zhuǎn)變要...
    迷月閃星情閱讀 10,567評論 0 11