Java面試總結

 

1、基礎篇

1.一、Java基礎 

  • 面向對象的特徵:繼承、封裝和多態
    final, finally, finalize 的區別

  •  

    final用於聲明屬性,方法和類,分別表示屬性不可變,方法不可覆蓋,類不可繼承。html

    內部類要訪問局部變量,局部變量必須定義成final類型,例如,一段代碼……前端

    finally是異常處理語句結構的一部分,表示老是執行。java

    finalize是Object類的一個方法,在垃圾收集器執行的時候會調用被回收對象的此方法,能夠覆蓋此方法提供垃圾收集時的其餘資源回收,例如關閉文件等。JVM不保證此方法總被調用mysql

  • Exception、Error、運行時異常與通常異常有何異同

  •  

    exception 表示一種設計或實現問題。也就是說,它表示若是程序運行正常,從不會發生的狀況android

  • error表示恢復不是不可能但很困難的狀況下的一種嚴重問題。好比說內存溢出。不可能期望程序能處理這樣的狀況。程序員

    異常表示程序運行過程當中可能出現的非正常狀態,運行時異常表示虛擬機的一般操做中可能遇到的異常,是一種常見運行錯誤。java編譯器要求方法必須聲明拋出可能發生的非運行時異常,可是並不要求必須聲明拋出未被捕獲的運行時異常。 web

  •  

    異常是指java程序運行時(非編譯)所發生的非正常狀況或錯誤,與現實生活中的事件很類似,現實生活中的事件能夠包含事件發生的時間、地點、人物、情節等信息,能夠用一個對象來表示,Java使用面向對象的方式來處理異常,它把程序中發生的每一個異常也都分別封裝到一個對象來表示的,該對象中包含有異常的信息。面試

    Java對異常進行了分類,不一樣類型的異常分別用不一樣的Java類表示,全部異常的根類爲java.lang.Throwable,Throwable下面又派生了兩個子類:Error和Exception,Error表示應用程序自己沒法克服和恢復的一種嚴重問題,程序只有死的份了,例如,說內存溢出和線程死鎖等系統問題。Exception表示程序還可以克服和恢復的問題,其中又分爲系統異常和普通異常,系統異常是軟件自己缺陷所致使的問題,也就是軟件開發人員考慮不周所致使的問題,軟件使用者沒法克服和恢復這種問題,但在這種問題下還可讓軟件系統繼續運行或者讓軟件死掉,例如,數組腳本越界(ArrayIndexOutOfBoundsException),空指針異常(NullPointerException)、類轉換異常(ClassCastException);普通異常是運行環境的變化或異常所致使的問題,是用戶可以克服的問題,例如,網絡斷線,硬盤空間不夠,發生這樣的異常後,程序不該該死掉。ajax

    java爲系統異常和普通異常提供了不一樣的解決方案,編譯器強制普通異常必須try..catch處理或用throws聲明繼續拋給上層調用方法處理,因此普通異常也稱爲checked異常,而系統異常能夠處理也能夠不處理,因此,編譯器不強制用try..catch處理或用throws聲明,因此係統異常也稱爲unchecked異常。redis

     

    提示答題者:就按照三個級別去思考:虛擬機必須宕機(就是死機)的錯誤,程序能夠死掉也能夠不死掉的錯誤,程序不該該死掉的錯誤;

  • 請寫出5種常見到的runtime exception

  •  

    這道題主要考你的代碼量到底多大,若是你長期寫代碼的,應該常常都看到過一些系統方面的異常,你不必定真要回答出5個具體的系統異常,但你要可以說出什麼是系統異常,以及幾個系統異常就能夠了,固然,這些異常徹底用其英文名稱來寫是最好的,若是實在寫不出,那就用中文吧,有總比沒有強!

    所謂系統異常,就是…..,它們都是RuntimeException的子類,在jdk doc中查RuntimeException類,就能夠看到其全部的子類列表,也就是看到了全部的系統異常。我比較有印象的系統異常有:NullPointerException,ArrayIndexOutOfBoundsException,ClassCastException,SQLException,FileNotFoundException,IOException......

  • int 和 Integer 有什麼區別,Integer的值緩存範圍

  •  

    int是java提供的8種原始數據類型之一。Java爲每一個原始類型提供了封裝類,Integer是java爲int提供的封裝類。int的默認值爲0,而Integer的默認值爲null,即Integer能夠區分出未賦值和值爲0的區別,int則沒法表達出未賦值的狀況,例如,要想表達出沒有參加考試和考試成績爲0的區別,則只能使用Integer。在JSP開發中,Integer的默認爲null,因此用el表達式在文本框中顯示時,值爲空白字符串,而int默認的默認值爲0,因此用el表達式在文本框中顯示時,結果爲0,因此,int不適合做爲web層的表單數據的類型。

    在Hibernate中,若是將OID定義爲Integer類型,那麼Hibernate就能夠根據其值是否爲null而判斷一個對象是不是臨時的,若是將OID定義爲了int類型,還須要在hbm映射文件中設置其unsaved-value屬性爲0。

    另外,Integer提供了多個與整數相關的操做方法,例如,將一個字符串轉換成整數,Integer中還定義了表示整數的最大值和最小值的常量。

    • Boolean:(所有緩存)
    • Byte:(所有緩存)
    • Integer(-128 — 127緩存)
    • Character(<= 127緩存)
    • Short(-128 — 127緩存)
    • Long(-128 — 127緩存)
    • Float(沒有緩存)
    • Doulbe(沒有緩存)
  • 包裝類,裝箱和拆箱

  •  

    包裝類(原始類型對應的類,即Boolean, Byte, Short, Integer, Long, Float, Double, Character)的自動拆、裝箱分別是指以下的過程:

    裝箱:是指基本類型變爲相應包裝類的過程,如Integer a=Integer.valueOf(100);或者int a=100;Integer b=new Integer(a);這裏的Integer.valueOf(100)和new Integer(a)就是裝箱,由基本數據類型構造出一個包裝類的對象。

    拆箱:就是裝箱的逆過程。如Integer a=new Integer(100);int b=a.intValue();這裏的a.intValue()就是拆箱的過程,由一個包裝類對象轉換到相應的基本數據類型。

    自動裝箱、拆箱:指編譯器幫助開發人員完成包裝類的裝箱和拆箱過程,也就是在將*.java文件編譯成*.class文件的過程當中完成。本文的目的是要介紹一下,編譯器在什麼時候才進行自動裝箱、拆箱。

    包裝類的自動裝箱和拆箱規則以下:

    • 遇到賦值運算符「=」(包括傳參數,參數傳遞屬於隱式賦值)時,會將包裝類拆箱或裝箱爲相應類型
    • 遇到算術運算符、位運算符和位移運算符「+, ++, --, -, *, /, %, &, |, ^, ~, <<, >>, >>>」時,對包裝類進行拆箱
    • 遇到關係運算符">, <, >=, <="(不包括「==」和「!=」哦)時,對包裝類進行拆箱
    • 對關係運算符"==, !="而言,遇到數字常量或算術表達式時,纔對包裝類進行拆箱
    其他狀況下,不進行自動的裝箱和拆箱,注意啊,這裏說的是自動裝箱和拆箱。
  • String、StringBuilder、StringBuffer

  •  

    1. 修改字符串速度 
      StringBuilder>StringBuffer>String
    2. 內容是否可變 
      只有String不可變。 
    3. 線程安全 
      只有StringBuilder是線程不安全的。

     

    String做爲不可變類,是明顯線程安全的,Java中全部不可變類都是線程安全的。

    StringBuffer類是可變類,可是StringBuffer類中實現的方法都是被Sychronized關鍵字所修飾的,所以它靠鎖實現了線程安全。 
    Stringbuilder類是可變類,而且方法沒有被Sychronized修飾,所以它是線程不安全的。

    JAVA平臺提供了兩個類:String和StringBuffer,它們能夠儲存和操做字符串,即包含多個字符的字符數據。這個String類提供了數值不可改變的字符串。而這個StringBuffer類提供的字符串進行修改。當你知道字符數據要改變的時候你就能夠使用StringBuffer。典型地,你能夠使用StringBuffers來動態構造字符數據。另外,String實現了equals方法,new String(「abc」).equals(newString(「abc」)的結果爲true,而StringBuffer沒有實現equals方法,因此,new StringBuffer(「abc」).equals(new StringBuffer(「abc」)的結果爲false。

     

    接着要舉一個具體的例子來講明,咱們要把1到100的全部數字拼起來,組成一個串。

    StringBuffer sbf = newStringBuffer(); 

    for(int i=0;i<100;i++) {

        sbf.append(i);

    }

    上面的代碼效率很高,由於只建立了一個StringBuffer對象,而下面的代碼效率很低,由於建立了101個對象。

    String str = new String(); 

    for(int i=0;i<100;i++) {

        str = str + i;

    }

    String覆蓋了equals方法和hashCode方法,而StringBuffer沒有覆蓋equals方法和hashCode方法,因此,將StringBuffer對象存儲進Java集合類中時會出現問題。

    在講二者區別時,應把循環的次數搞成10000,而後用endTime-beginTime來比較二者執行的時間差別,最後還要講講StringBuilder與StringBuffer的區別。(區別以下)

    StringBuffer線程安全的可變字符序列。一個相似於 String的字符串緩衝區,但不能修改。雖然在任意時間點上它都包含某種特定的字符序列,但經過某些方法調用能夠改變該序列的長度和內容,可將字符串緩衝區安全地用於多個線程。能夠在必要時對這些方法進行同步,所以任意特定實例上的全部操做就好像是以串行順序發生的,該順序與所涉及的每一個線程進行的方法調用順序一致。(從 JDK 5開始,爲該類補充了一個單個線程使用的等價類,即 StringBuilder。與該類相比,一般應該優先使用 StringBuilder類,由於它支持全部相同的操做,但因爲它不執行同步,因此速度更快。)

    StringBuilder一個可變的字符序列。此類提供一個與 StringBuffer兼容的 API,但不保證同步。該類被設計用做 StringBuffer的一個簡易替換,用在字符串緩衝區被單個線程使用的時候(這種狀況很廣泛)。(若是可能,建議優先採用該類,由於在大多數實現中,它比 StringBuffer要快。但將 StringBuilder的實例用於多個線程是不安全的。若是須要這樣的同步,則建議使用 StringBuffer。)

    StringBuffer和Stringbuilder上的主要操做都是 append和 insert 方法,可重載這些方法,以接受任意類型的數據。每一個方法都能有效地將給定的數據轉換成字符串,而後將該字符串的字符追加或插入到字符串緩衝區中。append方法始終將這些字符添加到緩衝區的末端;而 insert方法則在指定的點添加字符。

    例如,若是 z 引用一個當前內容是「start」的字符串緩衝區對象,則此方法調用z.append("le")會使字符串緩衝區包含「startle」,而 z.insert(4, "le")將更改字符串緩衝區,使之包含「starlet」。

    一般,若是 sb 引用 StringBuilder 的一個實例,則sb.append(x)和 sb.insert(sb.length(), x)具備相同的效果。只要發生有關源序列(如在源序列中追加或插入)的操做,該類就只在執行此操做的字符串緩衝區上而不是在源上實現同步。

  • 重載和重寫的區別

  •  

    Overload是重載的意思,Override是覆蓋的意思,也就是重寫。

    重載Overload表示同一個類中能夠有多個名稱相同的方法,但這些方法的參數列表各不相同(即參數個數或類型不一樣)。

    重寫Override表示子類中的方法能夠與父類中的某個方法的名稱和參數徹底相同,經過子類建立的實例對象調用這個方法時,將調用子類中的定義方法,這至關於把父類中定義的那個徹底相同的方法給覆蓋了,這也是面向對象編程的多態性的一種表現。子類覆蓋父類的方法時,只能比父類拋出更少的異常,或者是拋出父類拋出的異常的子異常,由於子類能夠解決父類的一些問題,不能比父類有更多的問題。子類方法的訪問權限只能比父類的更大,不能更小。若是父類的方法是private類型,那麼,子類則不存在覆蓋的限制,至關於子類中增長了一個全新的方法。

    至於Overloaded的方法是否能夠改變返回值的類型這個問題,要看你倒底想問什麼呢?這個題目很模糊。若是幾個Overloaded的方法的參數列表不同,它們的返回者類型固然也能夠不同。但我估計你想問的問題是:若是兩個方法的參數列表徹底同樣,是否可讓它們的返回值不一樣來實現重載Overload。這是不行的,咱們能夠用反證法來講明這個問題,由於咱們有時候調用一個方法時也能夠不定義返回結果變量,即不要關心其返回結果,例如,咱們調用map.remove(key)方法時,雖然remove方法有返回值,可是咱們一般都不會定義接收返回結果的變量,這時候假設該類中有兩個名稱和參數列表徹底相同的方法,僅僅是返回類型不一樣,java就沒法肯定編程者倒底是想調用哪一個方法了,由於它沒法經過返回結果類型來判斷。

    override能夠翻譯爲覆蓋,從字面就能夠知道,它是覆蓋了一個方法而且對其重寫,以求達到不一樣的做用。對咱們來講最熟悉的覆蓋就是對接口方法的實現,在接口中通常只是對方法進行了聲明,而咱們在實現時,就須要實現接口聲明的全部方法。除了這個典型的用法之外,咱們在繼承中也可能會在子類覆蓋父類中的方法。在覆蓋要注意如下的幾點:

    一、覆蓋的方法的標誌必需要和被覆蓋的方法的標誌徹底匹配,才能達到覆蓋的效果;

    二、覆蓋的方法的返回值必須和被覆蓋的方法的返回一致;

    三、覆蓋的方法所拋出的異常必須和被覆蓋方法的所拋出的異常一致,或者是其子類;

    四、被覆蓋的方法不能爲private,不然在其子類中只是新定義了一個方法,並無對其進行覆蓋。

    overload對咱們來講可能比較熟悉,能夠翻譯爲重載,它是指咱們能夠定義一些名稱相同的方法,經過定義不一樣的輸入參數來區分這些方法,而後再調用時,JVM就會根據不一樣的參數樣式,來選擇合適的方法執行。在使用重載要注意如下的幾點:

    一、在使用重載時只能經過不一樣的參數樣式。例如,不一樣的參數類型,不一樣的參數個數,不一樣的參數順序(固然,同一方法內的幾個參數類型必須不同,例如能夠是fun(int,float),可是不能爲fun(int,int));

    二、不能經過訪問權限、返回類型、拋出的異常進行重載;

    三、方法的異常類型和數目不會對重載形成影響;

    四、對於繼承來講,若是某一方法在父類中是訪問權限是priavte,那麼就不能在子類對其進行重載,若是定義的話,也只是定義了一個新方法,而不會達到重載的效果。

  • 抽象類和接口有什麼區別

  • 1.abstract class表示繼承關係,"is-a"關係,單繼承
    能夠有數據成員,默認friendly
    能夠有非抽象方法和抽象方法,抽象方法只能是public或protected

    2.interface表示like-a"關係,一個類能夠實現多個接口
    只能有靜態數據成員(默認是public staic final)
    只能有類型抽象方法,且public類型

  • 接口能夠繼承接口。抽象類能夠實現(implements)接口,抽象類能夠繼承具體類。抽象類中能夠有靜態的main方法。

  •  

    備註:只要明白了接口和抽象類的本質和做用,這些問題都很好回答,你想一想,若是你是java語言的設計者,你是否會提供這樣的支持,若是不提供的話,有什麼理由嗎?若是你沒有道理不提供,那答案就是確定的了。

     只有記住抽象類與普通類的惟一區別就是不能建立實例對象和容許有abstract方法。

  • 說說反射的用途及實現

  • Java 反射機制是在運行狀態中,對於任意一個類,都可以知道這個類的全部屬性和方法;對於任意一個對象,都可以調用它的任意方法和屬性;這種動態獲取信息以及動態調用對象方法的功能稱爲 Java 語言的反射機制

  • 在運行時構造一個類的對象;判斷一個類所具備的成員變量和方法;調用一個對象的方法;生成動態代理。反射最大的應用就是框架

  •  

    Java反射機制主要用於實現如下功能。

    (1)在運行時判斷任意一個對象所屬的類型。

    (2)在運行時構造任意一個類的對象。

    (3)在運行時判斷任意一個類所具備的成員變量和方法。

    (4)在運行時調用任意一個對象的方法,甚至能夠調用private方法

  • 說說自定義註解的場景及實現

  • 垂直化編程,就是A—B—C—D…等執行下去,一個邏輯一個邏輯完了再執行下一個,可是spring 中AOP提供了一種思想,它的做用就是,當在業務不知情的狀況下,對業務代碼的功能的加強,這種思想使用的場景,例如事務提交、方法執行以前的權限檢測、日誌打印、方法調用事件等等

  • java在咱們要自定義註解的時候提供了它本身的自定義語法以及元註解,元註解(負責註解其餘註解): Java5.0定義了4個標準的meta-annotation類型,它們被用來提供對其它 annotation類型做說明。Java5.0定義的元註解: 
        1.@Target, 
        2.@Retention, 
        3.@Documented, 
        4.@Inherited 
      這些類型和它們所支持的類在java.lang.annotation包中能夠找到。 
      1.@Target:用戶描述註解的做用範圍 
      取值(ElementType)有: 
        1.CONSTRUCTOR:用於描述構造器 
        2.FIELD:用於描述域 
        3.LOCAL_VARIABLE:用於描述局部變量 
        4.METHOD:用於描述方法 
        5.PACKAGE:用於描述包 
        6.PARAMETER:用於描述參數 
        7.TYPE:用於描述類、接口(包括註解類型) 或enum聲明 
    2.@Retention:表示須要在什麼級別保存該註釋信息 
    取值(RetentionPoicy)有: 
        1.SOURCE:在源文件中有效(即源文件保留) 
        2.CLASS:在class文件中有效(即class保留) 
        3.RUNTIME:在運行時有效(即運行時保留)(經常使用) 
      3.@Documented:Documented是一個標記註解 
      4.@Inherited :用於聲明一個註解; 

  • HTTP請求的GET與POST方式的區別

  •  

    (1) 在客戶端,Get方式在經過URL提交數據,數據在URL中能夠看到;POST方式,數據放置在HTML HEADER內提交。

    (2) GET方式提交的數據最多隻能有1024字節,而POST則沒有此限制。

    (3) 安全性問題。正如在(1)中提到,使用 Get的時候,參數會顯示在地址欄上,而 Post不會。因此,若是這些數據是中文數據並且是非敏感數據,那麼使用 get;若是用戶輸入的數據不是中文字符並且包含敏感數據,那麼仍是使用 post爲好。

    (4) 安全的和冪等的。所謂安全的意味着該操做用於獲取信息而非修改信息。冪等的意味着對同一 URL的多個請求應該返回一樣的結果。完整的定義並不像看起來那樣嚴格。換句話說,GET請求通常不該產生反作用。從根本上講,其目標是當用戶打開一個連接時,她能夠確信從自身的角度來看沒有改變資源。好比,新聞站點的頭版不斷更新。雖然第二次請求會返回不一樣的一批新聞,該操做仍然被認爲是安全的和冪等的,由於它老是返回當前的新聞。反之亦然。POST請求就不那麼輕鬆了。POST表示可能改變服務器上的資源的請求。仍然以新聞站點爲例,讀者對文章的註解應該經過 POST請求實現,由於在註解提交以後站點已經不一樣了

  • Session與Cookie區別

  •  

    Cookie保存在客戶端,未設置存儲時間的cookie爲會話cookie保存在瀏覽器的進程開闢的內存中,當瀏覽器關閉後會話cookie也會被刪除;設置了存儲時間的cookie保存在用戶設備的磁盤中直到過時。

    session保存在服務器端,存儲在IIS的進程開闢的內存中。

    當服務器端生成一個session時就會向客戶端發送一個cookie保存在客戶端,這個cookie保存的是session的sessionId。這樣才能保證客戶端發起請求後客戶端已經登陸的用戶可以與服務器端成千上萬的session中準確匹配到已經保存了該用戶信息的session,同時也可以確保不一樣頁面之間傳值時的正確匹配。

    注:爲了防止客戶端禁用了cookie而沒法使用session的狀況能夠把sessionId和其餘用戶信息重寫到url中,每次請求都在url中附帶sessionId和用戶信息(不包含用戶的敏感信息)

  • 列出本身經常使用的JDK包

  •  

    1.java.lang:語言包

    2.java.util:實用包

    3.java.awt:抽象窗口工具包

    4.javax.swing:輕量級的窗口工具包,這是目前使用最普遍的GUI程序設計包

    5.java.io:輸入輸出包

    6.java.net:網絡函數包

    7.java.applet:編制applet用到的包(目前編制applet程序時,更多的是使用swing中的JApplet類)。

  • MVC設計思想

  • MVC全名是Model View Controller,是模型(model)-視圖(view)-控制器(controller)的縮寫,M是指業務模型,V是指用戶界面,C是指控制器,一種軟件設計典範,用一種業務邏輯、數據、界面顯示分離的方法組織代碼,將業務邏輯彙集到一個部件裏面,在改進和個性化定製界面及用戶交互的同時,不須要從新編寫業務邏輯。

    MVC是軟件開發過程當中比較流行的設計思想。應該明確一點就是,MVC是設計模式,設計思想,不是一種編程技術。

    在web開發中最典型的是JSP+servlet+javabean模式,其思想的核心概念以下:

    Model:封裝應用程序的數據結構和事務邏輯,集中體現應用程序的狀態,當數據狀態改變是,可以在試圖裏面體現出來。JavaBean很是適合這個角色。

    View:是Model是外在表現,模型狀態改變是,有所體現,JSP很是適合這個角色。

    Controller:是對用戶輸入進行相應,將模型和試圖聯繫在一塊兒,負責將數據寫到模型中,並調用視圖。Servlet很是適合這個角色。

    MVC思想如圖:


    MVC的步驟以下:

    1.用戶在表單中輸入,表單提交給Servlet,Servlet驗證輸入,而後實例化JavaBean

    2,JavaBean查詢數據庫,查詢結果暫存在JavaBean中。

    3,Servlet跳轉到JSP,JSP使用JavaBean獲得它裏面的查詢結果,並顯示出來。

  • equals與==的區別

  • 值類型(int,char,long,boolean等)都是用==判斷相等性。對象引用的話,==判斷引用所指的對象是不是同一個。equals是Object的成員函數,有些類會覆蓋(override)這個方法,用於判斷對象的等價性。例如String類,兩個引用所指向的String都是"abc",但可能出現他們實際對應的對象並非同一個(和jvm實現方式有關),所以用==判斷他們可能不相等,但用equals判斷必定是相等的。

    (單獨把一個東西說清楚,而後再說清楚另外一個,這樣,它們的區別天然就出來了,混在一塊兒說,則很難說清楚)

    ==操做符專門用來比較兩個變量的值是否相等,也就是用於比較變量所對應的內存中所存儲的數值是否相同,要比較兩個基本類型的數據或兩個引用變量是否相等,只能用==操做符。

    若是一個變量指向的數據是對象類型的,那麼,這時候涉及了兩塊內存,對象自己佔用一塊內存(堆內存),變量也佔用一塊內存,例如Objet obj = new Object();變量obj是一個內存,new Object()是另外一個內存,此時,變量obj所對應的內存中存儲的數值就是對象佔用的那塊內存的首地址。對於指向對象類型的變量,若是要比較兩個變量是否指向同一個對象,即要看這兩個變量所對應的內存中的數值是否相等,這時候就須要用==操做符進行比較。

    equals方法是用於比較兩個獨立對象的內容是否相同,就比如去比較兩我的的長相是否相同,它比較的兩個對象是獨立的。例如,對於下面的代碼:

    String a=new String("foo");

    String b=new String("foo");

    兩條new語句建立了兩個對象,而後用a,b這兩個變量分別指向了其中一個對象,這是兩個不一樣的對象,它們的首地址是不一樣的,即a和b中存儲的數值是不相同的,因此,表達式a==b將返回false,而這兩個對象中的內容是相同的,因此,表達式a.equals(b)將返回true。

    在實際開發中,咱們常常要比較傳遞進行來的字符串內容是否等,例如,String input = …;input.equals(「quit」),許多人稍不注意就使用==進行比較了,這是錯誤的,隨便從網上找幾個項目實戰的教學視頻看看,裏面就有大量這樣的錯誤。記住,字符串的比較基本上都是使用equals方法。

    若是一個類沒有本身定義equals方法,那麼它將繼承Object類的equals方法,Object類的equals方法的實現代碼以下:

    boolean equals(Object o){

    return this==o;

    }

    這說明,若是一個類沒有本身定義equals方法,它默認的equals方法(從Object類繼承的)就是使用==操做符,也是在比較兩個變量指向的對象是不是同一對象,這時候使用equals和使用==會獲得一樣的結果,若是比較的是兩個獨立的對象則總返回false。若是你編寫的類但願可以比較該類建立的兩個實例對象的內容是否相同,那麼你必須覆蓋equals方法,由你本身寫代碼來決定在什麼狀況便可認爲兩個對象的內容是相同的。

  • hashCode和equals方法的區別與聯繫

  • hashCode 方法是基類Object中的 實例native方法,所以對全部繼承於Object的類都會有該方法。

  •  

    哈希相關概念 
     咱們首先來了解一下哈希表:

    • 概念 : Hash 就是把任意長度的輸入(又叫作預映射, pre-image),經過散列算法,變換成固定長度的輸出(int),該輸出就是散列值。這種轉換是一種 壓縮映射,也就是說,散列值的空間一般遠小於輸入的空間。不一樣的輸入可能會散列成相同的輸出,從而不可能從散列值來惟一的肯定輸入值。簡單的說,就是一種將任意長度的消息壓縮到某一固定長度的消息摘要的函數。

    • 應用–數據結構 : 數組的特色是:尋址容易,插入和刪除困難; 而鏈表的特色是:尋址困難,插入和刪除容易。那麼咱們能不能綜合二者的特性,作出一種尋址容易,插入和刪除也容易的數據結構?答案是確定的,這就是咱們要提起的哈希表,哈希表有多種不一樣的實現方法,我接下來解釋的是最經常使用的一種方法——拉鍊法,咱們能夠理解爲 「鏈表的數組」,如圖:

               這裏寫圖片描述 
                              圖1 哈希表示例

       左邊很明顯是個數組,數組的每一個成員是一個鏈表。該數據結構所容納的全部元素均包含一個指針,用於元素間的連接。咱們根據元素的自身特徵把元素分配到不一樣的鏈表中去,也是根據這些特徵,找到正確的鏈表,再從鏈表中找出這個元素。其中,將根據元素特徵計算元素數組下標的方法就是散列法。

    • 拉鍊法的適用範圍 : 快速查找,刪除的基本數據結構,一般須要總數據量能夠放入內存。

    • 要點 : 
      hash函數選擇,針對字符串,整數,排列,具體相應的hash方法; 
      碰撞處理,一種是open hashing,也稱爲拉鍊法,另外一種就是closed hashing,也稱開地址法,opened addressing

    前提: 談到hashCode就不得不說equals方法,兩者均是Object類裏的方法。因爲Object類是全部類的基類,因此一切類裏均可以重寫這兩個方法。

    • 原則 1 : 若是 x.equals(y) 返回 「true」,那麼 x 和 y 的 hashCode() 必須相等 ;
    • 原則 2 : 若是 x.equals(y) 返回 「false」,那麼 x 和 y 的 hashCode() 有可能相等,也有可能不等 ;
    • 原則 3 : 若是 x 和 y 的 hashCode() 不相等,那麼 x.equals(y) 必定返回 「false」 ;
    • 原則 4 : 通常來說,equals 這個方法是給用戶調用的,而 hashcode 方法通常用戶不會去調用 ;
    • 原則 5 : 當一個對象類型做爲集合對象的元素時,那麼這個對象應該擁有本身的equals()和hashCode()設計,並且要遵照前面所說的幾個原則。
  • 什麼是Java序列化和反序列化,如何實現Java序列化?或者請解釋Serializable 接口的做用

  • 序列化:把對象轉換爲字節序列的過程稱爲對象的序列化。
    反序列化:把字節序列恢復爲對象的過程稱爲對象的反序列化。

  • 實現Serializable接口便可

  • transient 修飾的屬性,是不會被序列化的   靜態static的屬性,不序列化

  • Object類中常見的方法,爲何wait  notify會放在Object裏邊?

  •  

    a、這些方法用於同步中

    b、使用這些方法時必需要標識所屬的同步的鎖

    c、鎖能夠是任意對象,因此任意對象調用的方法必定是定義在Object類中

  • Java的平臺無關性如何體現出來的

  •  Java平臺無關的能力給予網絡一個同構的運行環境,使得分佈式系統能夠圍繞着「網絡移動對象」開構建。好比對象序列化,RMI, Jini就是利用平臺無關性。把面向對象編程從虛擬機帶到了網絡上。

  • JDK和JRE的區別

  • JDK,開發java程序用的開發包,JDK裏面有java的運行環境(JRE),包括client和server端的。須要配置環境變量。。。。
    JRE,運行java程序的環境,JVM,JRE裏面只有client運行環境,安裝過程當中,會自動添加PATH。

  • Java 8有哪些新特性

  • 一、接口的默認方法二、Lambda 表達式三、函數式接口四、方法與構造函數引用五、Lambda 做用域六、訪問局部變量七、訪問對象字段與靜態變量八、訪問接口的默認方法九、Date API十、Annotation 註解

1.二、Java常見集合

  • List 和 Set 區別

  • Set和hashCode以及equals方法的聯繫

  • List 和 Map 區別

  • Arraylist 與 LinkedList 區別

  • ArrayList 與 Vector 區別

  • HashMap 和 Hashtable 的區別

  • HashSet 和 HashMap 區別

  • 以上問題可查看一下博客(Collection

  • HashMap 和 ConcurrentHashMap 的區別

  • HashMap 的工做原理及代碼實現,何時用到紅黑樹

  • 多線程狀況下HashMap死循環的問題

  • 以上問題可查看一下博客(HashMap

  • HashMap出現Hash DOS攻擊的問題

  • ConcurrentHashMap 的工做原理及代碼實現,如何統計全部的元素個數

  • 手寫簡單的HashMap

  •  

    1. public interface  DIYMap<K,V> {  
    2.     //Map雙列集合 基本功能是 快速取  
    3.     public V put(K k,V v);  
    4.     //快速取  
    5.     public V get(K k);  
    6.   
    7.     //定義一個內部接口  
    8.     public interface Entry<K,V>{  
    9.         public K getKey();  
    10.           
    11.         public V getValue();  
    12.     }  
    13. }  
    1. import java.util.ArrayList;  
    2. import java.util.List;  
    3. /* 
    4.     瞭解hashmap中entry實體的結構 
    5.     crc16算法 
    6.     hashmap底層=數組+鏈表 
    7.     經過hash算法帶來的好處, 快存快取  / 數組在存的時候是須要遍歷的 
    8.     HashMap底層是怎麼回事? 
    9.          
    10.  */  
    11. public class DIYHashMap<K, V> implements DIYMap<K, V>{  
    12.     //定義默認數組大小  
    13.     private  int defaultLenth=16;  
    14.     //負載因子,擴容標準    useSize/數組長度>0.75擴容  
    15.     private double defaultAddSizeFactor=0.75;  
    16.     //使用數組位置的總數  
    17.     private double useSize;  
    18.     //定義Map 骨架之一數組  
    19.     private Entry<K, V>[] table;  
    20.   
    21.     public DIYHashMap(int defaultLenth, double defaultAddSizeFactor) {  
    22.         if(defaultLenth<0){  
    23.             throw new IllegalArgumentException("數組長度爲負數"+defaultLenth);  
    24.         }  
    25.         if(defaultAddSizeFactor<=0 || Double.isNaN(defaultAddSizeFactor)){  
    26.             throw new IllegalArgumentException("擴容標準必須大於0的數字"+defaultLenth);  
    27.         }  
    28.       
    29.         this.defaultLenth = defaultLenth;  
    30.         this.defaultAddSizeFactor = defaultAddSizeFactor;  
    31.           
    32.         table=new Entry[defaultLenth];  
    33.     }  
    34.   
    35.     //快速存取 hash算法  
    36.     public V put(K k, V v) {  
    37.         if(useSize>defaultAddSizeFactor*defaultLenth){  
    38.             //擴容  
    39.             up2Size();  
    40.         }  
    41.         //經過key來計算出 存儲的位置  
    42.         int index=getIndex(k,table.length);  
    43.       
    44.         Entry<K, V> entry=table[index];  
    45.         Entry<K, V> newEntry=new Entry<K, V>(k, v, null);  
    46.         if(entry==null){  
    47.             table[index]=newEntry;  
    48.             useSize++;  
    49.         }else{//維護數組相同位置隊列  
    50.             Entry<K, V> tmp;  
    51.             while((tmp=table[index])!=null){  
    52.                 tmp=tmp.next;  
    53.             }  
    54.             tmp.next=newEntry;  
    55.         }  
    56.         return newEntry.getValue();  
    57.     }  
    58.   
    59.     private int getIndex(K k, int length) {  
    60.         //一般hashCode 取膜法  
    61.         int m=length-1;  
    62.         int index=hash(k.hashCode()) & m;  
    63.         return index >= 0 ? index : -index;  
    64.     }  
    65.   
    66.     //建立本身的hash算法,保證計算出的位置 在數組中均勻分佈  
    67.     private int hash(int hashCode) {  
    68.         hashCode=hashCode^((hashCode>>>20)^(hashCode>>>12));  
    69.         return hashCode^((hashCode>>>7)^(hashCode>>>4));  
    70.     }  
    71.   
    72.     //擴容數組  
    73.     private void up2Size() {  
    74.         Entry<K, V>[] newTable=new Entry[defaultLenth*2];  
    75.         //將原table中的entry從新,散列到新的table中  
    76.         againHash(newTable);  
    77.     }  
    78.   
    79.     //將原table中的entry從新,散列到新的table中  
    80.     private void againHash(Entry<K, V>[] newTable) {  
    81.         //數組裏面對象 封裝到list中,包括同一位置 有列表結構的都解析出來  
    82.         List<Entry<K,V>> entryList=new ArrayList<Entry<K,V>>();  
    83.         for(int i=0;i<table.length;i++){  
    84.             if(table[i]==null){  
    85.                 continue;  
    86.             }  
    87.             findEntryByNext(table[i],entryList);  
    88.         }  
    89.         if(entryList.size()>0){  
    90.             useSize=0;  
    91.             defaultLenth=defaultLenth*2;  
    92.             table=newTable;  
    93.             for (Entry<K, V> entry : entryList) {  
    94.                 if(entry.next!=null){  
    95.                     entry.next=null;  
    96.                 }  
    97.                 put(entry.getKey(), entry.getValue());  
    98.             }  
    99.         }  
    100.     }  
    101.   
    102.     private void findEntryByNext(Entry<K, V> entry, List<Entry<K, V>> entryList) {  
    103.         if(entry!=null && entry.next!=null){  
    104.             //這個entry對象已經造成鏈表結構  
    105.             entryList.add(entry);  
    106.             //遞歸 將鏈表中的entry實體 都一次封裝到entryList鏈表中  
    107.             findEntryByNext(entry.next, entryList);  
    108.         }else{  
    109.             entryList.add(entry);  
    110.         }  
    111.     }  
    112.   
    113.     //快取  
    114.     public V get(K k) {  
    115.         //經過key來計算出 存儲的位置  
    116.         int index=getIndex(k,table.length);  
    117.               
    118.         Entry<K, V> entry=table[index];  
    119.           
    120.         if(entry==null){  
    121.             throw new NullPointerException();  
    122.         }  
    123.   
    124.         return findValueByKey(k,entry);  
    125.     }  
    126.       
    127.     private V findValueByKey(K k, Entry<K, V> entry) {  
    128.           
    129.         if(k == entry.getKey() || k.equals(entry.getKey())){  
    130.             return entry.v;  
    131.         }else if(entry.next!=null){  
    132.             return findValueByKey(k,entry.next);  
    133.         }  
    134.         return null;  
    135.     }  
    136.   
    137.   
    138.     class Entry<K, V> implements DIYMap.Entry<K, V>{  
    139.   
    140.         K k;  
    141.         V v;  
    142.         //指向被this擠壓下去的entry  
    143.         Entry<K, V> next;  
    144.           
    145.         public Entry(K k, V v, Entry<K, V> next) {  
    146.             this.k = k;  
    147.             this.v = v;  
    148.             this.next = next;  
    149.         }  
    150.   
    151.         @Override  
    152.         public K getKey() {  
    153.             return k;  
    154.         }  
    155.   
    156.         @Override  
    157.         public V getValue() {  
    158.             return v;  
    159.         }  
    160.           
    161.     }  
    162. }  

     

  • 看過那些Java集合類的源碼

1.三、進程和線程

  • 線程和進程的概念、並行和併發的概念

  •  

    進程和線程

    進程是一個程序的實例。每一個進程都有本身的虛擬地址空間和控制線程,線程是操做系統調度器(Schduler)分配處理器時間的基礎單元。

    併發:

    講併發以前,要先看一張圖:

    這裏寫圖片描述

    1. Concurrency,是併發的意思。併發的實質是一個物理CPU(也能夠多個物理CPU) 在若干道程序(或線程)之間多路複用,併發性是對有限物理資源強制行使多用戶共享以提升效率。
    2. 微觀角度:全部的併發處理都有排隊等候,喚醒,執行等這樣的步驟,在微觀上他們都是序列被處理的,若是是同一時刻到達的請求(或線程)也會根據優先級的不一樣,而前後進入隊列排隊等候執行。
    3. 宏觀角度:多個幾乎同時到達的請求(或線程)在宏觀上看就像是同時在被處理。
    4. 通俗點講,併發就是隻有一個CPU資源,程序(或線程)之間要競爭獲得執行機會。圖中的第一個階段,在A執行的過程當中B,C不會執行,由於這段時間內這個CPU資源被A競爭到了,同理,第二個階段只有B在執行,第三個階段只有C在執行。其實,併發過程當中,A,B,C並非同時在進行的(微觀角度)。但又是同時進行的(宏觀角度)。

    並行:

    一樣,在講並行以前,要先看一張圖:

    這裏寫圖片描述

    1. Parallelism,即並行,指兩個或兩個以上事件(或線程)在同一時刻發生,是真正意義上的不一樣事件或線程在同一時刻,在不一樣CPU資源呢上(多核),同時執行。
    2. 並行,不存在像併發那樣競爭,等待的概念。
    3. 圖中,A,B,C都在同時運行(微觀,宏觀)。

    經過多線程實現併發,並行:

    1. java中的Thread類定義了多線程,經過多線程能夠實現併發或並行。
    2. 在CPU比較繁忙,資源不足的時候(開啓了不少進程),操做系統只爲一個含有多線程的進程分配僅有的CPU資源,這些線程就會爲本身儘可能多搶時間片,這就是經過多線程實現併發,線程之間會競爭CPU資源爭取執行機會。
    3. 在CPU資源比較充足的時候,一個進程內的多線程,能夠被分配到不一樣的CPU資源,這就是經過多線程實現並行。
    4. 至於多線程實現的是併發仍是並行?上面所說,所寫多線程可能被分配到一個CPU內核中執行,也可能被分配到不一樣CPU執行,分配過程是操做系統所爲,不可人爲控制。全部,若是有人問我我所寫的多線程是併發仍是並行的?我會說,都有可能。
    5. 無論併發仍是並行,都提升了程序對CPU資源的利用率,最大限度地利用CPU資源。
  • 建立線程的方式及實現

  •  

    1. 繼承Thread類建立線程類

     

    [java]  view plain  copy
     
    1. package com.thread;    
    2.     
    3. public class FirstThreadTest extends Thread{    
    4.     int i = 0;    
    5.     //重寫run方法,run方法的方法體就是現場執行體    
    6.     public void run()    
    7.     {    
    8.         for(;i<100;i++){    
    9.         System.out.println(getName()+"  "+i);    
    10.             
    11.         }    
    12.     }    
    13.     public static void main(String[] args)    
    14.     {    
    15.         for(int i = 0;i< 100;i++)    
    16.         {    
    17.             System.out.println(Thread.currentThread().getName()+"  : "+i);    
    18.             if(i==20)    
    19.             {    
    20.                 new FirstThreadTest().run();    
    21.                 new FirstThreadTest().run();    
    22.             }    
    23.         }    
    24.     }    
    25.     
    26. }    


    2. 經過Runable接口建立線程類

     

    [java]  view plain  copy
     
    1. package com.thread;    
    2.     
    3. public class RunnableThreadTest implements Runnable    
    4. {    
    5.     
    6.     private int i;    
    7.     public void run()    
    8.     {    
    9.         for(i = 0;i <100;i++)    
    10.         {    
    11.             System.out.println(Thread.currentThread().getName()+" "+i);    
    12.         }    
    13.     }    
    14.     public static void main(String[] args)    
    15.     {    
    16.         for(int i = 0;i < 100;i++)    
    17.         {    
    18.             System.out.println(Thread.currentThread().getName()+" "+i);    
    19.             if(i==20)    
    20.             {    
    21.                 RunnableThreadTest rtt = new RunnableThreadTest();    
    22.                 new Thread(rtt,"新線程1").start();    
    23.                 new Thread(rtt,"新線程2").start();    
    24.             }    
    25.         }    
    26.     
    27.     }    
    28.     
    29. }    


    3. 經過Callable和FutureTask建立線程

        a. 建立Callable接口的實現類,並實現call()方法;
        b. 建立Callable實現類的實例,使用FutureTask類來包裝Callable對象,該FutureTask對象封裝了該Callback對象的call()方法的返回值;
        c. 使用FutureTask對象做爲Thread對象的target建立並啓動新線程;

        d. 調用FutureTask對象的get()方法來得到子線程執行結束後的返回值。

     

    [java]  view plain  copy
     
    1. package com.demo;  
    2.   
    3. import java.util.concurrent.Callable;    
    4. import java.util.concurrent.ExecutionException;    
    5. import java.util.concurrent.FutureTask;    
    6.     
    7. public class CallableThreadTest implements Callable<Integer>    
    8. {    
    9.     
    10.     public static void main(String[] args)    
    11.     {    
    12.         CallableThreadTest ctt = new CallableThreadTest();    
    13.         FutureTask<Integer> ft = new FutureTask<Integer>(ctt);    
    14. //        Thread thread = new Thread(ft,"有返回值的線程");  
    15. //        thread.start();  
    16.         for(int i = 0;i < 100;i++)    
    17.         {    
    18.             System.out.println(Thread.currentThread().getName()+" 的循環變量i的值"+i);    
    19.             if(i==20)    
    20.             {    
    21.                 new Thread(ft,"有返回值的線程").start();    
    22.             }    
    23.         }    
    24.         try    
    25.         {    
    26.             System.out.println("子線程的返回值:"+ft.get());    
    27.         } catch (InterruptedException e)    
    28.         {    
    29.             e.printStackTrace();    
    30.         } catch (ExecutionException e)    
    31.         {    
    32.             e.printStackTrace();    
    33.         }    
    34.     
    35.     }    
    36.     
    37.     @Override    
    38.     public Integer call() throws Exception    
    39.     {    
    40.         int i = 0;    
    41.         for(;i<100;i++)    
    42.         {    
    43.             System.out.println(Thread.currentThread().getName()+" "+i);    
    44.         }    
    45.         return i;    
    46.     }    
    47.     
    48. }    

     

    4. 經過線程池建立線程

    [java]  view plain  copy
     
    1. /** 
    2.  *  
    3.  */  
    4. package com.demo;  
    5.   
    6. import java.util.concurrent.ExecutorService;  
    7. import java.util.concurrent.Executors;  
    8.   
    9. /** 
    10.  * @author Maggie 
    11.  * 
    12.  */  
    13. public class ThreadPool   
    14. {  
    15.     /* POOL_NUM */  
    16.     private static int POOL_NUM = 10;  
    17.       
    18.     /** 
    19.      * Main function 
    20.      */  
    21.     public static void main(String[] args)  
    22.     {  
    23.         ExecutorService executorService = Executors.newFixedThreadPool(5);  
    24.         for(int i = 0; i<POOL_NUM; i++)  
    25.         {  
    26.             RunnableThread thread = new RunnableThread();  
    27.             executorService.execute(thread);  
    28.         }  
    29.     }  
    30. }  
    31.   
    32. class RunnableThread implements Runnable  
    33. {  
    34.     private int THREAD_NUM = 10;  
    35.     public void run()  
    36.     {  
    37.         for(int i = 0; i<THREAD_NUM; i++)  
    38.         {  
    39.             System.out.println("線程" + Thread.currentThread() + " " + i);  
    40.         }   
    41.     }  
    42. }  
  • 進程間通訊的方式(線程間通訊

  •  

    1.管道(pipe):

         管道可用於具備親緣關係進程間的通訊,有名管道除了具備管道所具備的功能外,它還容許無親緣關係進程間的通訊。

       2.信號(signal):

         信號是在軟件層次上對中斷機制的一種模擬,它是比較複雜的通訊方式,用於通知進程有某事件發生,一個進程收到一個信號與處理器收到一箇中斷請求效果上能夠說是一致得。

       3.消息隊列(message queue):

         消息隊列是消息的連接表,它克服了上兩種通訊方式中信號量有限的缺點,具備寫權限得進程能夠按照必定得規則向消息隊列中添加新信息;對消息隊列有讀權限得進程則能夠從消息隊列中讀取信息。

       4.共享內存(shared memory):

         能夠說這是最有用的進程間通訊方式。它使得多個進程能夠訪問同一塊內存空間,不一樣進程能夠及時看到對方進程中對共享內存中數據得更新。這種方式須要依靠某種同步操做,如互斥鎖和信號量等。

       5.信號量(semaphore):

         主要做爲進程之間及同一種進程的不一樣線程之間得同步和互斥手段。

       6.套接字(socket);

         這是一種更爲通常得進程間通訊機制,它可用於網絡中不一樣機器之間的進程間通訊,應用很是普遍。

  • 說說 CountDownLatch、CyclicBarrier 原理和區別(線程間的通訊)(例子

  • 1.閉鎖CountDownLatch作減計數,而柵欄CyclicBarrier則是加計數。
    2.CountDownLatch是一次性的,CyclicBarrier能夠重用。
    3.CountDownLatch強調一個線程等多個線程完成某件事情。CyclicBarrier是多個線程互等,等你們都完成。
    4.鑑於上面的描述,CyclicBarrier在一些場景中能夠替代CountDownLatch實現相似的功能。

    另外,值得一提的是,CountDownLatch和CyclicBarrier在建立和啓動線程時,都沒有明確提到同時啓動所有線程,事實上這在技術上是不大可能,沒必要要,不提倡的。

  • 說說 Semaphore 原理(代碼

  •  

    Semaphore(信號量)是用來控制同時訪問特定資源的線程數量,它經過協調各個線程,以保證合理的使用公共資源,就比如如今的旅遊景點限流。

    主要方法:
     * acquire():今後信號量獲取一個許可,在提供一個許可前一直將線程阻塞,不然線程被中斷。 獲取一個許可(若是提供了一個)並當即返回,將可用的許可數減 1。
     * release():釋放一個許可,將其返回給信號量,即:將可用的許可數增長 1protected方法。

  • 說說 Exchanger 原理(代碼

  •  

    Java併發API提供了一種容許2個併發任務間相互交換數據的同步應用。更具體的說,Exchanger類容許在2個線程間定義同步點,當2個線程到達這個點,他們相互交換數據類型,使用第一個線程的數據類型變成第二個的,而後第二個線程的數據類型變成第一個的。

    用於實現兩我的之間的數據交換,每一個人在完成必定的事務後想與對方交換數據,第一個先拿出數據的人將一直等待第二我的拿着數據到來時,才能彼此交換數據。

  • ThreadLocal 原理分析,ThreadLocal爲何會出現OOM,出現的深層次原理(代碼)(代碼

  •  

    ThreadLocal類用來提供線程內部的局部變量。這些變量在多線程環境下訪問(經過get或set方法訪問)時能保證各個線程裏的變量相對獨立於其餘線程內的變量,ThreadLocal實例一般來講都是private static類型。 
    總結:ThreadLocal不是爲了解決多線程訪問共享變量,而是爲每一個線程建立一個單獨的變量副本,提供了保持對象的方法和避免參數傳遞的複雜性。

    ThreadLocal的主要應用場景爲按線程多實例(每一個線程對應一個實例)的對象的訪問,而且這個對象不少地方都要用到。例如:同一個網站登陸用戶,每一個用戶服務器會爲其開一個線程,每一個線程中建立一個ThreadLocal,裏面存用戶基本信息等,在不少頁面跳轉時,會顯示用戶信息或者獲得用戶的一些信息等頻繁操做,這樣多線程之間並無聯繫並且當前線程也能夠及時獲取想要的數據。

  • 講講線程池的實現原理(代碼

  • 多線程技術主要解決處理器單元內多個線程執行的問題,它能夠顯著減小處理器單元的閒置時間,增長處理器單元的吞吐能力。    
        假設一個服務器完成一項任務所需時間爲:T1 建立線程時間,T2 在線程中執行任務的時間,T3 銷燬線程時間。

        若是:T1 + T3 遠大於 T2,則能夠採用線程池,以提升服務器性能。
                    一個線程池包括如下四個基本組成部分:
                    一、線程池管理器(ThreadPool):用於建立並管理線程池,包括 建立線程池,銷燬線程池,添加新任務;
                    二、工做線程(PoolWorker):線程池中線程,在沒有任務時處於等待狀態,能夠循環的執行任務;
                    三、任務接口(Task):每一個任務必須實現的接口,以供工做線程調度任務的執行,它主要規定了任務的入口,任務執行完後的收尾工做,任務的執行狀態等;
                    四、任務隊列(taskQueue):用於存放沒有處理的任務。提供一種緩衝機制。
                    
        線程池技術正是關注如何縮短或調整T1,T3時間的技術,從而提升服務器程序性能的。它把T1,T3分別安排在服務器程序的啓動和結束的時間段或者一些空閒的時間段,這樣在服務器程序處理客戶請求時,不會有T1,T3的開銷了。
        線程池不只調整T1,T3產生的時間段,並且它還顯著減小了建立線程的數目,看一個例子:
        假設一個服務器一天要處理50000個請求,而且每一個請求須要一個單獨的線程完成。在線程池中,線程數通常是固定的,因此產生線程總數不會超過線程池中線程的數目,而若是服務器不利用線程池來處理這些請求則線程總數爲50000。通常線程池大小是遠小於50000。因此利用線程池的服務器程序不會爲了建立50000而在處理請求時浪費時間,從而提升效率。

     

        代碼實現中並無實現任務接口,而是把Runnable對象加入到線程池管理器(ThreadPool),而後剩下的事情就由線程池管理器(ThreadPool)來完成了

     

    Java經過ThreadPoolExecutor提供線程池:

    ThreadPoolExecutor做爲java.util.concurrent包對外提供基礎實現,之內部線程池的形式對外提供管理任務執行,線程調度,線程池管理等等服務; 

    線程池的參數:
    corePoolSize 爲核心線程;
    maximunPoolSize爲最大線程;
    keepAliveTime爲最長生命時間;
    unit是其時間單位;
    workQueue任務隊列;
    handler是過多線程以後的策略
    [java]  view plain  copy
     
     
     
    1. ExecutorService singleThreadPool = new ThreadPoolExecutor(4,  
    2.         10,  
    3.         0L,  
    4.         TimeUnit.MILLISECONDS,  
    5.         new LinkedBlockingQueue<Runnable>(1024),  
    6.         namedThreadFactory,  
    7.         new ThreadPoolExecutor.AbortPolicy());  
  • 線程池的幾種實現方式(代碼)(代碼

  • newCachedThreadPool建立一個可緩存線程池,若是線程池長度超過處理須要,可靈活回收空閒線程,若無可回收,則新建線程。
    newFixedThreadPool 建立一個定長線程池,可控制線程最大併發數,超出的線程會在隊列中等待。
    newScheduledThreadPool 建立一個定長線程池,支持定時及週期性任務執行。
    newSingleThreadExecutor 建立一個單線程化的線程池,它只會用惟一的工做線程來執行任務,保證全部任務按照指定順序(FIFO, LIFO, 優先級)執行。

  • 線程的生命週期,狀態是如何轉移的

  •  

    線程的生命週期開始:當Thread對象建立完成時

    線程的生命週期結束:①當run()方法中代碼正常執行完畢

                                        ②線程拋出一個未捕獲的異或錯誤時。

    線程整個生命週期的五個階段:

    新建狀態,就緒狀態,運行狀態,阻塞狀態,死亡狀態。

    新建狀態:
            當Thread對象建立完成時, 使用 new 關鍵字和 Thread 類或其子類創建一個線程對象後,該線程對象就處於新建狀態。但此時它還不能運行,僅僅由虛擬機爲其分配了內存,它保持這個狀態直到程序 start() 這個線程。


    就緒狀態:
           當線程對象調用了start()方法以後,該線程就進入就緒狀態。就緒狀態的線程處於就緒隊列(可運行池裏)中,此時它具有了運行的條件,可否得到CPU的使用權開始運行,還須要等待系統的調度。


    運行狀態:
         若是就緒狀態的線程得到CPU的使用權,開始執行 run()中的線程執行體,此時線程便處於運行狀態。當使用完系統分配的時間後,系統就會剝奪該線程佔用的CPU資源,讓其餘線程得到執行的機會。處於運行狀態的線程最爲複雜,它能夠變爲阻塞狀態、就緒狀態和死亡狀態。


    阻塞狀態:
    一個正在線程的線程在某種特殊形況下,如執行了耗時的輸入/輸出操做時,sleep(睡眠)、suspend(掛起)等方法,失去所佔用資源以後,該線程就從運行狀態進入阻塞狀態。在睡眠時間已到或得到設備資源後能夠從新進入就緒狀態。能夠分爲三種:
    等待阻塞:運行狀態中的線程執行 wait() 方法,使線程進入到等待阻塞狀態。,若想再此進入就緒狀態就須要使用notify()方法喚醒該線程。
    同步阻塞:線程在獲取 synchronized 同步鎖失敗(由於同步鎖被其餘線程佔用)。
    其餘阻塞:經過調用線程的 sleep() 、或 join() 發出了 I/O 請求時,線程就會進入到阻塞狀態。當sleep() 方法時間到了以後,join() 新加的線程運行結束後, I/O 處理完畢,線程從新轉入就緒狀態。


    死亡狀態:
    一個運行狀態的線程完成任務或者其餘終止條件發生時,該線程就切換到終止狀態。

  • 可參考:《Java多線程編程核心技術

1.四、鎖機制

  • 說說線程安全問題,什麼是線程安全,如何保證線程安全

  •  

    線程安全就是多線程訪問時,採用了加鎖機制,當一個線程訪問該類的某個數據時,進行保護,其餘線程不能進行訪問直到該線程讀取完,其餘線程纔可以使用。不會出現數據不一致或者數據污染。

     

    1. 不共享線程間的變量;
    2. 設置屬性變量爲不可變變量;
    3. 每一個共享的可變變量都使用一個肯定的鎖保護;
    4. 1使用線程安全的類 
      2使用synchronized同步代碼塊,或者用Lock鎖 
      3多線程併發狀況下,線程共享的變量改成方法局部級變量

     

  • 重入鎖的概念,重入鎖爲何能夠防止死鎖(代碼)(代碼

  • 所謂重入鎖,指的是以線程爲單位,當一個線程獲取對象鎖以後,這個線程能夠再次獲取本對象上的鎖,而其餘的線程是不能夠的
     *synchronized 和   ReentrantLock 都是可重入鎖
     *可重入鎖的意義在於防止死鎖
     *實現原理實現是經過爲每一個鎖關聯一個請求計數和一個佔有它的線程。
     *當計數爲0時,認爲鎖是未被佔有的。線程請求一個未被佔有的鎖時,jvm將記錄鎖的佔有者,而且講請求計數器置爲1 。
     *若是同一個線程再次請求這個鎖,計數將遞增;
     *每次佔用線程退出同步塊,計數器值將遞減。直到計數器爲0,鎖被釋放。

  • 產生死鎖的四個條件(互斥、請求與保持、不剝奪、循環等待)(代碼

  • (1) 互斥條件:一個資源每次只能被一個進程使用。
    (2) 佔有且等待:一個進程因請求資源而阻塞時,對已得到的資源保持不放。
    (3)不可強行佔有:進程已得到的資源,在末使用完以前,不能強行剝奪。
    (4) 循環等待條件:若干進程之間造成一種頭尾相接的循環等待資源關係。
    這四個條件是死鎖的必要條件,只要系統發生死鎖,這些條件必然成立,而只要上述條件之

    一不知足,就不會發生死鎖。

  • 如何檢查死鎖(經過jConsole檢查死鎖)

  •  

    Jconsole

     

    Jconsole是JDK自帶的圖形化界面工具。

    1. 使用JDK給咱們的的工具JConsole,能夠經過打開cmd而後輸入jconsole打開。

    2. 鏈接到須要查看的進程。

  •  

    Jstack

     

    Jstack是JDK自帶的命令行工具,主要用於線程Dump分析。

    1. 咱們先用Jps來查看java進程id。 2.看一下jstack的使用。
  • volatile 實現原理(禁止指令重排、刷新內存)(代碼)

  • synchronized 實現原理(對象監視器)

  • 這兩段話就解釋了synchronized的實現原理: 
       
      monitorenter: 
      每一個對象有一個monitor,即監視器,當且僅當monitor被佔用時,這個monitor就被鎖住了。線程執行monitorenter指令是爲了嘗試獲取該monitor的全部權,過程爲: 
      1) 若是一個monitor的進入數爲0,那麼該線程直接進入monitor,而且將monitor進入數置爲1,該線程成爲該monitor的全部者; 
      2) 若是該進程是已經佔用該monitor,則直接進入,而且monitor進入數加1; 
      3)若是該進程未佔有該monitor,即monitor被其餘線程所佔有,那麼該線程會被阻塞,直到該monitor的進入數變爲0,此時該線程會再次嘗試獲取該monitor。 
       
      monitorexit: 
      執行monitorexit指令的線程必須是已經擁有該monitor的線程,執行monitorexit指令後,該monitor的進入數減1,直到該monitor的進入數減爲0,此時該線程再也不是該monitor的全部者,其餘被阻塞進入該monitor的線程能夠嘗試獲取該monitor的全部權。 

  • synchronized 與 lock 的區別(代碼

  •  

    類別 synchronized Lock
    存在層次 Java的關鍵字,在jvm層面上 是一個類
    鎖的釋放 一、以獲取鎖的線程執行完同步代碼,釋放鎖 二、線程執行發生異常,jvm會讓線程釋放鎖 在finally中必須釋放鎖,否則容易形成線程死鎖
    鎖的獲取 假設A線程得到鎖,B線程等待。若是A線程阻塞,B線程會一直等待 分狀況而定,Lock有多個鎖獲取的方式,具體下面會說道,大體就是能夠嘗試得到鎖,線程能夠不用一直等待
    鎖狀態 沒法判斷 能夠判斷
    鎖類型 可重入 不可中斷 非公平 可重入 可判斷 可公平(二者皆可)
    性能 少許同步 大量同步
  • AQS同步隊列(代碼

  • 隊列同步器(簡稱:同步器)AbstractQueuedSynchronizer(英文簡稱:AQS,也是面試官常問的什麼是AQS的AQS),是用來構建鎖或者其餘同步組件的基礎框架,它使用了一個int成員變量表示同步狀態,經過內置的FIFO隊列來完成資源獲取線程的排隊工做。

  • CAS無鎖的概念、樂觀鎖和悲觀鎖(樂觀鎖、悲觀鎖)(CAS)(代碼)

  • CAS的語義是「我認爲V的值應該爲A,若是是,那麼將V的值更新爲B,不然不修改並告訴V的值實際爲多少」,CAS是項 樂觀鎖 技術,當多個線程嘗試使用CAS同時更新同一個變量時,只有其中一個線程能更新變量的值,而其它線程都失敗,失敗的線程並不會被掛起,而是被告知此次競爭中失敗,並能夠再次嘗試。CAS有3個操做數,內存值V,舊的預期值A,要修改的新值B。當且僅當預期值A和內存值V相同時,將內存值V修改成B,不然什麼都不作。 

  • 常見的原子操做類(代碼

  •  

    • AtomicBoolean:原子更新布爾變量
    • AtomicInteger:原子更新整型變量
    • AtomicLong:原子更新長整型變量

     

  • 什麼是ABA問題,出現ABA問題JDK是如何解決的(代碼

  • 樂觀鎖的業務場景及實現方式(代碼

  • Java 8並法包下常見的併發類(代碼

  • 偏向鎖、輕量級鎖、重量級鎖、自旋鎖的概念(各類鎖

  • 可參考:《Java多線程編程核心技術

1.五、JVM

  • JVM運行時內存區域劃分(代碼)

  •  

    程序計數器(Program Counter Register)、Java棧(VM Stack)、本地方法棧(Native Method Stack)、方法區(Method Area)、堆(Heap)。

      如上圖所示,JVM中的運行時數據區應該包括這些部分。在JVM規範中雖然規定了程序在執行期間運行時數據區應該包括這幾部分,可是至於具體如何實現並無作出規定,不一樣的虛擬機廠商能夠有不一樣的實現方式

  • 內存溢出OOM和堆棧溢出SOE的示例及緣由、如何排查與解決(代碼

  • 如何判斷對象是否能夠回收或存活(代碼

  • 常見的GC回收算法及其含義(代碼

  • 常見的JVM性能監控和故障處理工具類:jps、jstat、jmap、jinfo、jconsole等(代碼

  • JVM如何設置參數(代碼

  • JVM性能調優(代碼

  • 類加載器、雙親委派模型、一個類的生命週期、類是如何加載到JVM中的(代碼

  • 類加載的過程:加載、驗證、準備、解析、初始化

  •  

    1. 加載(Loading);
    2. 驗證(Verification);
    3. 準備 (Preparation);
    4. 解析(Resolution);
    5. 初始化(Initialization);
    6. 使用(Using)
    7. 卸載 (Unloading)

    其中驗證、準備和解析三部分稱爲鏈接,在Java語言中,類型的加載和鏈接過程都是在程序運行期間完成的(Java能夠動態擴展的語言特性就是依賴運行期動態加載、動態鏈接這個特色實現的),這樣會在類加載時稍微增長一些性能開銷,可是卻爲Java應用程序提供高度的靈活性 
    加載、驗證、準備、初始化和卸載這5個階段的順序是固定的(即:加載階段必須在驗證階段開始以前開始,驗證階段必須在準備階段開始以前開始等。這些階段都是互相交叉地混合式進行的,一般會在一個階段的執行過程當中調用或激活另外一個階段),解析階段則不必定,在某些狀況下,解析階段有可能在初始化階段結束後開始,以支持Java的動態綁定(動態綁定是指在執行期間(非編譯期)判斷所引用對象的實際類型,根據其實際的類型調用其相應的方法。程序運行過程當中,把函數(或過程)調用與響應調用所須要的代碼相結合的過程稱爲動態綁定。)

  • 強引用、軟引用、弱引用、虛引用

  • 1.強引用 
    之前咱們使用的大部分引用實際上都是強引用,這是使用最廣泛的引用。若是一個對象具備強引用,那就相似於必不可少的生活用品,垃圾回收器毫不會回收它。當內存空 間不足,Java虛擬機寧願拋出OutOfMemoryError錯誤,使程序異常終止,也不會靠隨意回收具備強引用的對象來解決內存不足問題。 

  •  

  •  

  •  

  • 強引用: 

  • Java內存模型JMM(代碼

1.六、設計模式

  • 常見的設計模式

  • 設計模式的的六大原則及其含義

  • 常見的單例模式以及各類實現方式的優缺點,哪種最好,手寫常見的單例模式

  • 設計模式在實際場景中的應用

  • Spring中用到了哪些設計模式

  • MyBatis中用到了哪些設計模式

  • 你項目中有使用哪些設計模式

  • 說說經常使用開源框架中設計模式使用分析

  • 動態代理很重要!!!

1.七、數據結構

  • 樹(二叉查找樹、平衡二叉樹、紅黑樹、B樹、B+樹)

  • 深度有限算法、廣度優先算法

  • 克魯斯卡爾算法、普林母算法、迪克拉斯算法

  • 什麼是一致性Hash及其原理、Hash環問題

  • 常見的排序算法和查找算法:快排、折半查找、堆排序等

1.八、網絡/IO基礎

    • BIO、NIO、AIO的概念

    •  

      1.Java對BIO、NIO、AIO的支持: 
      ① Java BIO : 同步並阻塞,服務器實現模式爲一個鏈接一個線程,即客戶端有鏈接請求時服務器端就須要啓動一個線程進行處理,若是這個鏈接不作任何事情會形成沒必要要的線程開銷,固然能夠經過線程池機制改善。 
      ② Java NIO : 同步非阻塞,服務器實現模式爲一個請求一個線程,即客戶端發送的鏈接請求都會註冊到多路複用器上,多路複用器輪詢到鏈接有I/O請求時才啓動一個線程進行處理。 
      ③ Java AIO(NIO.2) : 異步非阻塞,服務器實現模式爲一個有效請求一個線程,客戶端的I/O請求都是由OS先完成了再通知服務器應用去啓動線程進行處理,

      2.BIO、NIO、AIO適用場景分析: 
      ① BIO方式適用於鏈接數目比較小且固定的架構,這種方式對服務器資源要求比較高,併發侷限於應用中,JDK1.4之前的惟一選擇,但程序直觀簡單易理解。 
      ② NIO方式適用於鏈接數目多且鏈接比較短(輕操做)的架構,好比聊天服務器,併發侷限於應用中,編程比較複雜,JDK1.4開始支持。 
      ③ AIO方式使用於鏈接數目多且鏈接比較長(重操做)的架構,好比相冊服務器,充分調用OS參與併發操做,編程比較複雜,JDK7開始支持。

    •  

      3.Java NIO和IO的主要區別

      IO NIO
      面向流 面向緩衝
      阻塞IO 非阻塞IO
      選擇器

      面向流與面向緩衝 
      Java NIO和IO之間第一個最大的區別是,IO是面向流的,NIO是面向緩衝區的。 Java IO面向流意味着每次從流中讀一個或多個字節,直至讀取全部字節,它們沒有被緩存在任何地方。此外,它不能先後移動流中的數據。若是須要先後移動從流中讀取的數據,須要先將它緩存到一個緩衝區。 Java NIO的緩衝導向方法略有不一樣。數據讀取到一個它稍後處理的緩衝區,須要時可在緩衝區中先後移動。這就增長了處理過程當中的靈活性。可是,還須要檢查是否該緩衝區中包含全部您須要處理的數據。並且,需確保當更多的數據讀入緩衝區時,不要覆蓋緩衝區裏還沒有處理的數據。 
      阻塞與非阻塞IO 
      Java IO的各類流是阻塞的。這意味着,當一個線程調用read() 或 write()時,該線程被阻塞,直到有一些數據被讀取,或數據徹底寫入。該線程在此期間不能再幹任何事情了。 Java NIO的非阻塞模式,使一個線程從某通道發送請求讀取數據,可是它僅能獲得目前可用的數據,若是目前沒有數據可用時,就什麼都不會獲取。而不是保持線程阻塞,因此直至數據變的能夠讀取以前,該線程能夠繼續作其餘的事情。 非阻塞寫也是如此。一個線程請求寫入一些數據到某通道,但不須要等待它徹底寫入,這個線程同時能夠去作別的事情。 線程一般將非阻塞IO的空閒時間用於在其它通道上執行IO操做,因此一個單獨的線程如今能夠管理多個輸入和輸出通道(channel)。 
      選擇器(Selectors) 
      Java NIO的選擇器容許一個單獨的線程來監視多個輸入通道,你能夠註冊多個通道使用一個選擇器,而後使用一個單獨的線程來「選擇」通道:這些通道里已經有能夠處理的輸入,或者選擇已準備寫入的通道。這種選擇機制,使得一個單獨的線程很容易來管理多個通道。

    • 什麼是長鏈接和短鏈接(代碼)

    • Http1.0和2.0相比有什麼區別,可參考《Http 2.0》(代碼

    • Https的基本概念(代碼

    • 三次握手和四次揮手、爲何揮手須要四次(代碼)(代碼

    • 從瀏覽器中輸入URL到頁面加載的發生了什麼?可參考《代碼

    • TCP和UDP(代碼)(代碼

2、數據存儲和消息隊列

2.一、數據庫

  • MySQL 索引使用的注意事項(點擊打開連接)

  •  

    1.WHERE字句的查詢條件裏有 NOT IN 、<>、!=,MYSQL將沒法使用索引;

    2.WHERE字句的查詢條件裏使用了函數,MYSQL將沒法使用索引

    3.在JOIN操做中,MYSQL只有在主鍵和外鍵的數據類型相同時才能使用索引,不然即便創建了索引也不會使用

    4.使用了比較操做符LIKE和REGEXP,MYSQL只有在搜索模板的第一個字符不是通配符的狀況下才能使用索引。好比說,若是查詢條件是LIKE 'abc%',MYSQL將使用索引;若是條件是LIKE '%abc'或者'_abc%',MYSQL將不使用索引。

    5.在ORDER BY操做中,MYSQL只有在排序條件不是一個查詢條件表達式的狀況下才使用索引。儘管如此,在涉及多個數據表的查詢裏,即便有索引可用,那些索引在加快ORDER BY操做方面也沒什麼做用。

    使用order by特別提示:
    1>mysql一次查詢只能使用一個索引。若是要對多個字段使用索引,創建複合索引。
    2>在ORDER BY操做中,MySQL只有在排序條件不是一個查詢條件表達式的狀況下才使用索引。

    6.若是某個數據列裏包含着許多重複的值,就算爲它創建了索引也不會有很好的效果。好比說,若是某個數據列裏包含了淨是些諸如「0/1」或「Y/N」等值,就沒有必要爲它建立一個索引。

    7.使用短索引: 對串列進行索引,若是能夠就應該指定一個前綴長度。例如,若是有一個char(255)的列,若是在前10個或20個字符內,多數值是惟一的,那麼就不要對整個列進行索引。短索引不只能夠提升查詢速度並且能夠節省磁盤空間和I/O操做。(針對hash的索引方式,對每一個值都作hash值存儲I/O操做存儲索引信息)

    8.若是條件中有or(而且其中有or的條件是不帶索引的),即便其中有條件帶索引也不會使用(這也是爲何儘可能少用or的緣由)。注意:要想使用or,又想讓索引生效,只能將or條件中的每一個列都加上索引

    9.若是列類型是字符串,那必定要在條件中將數據使用引號引用起來,不然不使用索引

    10.對於那些定義爲text、image和bit數據類型的列不該該增長索引。由於這些列的數據量要麼至關大,要麼取值不多。

    11.只要列中包含有NULL值,都將不會被包含在索引中,複合索引中只要有一列含有NULL值,那麼這一列對於此符合索引就是無效的。

    12.組合索引之最左前綴:顧名思義,就是最左優先,上例中咱們建立了name_age_course多列索引,至關於建立了(name)單列索引,(name,age)組合索引以及(name,age,course)組合索引。在單獨使用(age)、(age,course)等條件下索引無效

  • DDL、DML、DCL分別指什麼

  • DML(data manipulation language): 
    它們是SELECT、UPDATE、INSERT、DELETE,就象它的名字同樣,這4條命令是用來對數據庫裏的數據進行操做的語言 
    DDL(data definition language): 
    DDL比DML要多,主要的命令有CREATE、ALTER、DROP等,DDL主要是用在定義或改變表(TABLE)的結構,數據類型,表之間的連接和約束等初始化工做上,他們大多在創建表時使用 
    DCL(Data Control Language): 
    是數據庫控制功能。是用來設置或更改數據庫用戶或角色權限的語句,包括(grant,deny,revoke等)語句。在默認狀態下,只有sysadmin,dbcreator,db_owner或db_securityadmin等人員纔有權力執行DCL

  • explain命令

  • 在工做中,咱們用於捕捉性能問題最經常使用的就是打開慢查詢,定位執行效率差的SQL,那麼當咱們定位到一個SQL之後還不算完事,咱們還須要知道該SQL的執行計劃,好比是全表掃描,仍是索引掃描,這些都須要經過EXPLAIN去完成。EXPLAIN命令是查看優化器如何決定執行查詢的主要方法。能夠幫助咱們深刻了解MySQL的基於開銷的優化器,還能夠得到不少可能被優化器考慮到的訪問策略的細節,以及當運行SQL語句時哪一種策略預計會被優化器採用。須要注意的是,生成的QEP並不肯定,它可能會根據不少因素髮生改變。MySQL不會將一個QEP和某個給定查詢綁定,QEP將由SQL語句每次執行時的實際狀況肯定,即使使用存儲過程也是如此。儘管在存儲過程當中SQL語句都是預先解析過的,但QEP仍然會在每次調用存儲過程的時候才被肯定。

  • left join,right join,inner join(點擊打開連接)

  • 數據庫事物ACID(原子性、一致性、隔離性、持久性)(點擊打開連接)

  • 事物的隔離級別(讀未提交、讀以提交、可重複讀、可序列化讀)(點擊打開連接)

  • 一、TransactionDefinition接口中定義五個隔離級別(isolation):

  • 髒讀、幻讀、不可重複讀

  •  髒讀:一個事務讀取了另外一個事務改寫但還未提交的數據,若是這些數據被回滾,則讀到的數據是無效的。
     不可重複讀:在同一事務中,屢次讀取到同一數據的結果有所不一樣。也就是說,後續讀取能夠讀到另外一個事務已經提交的更新數據。
     幻讀:一個事務讀取了幾行記錄後,另外一個事務插入一些記錄,幻讀就發生了,再查詢的時候,第一個事務就會發現有些原來沒有的記錄。

  • 數據庫的幾大範式(點擊打開連接)

  •  

    第一範式(1NF): 強調的是列的原子性,即列不可以再分紅其餘幾列。(屬性存在子集)

    第二範式(2NF): 首先是 1NF,另外包含兩部份內容,一是表必須有一個主鍵;二是沒有包含在主鍵中的列必須徹底依賴於主鍵,而不能只依賴於主鍵的一部分。 

     第三範式(3NF):首先是 2NF,另外非主鍵列必須直接依賴於主鍵,不能存在傳遞依賴。即不能存在:非主鍵列 A 依賴於非主鍵列                               B,非主鍵列 B 依賴於主鍵的狀況。(A->B  C->A這裏得出結論C->B就是傳遞依賴,箭頭理解:B依賴A)

  • 數據庫常見的命令

  • 說說分庫與分表設計(點擊打開連接)

  • 分庫與分錶帶來的分佈式困境與應對之策(如何解決分佈式下的分庫分表,全局表?)(點擊打開連接)

  • 說說 SQL 優化之道(點擊打開連接)

  •  

    *當只要一行數據時使用 LIMIT 1   **MySQL數據庫引擎會在找到一條數據後中止搜索,而不是繼續日後查少下一條符合記錄的數據

    *千萬不要 ORDER BY RAND()

    *避免 SELECT * 

     *應儘可能避免在 where 子句中對字段進行表達式操做

     *應儘可能避免在where子句中對字段進行函數操做

     *不少時候用 exists 代替 in 是一個好的選擇

     *應儘可能避免在 where 子句中使用 != 或 <> 操做符

     *對於連續的數值,能用 between 就不要用 in 

     *應儘可能避免在 where 子句中使用 or 來鏈接條件  **若是一個字段有索引,一個字段沒有索引,將致使引擎放棄使用索引而進行全表掃描

     *通常來講,預判一下過濾條件的範圍。因爲數據庫是從後向前解析 SQL 語句的,一般建議把能過濾最多結果的條件放在後面,(不是必定的,mysql會根據索引作一些優化),儘可能使過濾數據量大的條件先被執行

     *Join語句的優化   **儘量減小Join語句中的NestedLoop的循環總次數;「永遠用小結果集驅動大的結果集」

     *ORDER BY的實現與優化  **優化Query語句中的ORDER BY的時候,儘量利用已有的索引來避免實際的排序計算(order字段儘可能出如今條件中,而且有索引),能夠很大幅度的提高ORDER BY操做的性能。

    *GROUP BY的實現與優化   **因爲GROUP BY實際上也一樣須要進行排序操做,並且與ORDER BY相比,GROUP BY主要只是多了排序以後的分組操做。固然,若是在分組的時候還使用了其餘的一些聚合函數,那麼還須要一些聚合函數的計算。因此,在GROUP BY的實現過程當中,與ORDER BY同樣也能夠利用到索引。

  • MySQL遇到的死鎖問題、如何排查與解決(點擊打開連接)

  • 存儲引擎的 InnoDB與MyISAM區別,優缺點,使用場景

  • 主要區別:

    • 1).MyISAM是非事務安全型的,而InnoDB是事務安全型的。
    • 2).MyISAM鎖的粒度是表級,而InnoDB支持行級鎖定。
    • 3).MyISAM支持全文類型索引,而InnoDB不支持全文索引。
    • 4).MyISAM相對簡單,因此在效率上要優於InnoDB,小型應用能夠考慮使用MyISAM。
    • 5).MyISAM表是保存成文件的形式,在跨平臺的數據轉移中使用MyISAM存儲會省去很多的麻煩。
    • 6).InnoDB表比MyISAM表更安全,能夠在保證數據不會丟失的狀況下,切換非事務表到事務表(alter table tablename type=innodb)。
    應用場景:
    • 1).MyISAM管理非事務表。它提供高速存儲和檢索,以及全文搜索能力。若是應用中須要執行大量的SELECT查詢,那麼MyISAM是更好的選擇。
    • 2).InnoDB用於事務處理應用程序,具備衆多特性,包括ACID事務支持。若是應用中須要執行大量的INSERT或UPDATE操做,則應該使用InnoDB,這樣能夠提升多用戶併發操做的性能。
  • 索引類別(B+樹索引、全文索引、哈希索引)、索引的原理

  • 什麼是自適應哈希索引(AHI)

  • 爲何要用 B+tree做爲MySQL索引的數據結構

  • 彙集索引與非彙集索引的區別(點擊打開連接)

根本區別

    彙集索引和非彙集索引的根本區別是表記錄的排列順序和與索引的排列順序是否一致。

彙集索引

    彙集索引表記錄的排列順序和索引的排列順序一致,因此查詢效率快,只要找到第一個索引值記錄,其他就連續性的記錄在物理也同樣連續存放。彙集索引對應的缺點就是修改慢,由於爲了保證表中記錄的物理和索引順序一致,在記錄插入的時候,會對數據頁從新排序。

非彙集索引

    非彙集索引制定了表中記錄的邏輯順序,可是記錄的物理和索引不必定一致,兩種索引都採用B+樹結構,非彙集索引的葉子層並不和實際數據頁相重疊,而採用葉子層包含一個指向表中的記錄在數據頁中的指針方式。非彙集索引層次多,不會形成數據重排。

例子對比兩種索引

    彙集索引就相似新華字典中的拼音排序索引,都是按順序進行,例如找到字典中的「愛」,就裏面順序執行找到「癌」。而非彙集索引則相似於筆畫排序,索引順序和物理順序並非按順序存放的。

  • 遇到過索引失效的狀況沒,何時可能會出現,如何解決

  •  

    1. 若是條件中有or,即便其中有條件帶索引也不會使用(這也是爲何儘可能少用or的緣由)

      注意:要想使用or,又想讓索引生效,只能將or條件中的每一個列都加上索引

      2.對於多列索引,不是使用的第一部分,則不會使用索引

      3.like查詢是以%開頭(以%結尾是能夠的)

      4.若是列類型是字符串,那必定要在條件中將數據使用引號引用起來,不然不使用索引

      5.若是mysql估計使用全表掃描要比使用索引快,則不使用索引

  • limit 20000 加載很慢怎麼解決(點擊打開連接

  • 如何選擇合適的分佈式主鍵方案(點擊打開連接)

  • 選擇合適的數據存儲方案

  • 常見的幾種分佈式ID的設計方案(點擊打開連接)

  •  

    • 1. UUID

      UUID是Universally Unique Identifier的縮寫,它是在必定的範圍內(從特定的名字空間到全球)惟一的機器生成的標識符,UUID是16字節128位長的數字,一般以36字節的字符串表示,好比:3F2504E0-4F89-11D3-9A0C-0305E82C3301。

      UUID經由必定的算法機器生成,爲了保證UUID的惟一性,規範定義了包括網卡MAC地址、時間戳、名字空間(Namespace)、隨機或僞隨機數、時序等元素,以及從這些元素生成UUID的算法。UUID的複雜特性在保證了其惟一性的同時,意味着只能由計算機生成。

      優勢:
      • 本地生成ID,不須要進行遠程調用,時延低,性能高。
      缺點:
      • UUID過長,16字節128位,一般以36長度的字符串表示,不少場景不適用,好比用UUID作數據庫索引字段。
      • 沒有排序,沒法保證趨勢遞增。
    • 2. Flicker方案

      這個方案是由Flickr團隊提出,主要思路採用了MySQL自增加ID的機制(auto_increment + replace into)

    •  

      優勢:
      • 充分藉助數據庫的自增ID機制,可靠性高,生成有序的ID。
      缺點:
      • ID生成性能依賴單臺數據庫讀寫性能。
      • 依賴數據庫,當數據庫異常時整個系統不可用。

     

  • 常見的數據庫優化方案,在你的項目中數據庫如何進行優化的(點擊打開連接)

2.二、Redis

  • Redis 有哪些數據類型,可參考《Redis常見的5種不一樣的數據類型詳解》String list set sortset hash(點擊打開連接)

  • Redis 內部結構(點擊打開連接

  • Redis 使用場景(點擊打開連接

  • Redis 持久化機制,可參考《使用快照和AOF將Redis數據持久化到硬盤中

  • Redis 集羣方案與實現

  • Redis 爲何是單線程的?(點擊打開連接

  • redis利用隊列技術將併發訪問變爲串行訪問,消除了傳統數據庫串行控制的開銷

  •  

    整體來講快速的緣由以下:

    1)絕大部分請求是純粹的內存操做(很是快速)

    2)採用單線程,避免了沒必要要的上下文切換和競爭條件

    3)非阻塞IO

  • 緩存雪崩、緩存穿透、緩存預熱、緩存更新、緩存降級(點擊打開連接

  • 使用緩存的合理性問題(點擊打開連接

  • Redis常見的回收策略

  •  

    redis 提供 6種數據淘汰策略:

    1. voltile-lru:從已設置過時時間的數據集(server.db[i].expires)中挑選最近最少使用的數據淘汰
    2. volatile-ttl:從已設置過時時間的數據集(server.db[i].expires)中挑選將要過時的數據淘汰
    3. volatile-random:從已設置過時時間的數據集(server.db[i].expires)中任意選擇數據淘汰
    4. allkeys-lru:從數據集(server.db[i].dict)中挑選最近最少使用的數據淘汰
    5. allkeys-random:從數據集(server.db[i].dict)中任意選擇數據淘汰
    6. no-enviction(驅逐):禁止驅逐數據

2.三、消息隊列

    • 消息隊列的使用場景(點擊打開連接)(點擊打開連接

    • 消息的重發補償解決思路

    • 1. 處理失敗 指的是MessageListener的onMessage方法裏拋出RuntimeException。

      2. Message頭裏有兩個相關字段:Redelivered默認爲false,redeliveryCounter默認爲0。

      3. 消息先由broker發送給consumer,consumer調用listener,若是處理失敗,本地redeliveryCounter++,給broker一個特定應答,broker端的message裏redeliveryCounter++,延遲一點時間繼續調用,默認1s。超過6次,則給broker另外一個特定應答,broker就直接發送消息到DLQ。

      4. 若是失敗2次,consumer重啓,則broker再推過來的消息裏,redeliveryCounter=2,本地只能再重試4次即會進入DLQ。

      5. 重試的特定應答發送到broker,broker即會在內存將消息的redelivered設置爲true,redeliveryCounter++,可是這兩個字段都沒有持久化,即沒有修改存儲中的消息記錄。因此broker重啓時這兩個字段會被重置爲默認值

    • 消息的冪等性解決思路

    • 消息的堆積解決思路

    • 本身如何實現消息隊列

    • 如何保證消息的有序性(點擊打開連接

3、開源框架和容器

3.一、SSM/Servlet

  • Servlet的生命週期(連接

  • 加載—>實例化—>服務—>銷燬

  • 轉發與重定向的區別(連接

  •  

    一句話,轉發是服務器行爲,重定向是客戶端行爲。爲何這樣說呢,這就要看兩個動做的工做流程:

    轉發過程:客戶瀏覽器發送http請求----》web服務器接受此請求--》調用內部的一個方法在容器內部完成請求處理和轉發動做----》將目標資源發送給客戶;在這裏,轉發的路徑必須是同一個web容器下的url,其不能轉向到其餘的web路徑上去,中間傳遞的是本身的容器內的request。在客戶瀏覽器路徑欄顯示的仍然是其第一次訪問的路徑,也就是說客戶是感受不到服務器作了轉發的。轉發行爲是瀏覽器只作了一次訪問請求。

    重定向過程:客戶瀏覽器發送http請求----》web服務器接受後發送302狀態碼響應及對應新的location給客戶瀏覽器--》客戶瀏覽器發現是302響應,則自動再發送一個新的http請求,請求url是新的location地址----》服務器根據此請求尋找資源併發送給客戶。在這裏location能夠重定向到任意URL,既然是瀏覽器從新發出了請求,則就沒有什麼request傳遞的概念了。在客戶瀏覽器路徑欄顯示的是其重定向的路徑,客戶能夠觀察到地址的變化的。重定向行爲是瀏覽器作了至少兩次的訪問請求的。

  • BeanFactory 和 ApplicationContext 有什麼區別(連接

  • ,二者都是經過xml配置文件加載bean,ApplicationContext和BeanFacotry相比,提供了更多的擴展功能,但其主要區別在於後者是延遲加載,若是Bean的某一個屬性沒有注入,BeanFacotry加載後,直至第一次使用調用getBean方法纔會拋出異常;而ApplicationContext則在初始化自身是檢驗,這樣有利於檢查所依賴屬性是否注入;因此一般狀況下咱們選擇使用ApplicationContext.

  • Spring Bean 的生命週期(點擊打開連接

  • Spring IOC 如何實現(點擊打開連接

  • java程序中的每一個業務邏輯至少須要兩個或以上的對象來協做完成,一般,每一個對象在使用他的合做對象時,本身均要使用像new object() 這樣的語法來完成合做對象的申請工做。你會發現:對象間的耦合度高了。而IOC的思想是:Spring容器來實現這些相互依賴對象的建立、協調工做。對象只須要關係業務邏輯自己就能夠了。從這方面來講,對象如何獲得他的協做對象的責任被反轉了(IOC、DI)。
    這是我對Spring的IOC的體會。DI其實就是IOC的另一種說法。DI是由Martin Fowler 在2004年初的一篇論文中首次提出的。他總結:控制的什麼被反轉了?就是:得到依賴對象的方式反轉了。

  • Spring中Bean的做用域,默認的是哪個

  •  

    1.singleton

    singleton,也稱單例做用域。在每一個 Spring IoC 容器中有且只有一個實例,並且其完整生命週期徹底由 Spring 容器管理。對於全部獲取該 Bean 的操做 Spring 容器將只返回同一個 Bean。

    須要注意的是,若一個 Bean 未指定 scope 屬性,默認也爲 singleton 。

    2.prototype

    prototype,也稱原型做用域。每次向 Spring IoC 容器請求獲取 Bean 都返回一個全新的Bean。相對於 singleton 來講就是不緩存 Bean,每次都是一個根據 Bean 定義建立的全新 Bean。

    Web 做用域

    1.reqeust

    request,表示每一個請求須要容器建立一個全新Bean。

    在 Spring IoC 容器,即XmlWebApplicationContext 會爲每一個 HTTP 請求建立一個全新的 RequestPrecessor 對象。當請求結束後,該對象的生命週期即告結束。當同時有 10 個 HTTP 請求進來的時候,容器會分別針對這 10 個請求建立 10 個全新的 RequestPrecessor 實例,且他們相互之間互不干擾,從不是很嚴格的意義上說,request 能夠看作 prototype 的一種特例,除了場景更加具體以外,語意上差很少。

    2.session

    session,表示每一個會話須要容器建立一個全新 Bean。好比對於每一個用戶通常會有一個會話,該用戶的用戶信息須要存儲到會話中,此時能夠將該 Bean 配置爲 web 做用域。

    3.globalSession

    globalSession,相似於session 做用域,只是其用於 portlet 環境的 web 應用。若是在非portlet 環境將視爲 session 做用域。

  • 說說 Spring AOP、Spring AOP 實現原理(點擊打開連接

  •  

    AOP技術則偏偏相反,它利用一種稱爲「橫切」的技術,剖解開封裝的對象內部,並將那些影響了多個類的公共行爲封裝到一個可重用模塊,並將其名爲「Aspect」,即方面。所謂「方面」,簡單地說,就是將那些與業務無關,卻爲業務模塊所共同調用的邏輯或責任封裝起來,便於減小系統的重複代碼,下降模塊間的耦合度,並有利於將來的可操做性和可維護性。AOP表明的是一個橫向的關係,若是說「對象」是一個空心的圓柱體,其中封裝的是對象的屬性和行爲;那麼面向方面編程的方法,就彷彿一把利刃,將這些空心圓柱體剖開,以得到其內部的消息。而剖開的切面,也就是所謂的「方面」了。而後它又以巧奪天功的妙手將這些剖開的切面復原,不留痕跡。

    使用「橫切」技術,AOP把軟件系統分爲兩個部分:核心關注點和橫切關注點。業務處理的主要流程是核心關注點,與之關係不大的部分是橫切關注點。橫切關注點的一個特色是,他們常常發生在覈心關注點的多處,而各處都基本類似。好比權限認證、日誌、事務處理。Aop 的做用在於分離系統中的各類關注點,將核心關注點和橫切關注點分離開來。正如Avanade公司的高級方案構架師Adam Magee所說,AOP的核心思想就是「將應用程序中的商業邏輯同對其提供支持的通用服務進行分離。」

    實現AOP的技術,主要分爲兩大類:一是採用動態代理技術,利用截取消息的方式,對該消息進行裝飾,以取代原有對象行爲的執行;二是採用靜態織入的方式,引入特定的語法建立「方面」,從而使得編譯器能夠在編譯期間織入有關「方面」的代碼

  • 動態代理(CGLib 與 JDK)、優缺點、性能對比、如何選擇(點擊打開連接

  •  

    JDK動態代理是面向接口,在建立代理實現類時比CGLib要快,建立代理速度快。

    CGLib動態代理是經過字節碼底層繼承要代理類來實現(若是被代理類被final關鍵字所修飾,那麼抱歉會失敗),在建立代理這一塊沒有JDK動態代理快,可是運行速度比JDK動態代理要快。

    使用注意:

    若是要被代理的對象是個實現類,那麼Spring會使用JDK動態代理來完成操做(Spirng默認採用JDK動態代理實現機制)

    若是要被代理的對象不是個實現類那麼,Spring會強制使用CGLib來實現動態代理。

  • Spring 事務實現方式、事務的傳播機制、默認的事務類別(點擊打開連接)(點擊打開連接)(點擊打開連接

  • Spring事務機制是一種典型的策略模式,PlatformTransactionManager表明事務管理接口,但它並不知道到底如何管理事務,它只要求事務管理提供開始事務getTransaction(),提交事務commit()和回滾事務rollback()這三個方法,但具體如何實現則交給其實現類完成。編程人員只須要在配置文件中根據具體須要使用的事務類型作配置,Spring底層就自動會使用具體的事務實現類進行事務操做,而對於程序員來講,徹底不須要關心底層過程,只須要面向PlatformTransactionManager接口進行編程便可。PlatformTransactionManager接口中提供了以下方法:getTransaction(..), commit(); rollback(); 這些都是與平臺無關的事務操做。

  •  

    一、TransactionDefinition接口中定義五個隔離級別(isolation):

    說明:
     髒讀:一個事務讀取了另外一個事務改寫但還未提交的數據,若是這些數據被回滾,則讀到的數據是無效的。
     不可重複讀:在同一事務中,屢次讀取到同一數據的結果有所不一樣。也就是說,後續讀取能夠讀到另外一個事務已經提交的更新數據。
     幻讀:一個事務讀取了幾行記錄後,另外一個事務插入一些記錄,幻讀就發生了,再查詢的時候,第一個事務就會發現有些原來沒有的記錄。

    2. 在TransactionDefinition接口中定義了七個事務傳播行爲(propagationBehavior):

    三、TransactionDefinition接口中定義了事務超時
     所謂事務超時,就是指一個事務所容許執行的最長時間,若是超過該時間限制但事務尚未完成,則自動回滾事務。在 TransactionDefinition 中以 int 的值來表示超時時間,其單位是秒。
     默認設置爲底層事務系統的超時值,若是底層數據庫事務系統沒有設置超時值,那麼就是none,沒有超時限制。
    四、事務只讀屬性
     只讀事務用於客戶代碼只讀但不修改數據的情形,只讀事務用於特定情景下的優化,好比使用Hibernate的時候,默認爲讀寫事務。

  •  

    隔離級別越高,越能保證數據的完整性和一致性,可是對併發性能的影響也越大。

    大多數的數據庫默認隔離級別爲 Read Commited,好比 SqlServer、Oracle

    少數數據庫默認隔離級別爲:Repeatable Read 好比: MySQL InnoDB

  • Spring 事務底層原理(點擊打開連接

  • Spring事務失效(事務嵌套),JDK動態代理給Spring事務埋下的坑,可參考《JDK動態代理給Spring事務埋下的坑!

  • 如何自定義註解實現功能

  • Spring MVC 運行流程(點擊打開連接

  • 在整個Spring MVC框架中,DispatcherServlet處於核心位置,它負責協調和組織不一樣組件完成請求處理並返回響應的工做。具體流程爲:
    1)客戶端發送http請求,web應用服務器接收到這個請求,若是匹配DispatcherServlet的映射路徑(在web.xml中配置),web容器將請求轉交給DispatcherServlet處理;
    2)DispatcherServlet根據請求的信息及HandlerMapping的配置找處處理該請求的Controller;
    3)Controller完成業務邏輯處理後,返回一個ModelAndView給DispatcherServlet;
    4)DispatcherServlet藉由ViewResolver完成ModelAndView中邏輯視圖名到真實視圖對象View的解析工做;
    5)DispatcherServlet根據ModelAndView中的數據模型對View對象進行視圖渲染,最終客戶端獲得的響應消息多是一個普通的html頁面,也多是一個xml或json串,甚至是一張圖片或一個PDF文檔等不一樣的媒體形式。

  •  

    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    文字敘述

    1 用戶瀏覽器發起請求

    2 前端控制器DispatcherServlet首先會去請求Handler(也就是Controller),

    怎麼請求Handler----經過查找HandlerMapping(裏面有xml或者註解方式配置的Handler映射信息信息)來匹配用戶請求url對應的Handler,

    將查找到的請求信息,放入到執行鏈HandlerExecutionChain中,而後在放入該url對應的攔截器信息。

    而後將執行鏈HandlerExecutionChain返回給前端控制器DispatcherServlet

    3 前端控制器DispatcherServlet經過請求到的handler,再請求處理器適配器HandlerAdapter去執行handler,

               ::: 執行以前須要先請求執行鏈中的攔截器的preHandle方法進行某些請求校驗等。

    4 處理器適配器執行handler後返回給前端控制器DispatcherServlet一個ModelAndView(裏面放有視圖信息,模型數據信息)

              ::: 執行攔截器的postHandle方法

    5 前端控制器DispatcherServlet請求視圖解析器解析視圖,根據邏輯名(xxxx/xxxx/xxxx.jsp)解析成真正的視圖view(jsp,ftl等)

    6 視圖解析器解析完成後,返回給前端控制器DispatcherServlet一個View

    7 前端控制器DispatcherServlet進行視圖渲染,將模型數據填充到request中

    8 響應用戶請求,展現jsp等視圖信息。

  • Spring MVC 啓動流程

  • Spring 的單例實現原理(點擊打開連接

  •  

    咱們來看看Spring中的單例實現,當咱們試圖從Spring容器中取得某個類的實例時,默認狀況下,Spring會才用單例模式進行建立。
    <bean id="date" class="java.util.Date"/>
    <bean id="date" class="java.util.Date" scope="singleton"/> (僅爲Spring2.0支持)
    <bean id="date" class="java.util.Date" singleton="true"/>
    以上三種建立對象的方式是徹底相同的,容器都會向客戶返回Date類的單例引用。那麼若是我不想使用默認的單例模式,每次請求我都但願得到一個新的對象怎麼辦呢?很簡單,將scope屬性值設置爲prototype(原型)就能夠了
    <bean id="date" class="java.util.Date" scope="prototype"/>
    經過以上配置信息,Spring就會每次給客戶端返回一個新的對象實例。
    那麼Spring對單例的底層實現,究竟是餓漢式單例仍是懶漢式單例呢?呵呵,都不是。Spring框架對單例的支持是採用單例註冊表的方式進行實現的,源碼以下:
  • 剛纔的源碼中,你們真正要記住的是Spring對bean實例的建立是採用單例註冊表的方式進行實現的,而這個註冊表的緩存是HashMap對象,若是配置文件中的配置信息不要求使用單例,Spring會採用新建實例的方式返回對象實例
  • Spring 框架中用到了哪些設計模式

  •  

    1.工廠模式,這個很明顯,在各類BeanFactory以及ApplicationContext建立中都用到了;

    2.模版模式,這個也很明顯,在各類BeanFactory以及ApplicationContext實現中也都用到了;

    3.代理模式,在Aop實現中用到了JDK的動態代理;

    4.策略模式,第一個地方,加載資源文件的方式,使用了不一樣的方法,好比:ClassPathResourece,FileSystemResource,ServletContextResource,UrlResource但他們都有共同的藉口Resource;第二個地方就是在Aop的實現中,採用了兩種不一樣的方式,JDK動態代理和CGLIB代理;

    5.單例模式,這個好比在建立bean的時候

  • Spring 其餘產品(Srping Boot、Spring Cloud、Spring Secuirity、Spring Data、Spring AMQP 等)

  • 有沒有用到Spring Boot,Spring Boot的認識、原理

  • 它的核心功能是由@EnableAutoConfiguration這個註解提供的/Spring boot出現以後,得益於「習慣優於配置」這個理念,再也沒有繁瑣的配置、難以集成的內容(大多數流行第三方技術都被集成在內)。

  • Hibernate的原理(點擊打開連接

  • 1.經過Configuration config = new Configuration().configure();//讀取並解析hibernate.cfg.xml配置文件
    2.由hibernate.cfg.xml中的<mapping resource="com/xx/User.hbm.xml"/>讀取並解析映射信息
    3.經過SessionFactory sf = config.buildSessionFactory();//建立SessionFactory
    4.Session session = sf.openSession();//打開Sesssion
    5.Transaction tx = session.beginTransaction();//建立並啓動事務Transation
    6.persistent operate操做數據,持久化操做
    7.tx.commit();//提交事務
    8.關閉Session
    9.關閉SesstionFactory

  •  

    1. 面向對象設計的軟件內部運行過程能夠理解成就是在不斷建立各類新對象、創建對象之間的關係,調用對象的方法來改變各個對象的狀態和對象消亡的過程,無論程序運行的過程和操做怎麼樣,本質上都是要獲得一個結果,程序上一個時刻和下一個時刻的運行結果的差別就表如今內存中的對象狀態發生了變化。

    2.爲了在關機和內存空間不夠的情況下,保持程序的運行狀態,須要將內存中的對象狀態保存到持久化設備和從持久化設備中恢復出對象的狀態,一般都是保存到關係數據庫來保存大量對象信息。從Java程序的運行功能上來說,保存對象狀態的功能相比系統運行的其餘功能來講,應該是一個很不起眼的附屬功能,java採用jdbc來實現這個功能,這個不起眼的功能卻要編寫大量的代碼,而作的事情僅僅是保存對象和恢復對象,而且那些大量的jdbc代碼並無什麼技術含量,基本上是採用一套例行公事的標準代碼模板來編寫,是一種苦活和重複性的工做。

    3.經過數據庫保存java程序運行時產生的對象和恢復對象,其實就是實現了java對象與關係數據庫記錄的映射關係,稱爲ORM(即Object Relation Mapping),人們能夠經過封裝JDBC代碼來實現了這種功能,封裝出來的產品稱之爲ORM框架,Hibernate就是其中的一種流行ORM框架。使用Hibernate框架,不用寫JDBC代碼,僅僅是調用一個save方法,就能夠將對象保存到關係數據庫中,僅僅是調用一個get方法,就能夠從數據庫中加載出一個對象。

    4.使用Hibernate的基本流程是:配置Configuration對象、產生SessionFactory、建立session對象,啓動事務,完成CRUD操做,提交事務,關閉session。

    5.使用Hibernate時,先要配置hibernate.cfg.xml文件,其中配置數據庫鏈接信息和方言等,還要爲每一個實體配置相應的hbm.xml文件,hibernate.cfg.xml文件中須要登記每一個hbm.xml文件。

    6.在應用Hibernate時,重點要了解Session的緩存原理,級聯,延遲加載和hql查詢。

  • Hibernate與 MyBatis的比較(點擊打開連接)、

  • springmvc與struts2比較點擊打開連接

    struts2是類級別的攔截, 一個類對應一個request上下文, 
    springmvc是方法級別的攔截,一個方法對應一個request上下文,而方法同時又跟一個url對應
    因此說從架構自己上 spring3 mvc就容易實現restful url 
    而struts2的架構實現起來要費勁 
    由於struts2 action的一個方法能夠對應一個url 
    而其類屬性卻被全部方法共享,這也就沒法用註解或其餘方式標識其所屬方法了 

    =================================== 
    spring3mvc的方法之間基本上獨立的,獨享request response數據 
    請求數據經過參數獲取,處理結果經過ModelMap交回給框架 
    方法之間不共享變量 

    而struts2搞的就比較亂,雖然方法之間也是獨立的,但其全部Action變量是共享的 
    這不會影響程序運行,卻給咱們編碼 讀程序時帶來麻煩 

    ==================================== 
    spring3 mvc的驗證也是一個亮點,支持JSR303 
    處理ajax的請求更是方便 只需一個註解@ResponseBody ,而後直接返回響應文本便可 
  • 可參考《爲何會有Spring

  • 可參考《爲何會有Spring AOP

3.二、Netty

  • 爲何選擇 Netty

  • 說說業務中,Netty 的使用場景

  • 原生的 NIO 在 JDK 1.7 版本存在 epoll bug

  • 什麼是TCP 粘包/拆包

  • TCP粘包/拆包的解決辦法

  • Netty 線程模型

  • 說說 Netty 的零拷貝

  • Netty 內部執行流程

  • Netty 重連實現

3.三、Tomcat

4、分佈式

4.一、Nginx

  • 請解釋什麼是C10K問題或者知道什麼是C10K問題嗎?(點擊打開連接)

  • Nginx簡介,可參考《Nginx簡介》(點擊打開連接)(點擊打開連接)

  • 正向代理和反向代理.

  • Nginx幾種常見的負載均衡策略

  • Nginx服務器上的Master和Worker進程分別是什麼

  • 使用「反向代理服務器」的優勢是什麼?

4.二、分佈式其餘

  • 談談業務中使用分佈式的場景

  • Session 分佈式方案

  • Session 分佈式處理

  • 分佈式鎖的應用場景、分佈式鎖的產生緣由、基本概念

  • 分佈是鎖的常看法決方案

  • 分佈式事務的常看法決方案

  • 集羣與負載均衡的算法與實現

  • 說說分庫與分表設計,可參考《數據庫分庫分表策略的具體實現方案

  • 分庫與分錶帶來的分佈式困境與應對之策

4.三、Dubbo

  • 什麼是Dubbo,可參考《Dubbo入門

  • 什麼是RPC、如何實現RPC、RPC 的實現原理,可參考《基於HTTP的RPC實現

  • Dubbo中的SPI是什麼概念

  • Dubbo的基本原理、執行流程

5、微服務

5.一、安全問題

  • 如何防範常見的Web攻擊、如何方式SQL注入

  • 服務端通訊安全攻防

  • HTTPS原理剖析、降級攻擊、HTTP與HTTPS的對比

5.二、性能優化

  • 性能指標有哪些

  • 如何發現性能瓶頸

  • 性能調優的常見手段

  • 說說你在項目中如何進行性能調優

6、其餘

6.一、設計能力

6.二、業務工程

  • 說說你的開發流程、如何進行自動化部署的

  • 你和團隊是如何溝通的

  • 你如何進行代碼評審

  • 說說你對技術與業務的理解

  • 說說你在項目中遇到感受最難Bug,是如何解決的

  • 介紹一下工做中的一個你認爲最有價值的項目,以及在這個過程當中的角色、解決的問題、你以爲大家項目還有哪些不足的地方

6.三、軟實力

  • 說說你的優缺點、亮點

  • 說說你最近在看什麼書、什麼博客、在研究什麼新技術、再看那些開源項目的源代碼

  • 說說你以爲最有意義的技術書籍

  • 工做之餘作什麼事情、平時是如何學習的,怎樣提高本身的能力

  • 說說我的發展方向方面的思考

  • 說說你認爲的服務端開發工程師應該具有哪些能力

  • 說說你認爲的架構師是什麼樣的,架構師主要作什麼

  • 如何看待加班的問題

  •  

    市場經濟機遇與挑戰並存,企業每臨重要關頭,爲爭取主動搶佔先機而組織加班,做爲員工應該充分理解,主動請戰保質保量加入突擊。固然做爲企業應該努力避免此種情況發生,突擊必然緊張 緊張產生忙亂,接二連三地加班容易引發員工心理疲勞懈怠情緒,反而影響質量與效率。企業必須在管理上下功夫,努力作到高效八小時,達到緊湊有序 均衡生產的目的。
相關文章
相關標籤/搜索