最新Java面試題及答案整理

基礎篇

1、基本功

面向對象特徵

封裝,繼承,多態和抽象html

1. 封裝前端

封裝給對象提供了隱藏內部特性和行爲的能力。對象提供一些能被其餘對象訪問的方法來改
變它內部的數據。在 Java 當中,有 3 種修飾符: public, private 和 protected。每一種修飾符
給其餘的位於同一個包或者不一樣包下面對象賦予了不一樣的訪問權限。
下面列出了使用封裝的一些好處:java

    • 經過隱藏對象的屬性來保護對象內部的狀態。
    • 提升了代碼的可用性和可維護性,由於對象的行爲能夠被單獨的改變或者是擴展。
    • 禁止對象之間的不良交互提升模塊化

2. 繼承mysql

繼承給對象提供了從基類獲取字段和方法的能力。繼承提供了代碼的重用行,也能夠在不修改類的狀況下給現存的類添加新特性。git

3. 多態程序員

多態是編程語言給不一樣的底層數據類型作相同的接口展現的一種能力。一個多態類型上的操做能夠應用到其餘類型的值上面。github

4. 抽象redis

抽象是把想法從具體的實例中分離出來的步驟,所以,要根據他們的功能而不是實現細節來建立類。 Java 支持建立只暴漏接口而不包含方法實現的抽象的類。這種抽象技術的主要目的是把類的行爲和實現細節分離開。算法

final, finally, finalize 的區別

1. finalspring

修飾符(關鍵字)若是一個類被聲明爲final,意味着它不能再派生出新的子類,不能做爲父類被繼承。所以一個類不能既被聲明爲 abstract的,又被聲明爲final的。將變量或方法聲明爲final,能夠保證它們在使用中不被改變。被聲明爲final的變量必須在聲明時給定初值,而在之後的引用中只能讀取,不可修改。被聲明爲final的方法也一樣只能使用,不能重載。

2. finally

在異常處理時提供 finally 塊來執行任何清除操做。若是拋出一個異常,那麼相匹配的 catch 子句就會執行,而後控制就會進入 finally 塊(若是有的話)。

3. finalize

方法名。Java 技術容許使用 finalize() 方法在垃圾收集器將對象從內存中清除出去以前作必要的清理工做。這個方法是由垃圾收集器在肯定這個對象沒有被引用時對這個對象調用的。它是在 Object 類中定義的,所以全部的類都繼承了它。子類覆蓋 finalize() 方法以整理系統資源或者執行其餘清理工做。finalize() 方法是在垃圾收集器刪除對象以前對這個對象調用的。

int 和 Integer 有什麼區別

int 是基本數據類型
Integer是其包裝類,注意是一個類。
爲何要提供包裝類呢???
一是爲了在各類類型間轉化,經過各類方法的調用。不然 你沒法直接經過變量轉化。
好比,如今int要轉爲String

int a=0;
String result=Integer.toString(a);

在java中包裝類,比較多的用途是用在於各類數據類型的轉化中。
我寫幾個demo
//經過包裝類來實現轉化的

int num=Integer.valueOf("12");
int num2=Integer.parseInt("12");
double num3=Double.valueOf("12.2");
double num4=Double.parseDouble("12.2");
//其餘的相似。經過基本數據類型的包裝來的valueOf和parseXX來實現String轉爲XX
String a=String.valueOf("1234");//這裏括號中幾乎能夠是任何類型
String b=String.valueOf(true);
String c=new Integer(12).toString();//經過包裝類的toString()也能夠
String d=new Double(2.3).toString();

再舉例下。好比我如今要用泛型

List<Integer> nums;

這裏<>須要類。若是你用int。它會報錯的。

重載和重寫的區別

override(重寫)

1. 方法名、參數、返回值相同。

2. 子類方法不能縮小父類方法的訪問權限。

3. 子類方法不能拋出比父類方法更多的異常(但子類方法能夠不拋出異常)。

4. 存在於父類和子類之間。

5. 方法被定義爲final不能被重寫。

overload(重載)

1. 參數類型、個數、順序至少有一個不相同。

2. 不能重載只有返回值不一樣的方法名。

3. 存在於父類和子類、同類中。

抽象類和接口有什麼區別

接口是公開的,裏面不能有私有的方法或變量,是用於讓別人使用的,而抽象類是能夠有私有方法或私有變量的,
另外,實現接口的必定要實現接口裏定義的全部方法,而實現抽象類能夠有選擇地重寫須要用到的方法,通常的應用裏,最頂級的是接口,而後是抽象類實現接口,最後纔到具體類實現。
還有,接口能夠實現多重繼承,而一個類只能繼承一個超類,但能夠經過繼承多個接口實現多重繼承,接口還有標識(裏面沒有任何方法,如Remote接口)和數據共享(裏面的變量全是常量)的做用。

說說反射的用途及實現

Java反射機制主要提供瞭如下功能:在運行時構造一個類的對象;判斷一個類所具備的成員變量和方法;調用一個對象的方法;生成動態代理。反射最大的應用就是框架

Java反射的主要功能:

  • 肯定一個對象的類
  • 取出類的modifiers,數據成員,方法,構造器,和超類.
  • 找出某個接口裏定義的常量和方法說明.
  • 建立一個類實例,這個實例在運行時刻纔有名字(運行時間才生成的對象).
  • 取得和設定對象數據成員的值,若是數據成員名是運行時刻肯定的也能作到.
  • 在運行時刻調用動態對象的方法.
  • 建立數組,數組大小和類型在運行時刻才肯定,也能更改數組成員的值.

反射的應用不少,不少框架都有用到

spring 的 ioc/di 也是反射….
javaBean和jsp之間調用也是反射….
struts的 FormBean 和頁面之間…也是經過反射調用….
JDBC 的 classForName()也是反射…..
hibernate的 find(Class clazz) 也是反射….

反射還有一個不得不說的問題,就是性能問題,大量使用反射系統性能大打折扣。怎麼使用使你的系統達到最優就看你係統架構和綜合使用問題啦,這裏就很少說了。

來源:http://uule.iteye.com/blog/1423512

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

(此題自由發揮,就看你對註解的理解了!==)登錄、權限攔截、日誌處理,以及各類Java框架,如Spring,Hibernate,JUnit 提到註解就不能不說反射,Java自定義註解是經過運行時靠反射獲取註解。實際開發中,例如咱們要獲取某個方法的調用日誌,能夠經過AOP(動態代理機制)給方法添加切面,經過反射來獲取方法包含的註解,若是包含日誌註解,就進行日誌記錄。

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

GET方法會把名值對追加在請求的URL後面。由於URL對字符數目有限制,進而限制了用在客戶端請求的參數值的數目。而且請求中的參數值是可見的,所以,敏感信息不能用這種方式傳遞。

POST方法經過把請求參數值放在請求體中來克服GET方法的限制,所以,能夠發送的參數的數目是沒有限制的。最後,經過POST請求傳遞的敏感信息對外部客戶端是不可見的。

參考:https://www.cnblogs.com/wangli-66/p/5453507.html

session 與 cookie 區別

cookie 是 Web 服務器發送給瀏覽器的一塊信息。瀏覽器會在本地文件中給每個 Web 服務
器存儲 cookie。之後瀏覽器在給特定的 Web 服務器發請求的時候,同時會發送全部爲該服
務器存儲的 cookie。下面列出了 session 和 cookie 的區別:
不管客戶端瀏覽器作怎麼樣的設置,session都應該能正常工做。客戶端能夠選擇禁用 cookie,
可是, session 仍然是可以工做的,由於客戶端沒法禁用服務端的 session。

JDBC 流程

一、 加載JDBC驅動程序:
在鏈接數據庫以前,首先要加載想要鏈接的數據庫的驅動到JVM(Java虛擬機),
這經過java.lang.Class類的靜態方法forName(String className)實現。
例如:

try{
//加載MySql的驅動類
Class.forName("com.mysql.jdbc.Driver") ;
}catch(ClassNotFoundException e){
System.out.println("找不到驅動程序類 ,加載驅動失敗!");
e.printStackTrace() ;
}

成功加載後,會將Driver類的實例註冊到DriverManager類中。

二、 提供JDBC鏈接的URL

  • 鏈接URL定義了鏈接數據庫時的協議、子協議、數據源標識。
  • 書寫形式:協議:子協議:數據源標識

協議:在JDBC中老是以jdbc開始 子協議:是橋鏈接的驅動程序或是數據庫管理系統名稱。
數據源標識:標記找到數據庫來源的地址與鏈接端口。
例如:
jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=gbk;useUnicode=true;(MySql的鏈接URL)
表示使用Unicode字符集。若是characterEncoding設置爲 gb2312或GBK,本參數必須設置爲true 。characterEncoding=gbk:字符編碼方式。

三、建立數據庫的鏈接

  • 要鏈接數據庫,須要向java.sql.DriverManager請求並得到Connection對象, 該對象就表明一個數據庫的鏈接。
  • 使用DriverManager的getConnectin(String url , String username , String password )方法傳入指定的欲鏈接的數據庫的路徑、數據庫的用戶名和 密碼來得到。

例如: //鏈接MySql數據庫,用戶名和密碼都是root

String url = "jdbc:mysql://localhost:3306/test" ;
String username = "root" ;
String password = "root" ;
try{
Connection con = DriverManager.getConnection(url , username , password ) ;
}catch(SQLException se){
System.out.println("數據庫鏈接失敗!");
se.printStackTrace() ;
}

四、 建立一個Statement
•要執行SQL語句,必須得到java.sql.Statement實例,Statement實例分爲如下3 種類型:
一、執行靜態SQL語句。一般經過Statement實例實現。
二、執行動態SQL語句。一般經過PreparedStatement實例實現。
三、執行數據庫存儲過程。一般經過CallableStatement實例實現。
具體的實現方式:
Statement stmt = con.createStatement() ; PreparedStatement pstmt = con.prepareStatement(sql) ; CallableStatement cstmt = con.prepareCall(「{CALL demoSp(? , ?)}」) ;

五、執行SQL語句

Statement接口提供了三種執行SQL語句的方法:executeQuery 、executeUpdate 和execute
一、ResultSet executeQuery(String sqlString):執行查詢數據庫的SQL語句 ,返回一個結果集(ResultSet)對象。
二、int executeUpdate(String sqlString):用於執行INSERT、UPDATE或 DELETE語句以及SQL DDL語句,如:CREATE TABLE和DROP TABLE等
三、execute(sqlString):用於執行返回多個結果集、多個更新計數或兩者組合的 語句。 具體實現的代碼:
ResultSet rs = stmt.executeQuery(「SELECT * FROM …」) ; int rows = stmt.executeUpdate(「INSERT INTO …」) ; boolean flag = stmt.execute(String sql) ;

六、處理結果

兩種狀況:
一、執行更新返回的是本次操做影響到的記錄數。
二、執行查詢返回的結果是一個ResultSet對象。
• ResultSet包含符合SQL語句中條件的全部行,而且它經過一套get方法提供了對這些 行中數據的訪問。
• 使用結果集(ResultSet)對象的訪問方法獲取數據:
while(rs.next()){
String name = rs.getString(「name」) ;
String pass = rs.getString(1) ; // 此方法比較高效
}
(列是從左到右編號的,而且從列1開始)

七、關閉JDBC對象

操做完成之後要把全部使用的JDBC對象全都關閉,以釋放JDBC資源,關閉順序和聲 明順序相反:

一、關閉記錄集
二、關閉聲明
三、關閉鏈接對象

if(rs != null){ // 關閉記錄集
    try{
      rs.close() ;
    }catch(SQLException e){
      e.printStackTrace() ;
    }
}
if(stmt != null){ // 關閉聲明
    try{
      stmt.close() ;
    }catch(SQLException e){
      e.printStackTrace() ;
    }
}
if(conn != null){ // 關閉鏈接對象
    try{
      conn.close() ;
    }catch(SQLException e){
      e.printStackTrace() ;
    }
}

MVC 設計思想

MVC就是
M:Model 模型
V:View 視圖
C:Controller 控制器
模型就是封裝業務邏輯和數據的一個一個的模塊,控制器就是調用這些模塊的(java中一般是用Servlet來實現,框架的話不少是用Struts2來實現這一層),視圖就主要是你看到的,好比JSP等.
當用戶發出請求的時候,控制器根據請求來選擇要處理的業務邏輯和要選擇的數據,再返回去把結果輸出到視圖層,這裏多是進行重定向或轉發等.

equals 與 == 的區別

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

2、集合

List 和 Set 區別

List,Set都是繼承自Collection接口

List特色:元素有放入順序,元素可重複

Set特色:元素無放入順序,元素不可重複,重複元素會覆蓋掉

(注意:元素雖然無放入順序,可是元素在set中的位置是有該元素的HashCode決定的,其位置實際上是固定的,加入Set 的Object必須定義equals()方法 ,另外list支持for循環,也就是經過下標來遍歷,也能夠用迭代器,可是set只能用迭代,由於他無序,沒法用下標來取得想要的值。)

Set和List對比:

Set:檢索元素效率低下,刪除和插入效率高,插入和刪除不會引發元素位置改變。

List:和數組相似,List能夠動態增加,查找元素效率高,插入刪除元素效率低,由於會引發其餘元素位置改變。

List 和 Map 區別

List是對象集合,容許對象重複。

Map是鍵值對的集合,不容許key重複。

Arraylist 與 LinkedList 區別

Arraylist:

優勢:ArrayList是實現了基於動態數組的數據結構,由於地址連續,一旦數據存儲好了,查詢操做效率會比較高(在內存裏是連着放的)。

缺點:由於地址連續, ArrayList要移動數據,因此插入和刪除操做效率比較低。

LinkedList:

優勢:LinkedList基於鏈表的數據結構,地址是任意的,因此在開闢內存空間的時候不須要等一個連續的地址,對於新增和刪除操做add和remove,LinedList比較佔優點。LinkedList 適用於要頭尾操做或插入指定位置的場景

缺點:由於LinkedList要移動指針,因此查詢操做性能比較低。

適用場景分析:

當須要對數據進行對此訪問的狀況下選用ArrayList,當須要對數據進行屢次增長刪除修改時採用LinkedList。

ArrayList 與 Vector 區別

public ArrayList(int initialCapacity)//構造一個具備指定初始容量的空列表。
public ArrayList()//構造一個初始容量爲10的空列表。
public ArrayList(Collection<?  extends E> c)//構造一個包含指定 collection 的元素的列表

Vector有四個構造方法:

public Vector()//使用指定的初始容量和等於零的容量增量構造一個空向量。
public Vector(int initialCapacity)//構造一個空向量,使其內部數據數組的大小,其標準容量增量爲零。
public Vector(Collection<? extends E> c)//構造一個包含指定 collection 中的元素的向量
public Vector(int initialCapacity,int capacityIncrement)//使用指定的初始容量和容量增量構造一個空的向量

ArrayList和Vector都是用數組實現的,主要有這麼三個區別:

  1. Vector是多線程安全的,線程安全就是說多線程訪問同一代碼,不會產生不肯定的結果。而ArrayList不是,這個能夠從源碼中看出,Vector類中的方法不少有synchronized進行修飾,這樣就致使了Vector在效率上沒法與ArrayList相比;

  2. 兩個都是採用的線性連續空間存儲元素,可是當空間不足的時候,兩個類的增長方式是不一樣。

  3. Vector能夠設置增加因子,而ArrayList不能夠。

  4. Vector是一種老的動態數組,是線程同步的,效率很低,通常不同意使用。

適用場景分析:

  1. Vector是線程同步的,因此它也是線程安全的,而ArrayList是線程異步的,是不安全的。若是不考慮到線程的安全因素,通常用ArrayList效率比較高。

  2. 若是集合中的元素的數目大於目前集合數組的長度時,在集合中使用數據量比較大的數據,用Vector有必定的優點。

HashMap 和 Hashtable 的區別

1.hashMap去掉了HashTable 的contains方法,可是加上了containsValue()和containsKey()方法。

2.hashTable同步的,而HashMap是非同步的,效率上逼hashTable要高。

3.hashMap容許空鍵值,而hashTable不容許。

注意:
TreeMap:非線程安全基於紅黑樹實現。TreeMap沒有調優選項,由於該樹總處於平衡狀態。

Treemap:適用於按天然順序或自定義順序遍歷鍵(key)。

參考:http://blog.csdn.net/qq_22118507/article/details/51576319

HashSet 和 HashMap 區別

set是線性結構,set中的值不能重複,hashset是set的hash實現,hashset中值不能重複是用hashmap的key來實現的。

map是鍵值對映射,能夠空鍵空值。HashMap是Map接口的hash實現,key的惟一性是經過key值hash值的惟一來肯定,value值是則是鏈表結構。

他們的共同點都是hash算法實現的惟一性,他們都不能持有基本類型,只能持有對象

HashMap 和 ConcurrentHashMap 的區別

ConcurrentHashMap是線程安全的HashMap的實現。

(1)ConcurrentHashMap對整個桶數組進行了分割分段(Segment),而後在每個分段上都用lock鎖進行保護,相對於HashTable的syn關鍵字鎖的粒度更精細了一些,併發性能更好,而HashMap沒有鎖機制,不是線程安全的。

(2)HashMap的鍵值對容許有null,可是ConCurrentHashMap都不容許。

HashMap 的工做原理及代碼實現

參考:https://tracylihui.github.io/2015/07/01/Java集合學習1:HashMap的實現原理/

ConcurrentHashMap 的工做原理及代碼實現

HashTable裏使用的是synchronized關鍵字,這實際上是對對象加鎖,鎖住的都是對象總體,當Hashtable的大小增長到必定的時候,性能會急劇降低,由於迭代時須要被鎖定很長的時間。

ConcurrentHashMap算是對上述問題的優化,其構造函數以下,默認傳入的是16,0.75,16。

public ConcurrentHashMap(int paramInt1, float paramFloat, int paramInt2)  {
//…
int i = 0;
int j = 1;
while (j < paramInt2) {
  ++i;
  j <<= 1;
}
this.segmentShift = (32 - i);
this.segmentMask = (j - 1);
this.segments = Segment.newArray(j);
//…
int k = paramInt1 / j;
if (k * j < paramInt1)
  ++k;
int l = 1;
while (l < k)
  l <<= 1;
 
for (int i1 = 0; i1 < this.segments.length; ++i1)
  this.segments[i1] = new Segment(l, paramFloat);
 }
public V put(K paramK, V paramV)  {
if (paramV == null)
  throw new NullPointerException();
int i = hash(paramK.hashCode()); //這裏的hash函數和HashMap中的不同  
return this.segments[(i >>> this.segmentShift & this.segmentMask)].put(paramK, i, paramV, false);
}

ConcurrentHashMap引入了分割(Segment),上面代碼中的最後一行其實就能夠理解爲把一個大的Map拆分紅N個小的HashTable,在put方法中,會根據hash(paramK.hashCode())來決定具體存放進哪一個Segment,若是查看Segment的put操做,咱們會發現內部使用的同步機制是基於lock操做的,這樣就能夠對Map的一部分(Segment)進行上鎖,這樣影響的只是將要放入同一個Segment的元素的put操做,保證同步的時候,鎖住的不是整個Map(HashTable就是這麼作的),相對於HashTable提升了多線程環境下的性能,所以HashTable已經被淘汰了。

3、線程

建立線程的方式及實現

Java中建立線程主要有三種方式:

1、繼承Thread類建立線程類

(1)定義Thread類的子類,並重寫該類的run方法,該run方法的方法體就表明了線程要完成的任務。所以把run()方法稱爲執行體。

(2)建立Thread子類的實例,即建立了線程對象。

(3)調用線程對象的start()方法來啓動該線程。

package com.thread;
 
public class FirstThreadTest extends Thread{
    int i = 0;
    //重寫run方法,run方法的方法體就是現場執行體
    public void run()
    {
        for(;i<100;i++){
          System.out.println(getName()+"  "+i);
        }
    }
    public static void main(String[] args)
    {
        for(int i = 0;i< 100;i++)
        {
            System.out.println(Thread.currentThread().getName()+"  : "+i);
            if(i==20)
            {
                new FirstThreadTest().start();
                new FirstThreadTest().start();
            }
        }
    }
}

上述代碼中Thread.currentThread()方法返回當前正在執行的線程對象。getName()方法返回調用該方法的線程的名字。

2、經過Runnable接口建立線程類

(1)定義runnable接口的實現類,並重寫該接口的run()方法,該run()方法的方法體一樣是該線程的線程執行體。

(2)建立 Runnable實現類的實例,並依此實例做爲Thread的target來建立Thread對象,該Thread對象纔是真正的線程對象。

(3)調用線程對象的start()方法來啓動該線程。

package com.thread;
 
public class RunnableThreadTest implements Runnable
{
 
    private int i;
    public void run()
    {
        for(i = 0;i <100;i++)
        {
            System.out.println(Thread.currentThread().getName()+" "+i);
        }
    }
    public static void main(String[] args)
    {
        for(int i = 0;i < 100;i++)
        {
            System.out.println(Thread.currentThread().getName()+" "+i);
            if(i==20)
            {
                RunnableThreadTest rtt = new RunnableThreadTest();
                new Thread(rtt,"新線程1").start();
                new Thread(rtt,"新線程2").start();
            }
        }
    }
}

3、經過Callable和Future建立線程

(1)建立Callable接口的實現類,並實現call()方法,該call()方法將做爲線程執行體,而且有返回值。

(2)建立Callable實現類的實例,使用FutureTask類來包裝Callable對象,該FutureTask對象封裝了該Callable對象的call()方法的返回值。

(3)使用FutureTask對象做爲Thread對象的target建立並啓動新線程。

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

package com.thread;
 
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
 
public class CallableThreadTest implements Callable<Integer>
{
    public static void main(String[] args)
    {
        CallableThreadTest ctt = new CallableThreadTest();
        FutureTask<Integer> ft = new FutureTask<>(ctt);
        for(int i = 0;i < 100;i++)
        {
            System.out.println(Thread.currentThread().getName()+" 的循環變量i的值"+i);
            if(i==20)
            {
                new Thread(ft,"有返回值的線程").start();
            }
        }
        try
        {
            System.out.println("子線程的返回值:"+ft.get());
        } catch (InterruptedException e)
        {
            e.printStackTrace();
        } catch (ExecutionException e)
        {
            e.printStackTrace();
        }
    }
    @Override
    public Integer call() throws Exception
    {
        int i = 0;
        for(;i<100;i++)
        {
            System.out.println(Thread.currentThread().getName()+" "+i);
        }
        return i;
    }
}

建立線程的三種方式的對比

採用實現Runnable、Callable接口的方式創見多線程時,優點是:

線程類只是實現了Runnable接口或Callable接口,還能夠繼承其餘類。

在這種方式下,多個線程能夠共享同一個target對象,因此很是適合多個相同線程來處理同一份資源的狀況,從而能夠將CPU、代碼和數據分開,造成清晰的模型,較好地體現了面向對象的思想。

劣勢是:

編程稍微複雜,若是要訪問當前線程,則必須使用Thread.currentThread()方法。

使用繼承Thread類的方式建立多線程時優點是:

編寫簡單,若是須要訪問當前線程,則無需使用Thread.currentThread()方法,直接使用this便可得到當前線程。

劣勢是:

線程類已經繼承了Thread類,因此不能再繼承其餘父類。

sleep() 、join()、yield()有什麼區別

一、sleep()方法

在指定的毫秒數內讓當前正在執行的線程休眠(暫停執行),此操做受到系統計時器和調度程序精度和準確性的影響。 讓其餘線程有機會繼續執行,但它並不釋放對象鎖。也就是若是有Synchronized同步塊,其餘線程仍然不能訪問共享數據。注意該方法要捕獲異常

好比有兩個線程同時執行(沒有Synchronized),一個線程優先級爲MAX_PRIORITY,另外一個爲MIN_PRIORITY,若是沒有Sleep()方法,只有高優先級的線程執行完成後,低優先級的線程才能執行;但當高優先級的線程sleep(5000)後,低優先級就有機會執行了。
總之,sleep()能夠使低優先級的線程獲得執行的機會,固然也可讓同優先級、高優先級的線程有執行的機會。

二、yield()方法

yield()方法和sleep()方法相似,也不會釋放「鎖標誌」,區別在於,它沒有參數,即yield()方法只是使當前線程從新回到可執行狀態,因此執行yield()的線程有可能在進入到可執行狀態後立刻又被執行,另外yield()方法只能使同優先級或者高優先級的線程獲得執行機會,這也和sleep()方法不一樣。

三、join()方法

Thread的非靜態方法join()讓一個線程B「加入」到另一個線程A的尾部。在A執行完畢以前,B不能工做。

Thread t = new MyThread(); t.start(); t.join();

保證當前線程中止執行,直到該線程所加入的線程完成爲止。然而,若是它加入的線程沒有存活,則當前線程不須要中止。

說說 CountDownLatch 原理

參考:

分析CountDownLatch的實現原理

何時使用CountDownLatch

Java併發編程:CountDownLatch、CyclicBarrier和Semaphore

說說 CyclicBarrier 原理

參考:

JUC回顧之-CyclicBarrier底層實現和原理

說說 Semaphore 原理

JAVA多線程–信號量(Semaphore)

JUC回顧之-Semaphore底層實現和原理

說說 Exchanger 原理

java.util.concurrent.Exchanger應用範例與原理淺析

說說 CountDownLatch 與 CyclicBarrier 區別

儘可能把CyclicBarrier和CountDownLatch的區別說通俗點

ThreadLocal 原理分析

Java併發編程:深刻剖析ThreadLocal

講講線程池的實現原理

主要是ThreadPoolExecutor的實現原理

Java併發編程:線程池的使用

線程池的幾種方式

newFixedThreadPool(int nThreads)
建立一個固定長度的線程池,每當提交一個任務就建立一個線程,直到達到線程池的最大數量,這時線程規模將再也不變化,當線程發生未預期的錯誤而結束時,線程池會補充一個新的線程

newCachedThreadPool()
建立一個可緩存的線程池,若是線程池的規模超過了處理需求,將自動回收空閒線程,而當需求增長時,則能夠自動添加新線程,線程池的規模不存在任何限制

newSingleThreadExecutor()
這是一個單線程的Executor,它建立單個工做線程來執行任務,若是這個線程異常結束,會建立一個新的來替代它;它的特色是能確保依照任務在隊列中的順序來串行執行

newScheduledThreadPool(int corePoolSize)
建立了一個固定長度的線程池,並且以延遲或定時的方式來執行任務,相似於Timer。

舉個栗子

private static final Executor exec=Executors.newFixedThreadPool(50);
 
Runnable runnable=new Runnable(){
    public void run(){
        ...
    }
}
exec.execute(runnable);
 
Callable<Object> callable=new Callable<Object>() {
    public Object call() throws Exception {
        return null;
    }
};
 
Future future=executorService.submit(callable);
future.get(); // 等待計算完成後,獲取結果
future.isDone(); // 若是任務已完成,則返回 true
future.isCancelled(); // 若是在任務正常完成前將其取消,則返回 true
future.cancel(true); // 試圖取消對此任務的執行,true中斷運行的任務,false容許正在運行的任務運行完成

參考:

建立線程池的幾種方式

線程的生命週期

新建(New)、就緒(Runnable)、運行(Running)、阻塞(Blocked)和死亡(Dead)5種狀態

(1)生命週期的五種狀態

新建(new Thread)
當建立Thread類的一個實例(對象)時,此線程進入新建狀態(未被啓動)。
例如:Thread t1=new Thread();

就緒(runnable)
線程已經被啓動,正在等待被分配給CPU時間片,也就是說此時線程正在就緒隊列中排隊等候獲得CPU資源。例如:t1.start();

運行(running)
線程得到CPU資源正在執行任務(run()方法),此時除非此線程自動放棄CPU資源或者有優先級更高的線程進入,線程將一直運行到結束。

死亡(dead)
當線程執行完畢或被其它線程殺死,線程就進入死亡狀態,這時線程不可能再進入就緒狀態等待執行。

天然終止:正常運行run()方法後終止

異常終止:調用stop()方法讓一個線程終止運行

堵塞(blocked)
因爲某種緣由致使正在運行的線程讓出CPU並暫停本身的執行,即進入堵塞狀態。

正在睡眠:用sleep(long t) 方法可以使線程進入睡眠方式。一個睡眠着的線程在指定的時間過去可進入就緒狀態。

正在等待:調用wait()方法。(調用motify()方法回到就緒狀態)

被另外一個線程所阻塞:調用suspend()方法。(調用resume()方法恢復)

參考:

線程的生命週期

4、鎖機制

說說線程安全問題

線程安全是指要控制多個線程對某個資源的有序訪問或修改,而在這些線程之間沒有產生衝突。
在Java裏,線程安全通常體如今兩個方面:
一、多個thread對同一個java實例的訪問(read和modify)不會相互干擾,它主要體如今關鍵字synchronized。如ArrayList和Vector,HashMap和Hashtable(後者每一個方法前都有synchronized關鍵字)。若是你在interator一個List對象時,其它線程remove一個element,問題就出現了。
二、每一個線程都有本身的字段,而不會在多個線程之間共享。它主要體如今java.lang.ThreadLocal類,而沒有Java關鍵字支持,如像static、transient那樣。

volatile 實現原理

聊聊併發(一)——深刻分析Volatile的實現原理

悲觀鎖 樂觀鎖

樂觀鎖 悲觀鎖
是一種思想。能夠用在不少方面。

好比數據庫方面。
悲觀鎖就是for update(鎖定查詢的行)
樂觀鎖就是 version字段(比較跟上一次的版本號,若是同樣則更新,若是失敗則要重複讀-比較-寫的操做。)

JDK方面:
悲觀鎖就是sync
樂觀鎖就是原子類(內部使用CAS實現)

本質來講,就是悲觀鎖認爲總會有人搶個人。
樂觀鎖就認爲,基本沒人搶。

CAS 樂觀鎖

樂觀鎖是一種思想,即認爲讀多寫少,遇到併發寫的可能性比較低,因此採起在寫時先讀出當前版本號,而後加鎖操做(比較跟上一次的版本號,若是同樣則更新),若是失敗則要重複讀-比較-寫的操做。

CAS是一種更新的原子操做,比較當前值跟傳入值是否同樣,同樣則更新,不然失敗。
CAS頂多算是樂觀鎖寫那一步操做的一種實現方式罷了,不用CAS本身加鎖也是能夠的。

ABA 問題

ABA:若是另外一個線程修改V值假設原來是A,先修改爲B,再修改回成A,當前線程的CAS操做沒法分辨當前V值是否發生過變化。

參考:

Java CAS 和ABA問題

樂觀鎖的業務場景及實現方式

樂觀鎖(Optimistic Lock):
每次獲取數據的時候,都不會擔憂數據被修改,因此每次獲取數據的時候都不會進行加鎖,可是在更新數據的時候須要判斷該數據是否被別人修改過。若是數據被其餘線程修改,則不進行數據更新,若是數據沒有被其餘線程修改,則進行數據更新。因爲數據沒有進行加鎖,期間該數據能夠被其餘線程進行讀寫操做。

樂觀鎖:比較適合讀取操做比較頻繁的場景,若是出現大量的寫入操做,數據發生衝突的可能性就會增大,爲了保證數據的一致性,應用層須要不斷的從新獲取數據,這樣會增長大量的查詢操做,下降了系統的吞吐量。


 

核心篇

1、數據存儲

MySQL 索引使用的注意事項

參考:

mysql索引使用技巧及注意事項

說說反模式設計

參考:

每一個程序員要注意的 9 種反模式

說說分庫與分表設計

分表與分庫使用場景以及設計方式

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

服務端指南 數據存儲篇 | MySQL(09) 分庫與分錶帶來的分佈式困境與應對之策

說說 SQL 優化之道

sql優化的幾種方法

MySQL 遇到的死鎖問題

參考:

Mysql併發時經典常見的死鎖緣由及解決方法

存儲引擎的 InnoDB 與 MyISAM

1)InnoDB支持事務,MyISAM不支持,這一點是很是之重要。事務是一種高級的處理方式,如在一些列增刪改中只要哪一個出錯還能夠回滾還原,而MyISAM就不能夠了。

2)MyISAM適合查詢以及插入爲主的應用,InnoDB適合頻繁修改以及涉及到安全性較高的應用

3)InnoDB支持外鍵,MyISAM不支持

4)從MySQL5.5.5之後,InnoDB是默認引擎

5)InnoDB不支持FULLTEXT類型的索引

6)InnoDB中不保存表的行數,如select count() from table時,InnoDB須要掃描一遍整個表來計算有多少行,可是MyISAM只要簡單的讀出保存好的行數便可。注意的是,當count()語句包含where條件時MyISAM也須要掃描整個表

7)對於自增加的字段,InnoDB中必須包含只有該字段的索引,可是在MyISAM表中能夠和其餘字段一塊兒創建聯合索引

8)清空整個表時,InnoDB是一行一行的刪除,效率很是慢。MyISAM則會重建表

9)InnoDB支持行鎖(某些狀況下仍是鎖整表,如 update table set a=1 where user like ‘%lee%’

參考:

MySQL存儲引擎之MyIsam和Innodb總結性梳理

數據庫索引的原理

參考:

http://blog.csdn.net/suifeng3051/article/details/52669644

爲何要用 B-tree

鑑於B-tree具備良好的定位特性,其常被用於對檢索時間要求苛刻的場合,例如:
一、B-tree索引是數據庫中存取和查找文件(稱爲記錄或鍵值)的一種方法。
二、硬盤中的結點也是B-tree結構的。與內存相比,硬盤必須花成倍的時間來存取一個數據元素,這是由於硬盤的機械部件讀寫數據的速度遠遠趕不上純電子媒體的內存。與一個結點兩個分支的二元樹相比,B-tree利用多個分支(稱爲子樹)的結點,減小獲取記錄時所經歷的結點數,從而達到節省存取時間的目的。

彙集索引與非彙集索引的區別

參考:

快速理解彙集索引和非彙集索引

limit 20000 加載很慢怎麼解決

LIMIT n 等價於 LIMIT 0,n

此題總結一下就是讓limit走索引去查詢,例如:order by 索引字段,或者limit前面根where條件走索引字段等等。

參考:

MYSQL分頁limit速度太慢優化方法

選擇合適的分佈式主鍵方案

參考:

分佈式系統惟一ID生成方案彙總

選擇合適的數據存儲方案

  • 關係型數據庫 MySQL

MySQL 是一個最流行的關係型數據庫,在互聯網產品中應用比較普遍。通常狀況下,MySQL 數據庫是選擇的第一方案,基本上有 80% ~ 90% 的場景都是基於 MySQL 數據庫的。由於,須要關係型數據庫進行管理,此外,業務存在許多事務性的操做,須要保證事務的強一致性。同時,可能還存在一些複雜的 SQL 的查詢。值得注意的是,前期儘可能減小表的聯合查詢,便於後期數據量增大的狀況下,作數據庫的分庫分表。

  • 內存數據庫 Redis

隨着數據量的增加,MySQL 已經知足不了大型互聯網類應用的需求。所以,Redis 基於內存存儲數據,能夠極大的提升查詢性能,對產品在架構上很好的補充。例如,爲了提升服務端接口的訪問速度,儘量將讀頻率高的熱點數據存放在 Redis 中。這個是很是典型的以空間換時間的策略,使用更多的內存換取 CPU 資源,經過增長系統的內存消耗,來加快程序的運行速度。

在某些場景下,能夠充分的利用 Redis 的特性,大大提升效率。這些場景包括緩存,會話緩存,時效性,訪問頻率,計數器,社交列表,記錄用戶斷定信息,交集、並集和差集,熱門列表與排行榜,最新動態等。

使用 Redis 作緩存的時候,須要考慮數據不一致與髒讀、緩存更新機制、緩存可用性、緩存服務降級、緩存穿透、緩存預熱等緩存使用問題。

  • 文檔數據庫 MongoDB

MongoDB 是對傳統關係型數據庫的補充,它很是適合高伸縮性的場景,它是可擴展性的表結構。基於這點,能夠將預期範圍內,表結構可能會不斷擴展的 MySQL 表結構,經過 MongoDB 來存儲,這就能夠保證表結構的擴展性。

此外,日誌系統數據量特別大,若是用 MongoDB 數據庫存儲這些數據,利用分片集羣支持海量數據,同時使用匯集分析和 MapReduce 的能力,是個很好的選擇。

MongoDB 還適合存儲大尺寸的數據,GridFS 存儲方案就是基於 MongoDB 的分佈式文件存儲系統。

  • 列族數據庫 HBase

HBase 適合海量數據的存儲與高性能實時查詢,它是運行於 HDFS 文件系統之上,而且做爲 MapReduce 分佈式處理的目標數據庫,以支撐離線分析型應用。在數據倉庫、數據集市、商業智能等領域發揮了愈來愈多的做用,在數以千計的企業中支撐着大量的大數據分析場景的應用。

  • 全文搜索引擎 ElasticSearch

在通常狀況下,關係型數據庫的模糊查詢,都是經過 like 的方式進行查詢。其中,like 「value%」 能夠使用索引,可是對於 like 「%value%」 這樣的方式,執行全表查詢,這在數據量小的表,不存在性能問題,可是對於海量數據,全表掃描是很是可怕的事情。ElasticSearch 做爲一個創建在全文搜索引擎 Apache Lucene 基礎上的實時的分佈式搜索和分析引擎,適用於處理實時搜索應用場景。此外,使用 ElasticSearch 全文搜索引擎,還能夠支持多詞條查詢、匹配度與權重、自動聯想、拼寫糾錯等高級功能。所以,能夠使用 ElasticSearch 做爲關係型數據庫全文搜索的功能補充,將要進行全文搜索的數據緩存一份到 ElasticSearch 上,達處處理複雜的業務與提升查詢速度的目的。

ElasticSearch 不只僅適用於搜索場景,還很是適合日誌處理與分析的場景。著名的 ELK 日誌處理方案,由 ElasticSearch、Logstash 和 Kibana 三個組件組成,包括了日誌收集、聚合、多維度查詢、可視化顯示等。

ObjectId 規則

參考:

MongoDB學習筆記~ObjectId主鍵的設計

mongodb中的_id的ObjectId的生成規則

聊聊 MongoDB 使用場景

參考:

什麼場景應該用 MongoDB ?

倒排索引

參考:

什麼是倒排索引?

聊聊 ElasticSearch 使用場景

在通常狀況下,關係型數據庫的模糊查詢,都是經過 like 的方式進行查詢。其中,like 「value%」 能夠使用索引,可是對於 like 「%value%」 這樣的方式,執行全表查詢,這在數據量小的表,不存在性能問題,可是對於海量數據,全表掃描是很是可怕的事情。ElasticSearch 做爲一個創建在全文搜索引擎 Apache Lucene 基礎上的實時的分佈式搜索和分析引擎,適用於處理實時搜索應用場景。此外,使用 ElasticSearch 全文搜索引擎,還能夠支持多詞條查詢、匹配度與權重、自動聯想、拼寫糾錯等高級功能。所以,能夠使用 ElasticSearch 做爲關係型數據庫全文搜索的功能補充,將要進行全文搜索的數據緩存一份到 ElasticSearch 上,達處處理複雜的業務與提升查詢速度的目的。

2、緩存使用

Redis 有哪些類型

Redis支持五種數據類型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。

參考:
Redis 數據類型

Redis 內部結構

參考:

redis內部數據結構深刻淺出

聊聊 Redis 使用場景

隨着數據量的增加,MySQL 已經知足不了大型互聯網類應用的需求。所以,Redis 基於內存存儲數據,能夠極大的提升查詢性能,對產品在架構上很好的補充。例如,爲了提升服務端接口的訪問速度,儘量將讀頻率高的熱點數據存放在 Redis 中。這個是很是典型的以空間換時間的策略,使用更多的內存換取 CPU 資源,經過增長系統的內存消耗,來加快程序的運行速度。

在某些場景下,能夠充分的利用 Redis 的特性,大大提升效率。這些場景包括緩存,會話緩存,時效性,訪問頻率,計數器,社交列表,記錄用戶斷定信息,交集、並集和差集,熱門列表與排行榜,最新動態等。

使用 Redis 作緩存的時候,須要考慮數據不一致與髒讀、緩存更新機制、緩存可用性、緩存服務降級、緩存穿透、緩存預熱等緩存使用問題。

Redis 持久化機制

參考:

redis的持久化和緩存機制

Redis 如何實現持久化

參考:

Redis如何實現持久化

Redis 集羣方案與實現

參考:

redis集羣主流架構方案分析

Redis 爲何是單線程的

單純的網絡IO來講,量大到必定程度以後,多線程的確有優點——但並非單純的多線程,而是每一個線程本身有本身的epoll這樣的模型,也就是多線程和multiplexing混合。

通常這個開頭咱們都會跟一個「可是」。
可是。

還要考慮Redis操做的對象。它操做的對象是內存中的數據結構。若是在多線程中操做,那就須要爲這些對象加鎖。最終來講,多線程性能有提升,可是每一個線程的效率嚴重降低了。並且程序的邏輯嚴重複雜化。
要知道Redis的數據結構並不全是簡單的Key-Value,還有列表,hash,map等等複雜的結構,這些結構有可能會進行很細粒度的操做,好比在很長的列表後面添加一個元素,在hash當中添加或者刪除一個對象,等等。這些操做還能夠合成MULTI/EXEC的組。這樣一個操做中可能就須要加很是多的鎖,致使的結果是同步開銷大大增長。這還帶來一個惡果就是吞吐量雖然增大,可是響應延遲可能會增長。
Redis在權衡以後的選擇是用單線程,突出本身功能的靈活性。在單線程基礎上任何原子操做均可以幾乎無代價地實現,多麼複雜的數據結構均可以輕鬆運用,甚至能夠使用Lua腳本這樣的功能。對於多線程來講這須要高得多的代價。

並非全部的KV數據庫或者內存數據庫都應該用單線程,好比ZooKeeper就是多線程的,最終仍是看做者本身的意願和取捨。單線程的威力實際上很是強大,每核心效率也很是高,在今天的虛擬化環境當中能夠充分利用雲化環境來提升資源利用率。多線程天然是能夠比單線程有更高的性能上限,可是在今天的計算環境中,即便是單機多線程的上限也每每不能知足須要了,須要進一步摸索的是多服務器集羣化的方案,這些方案中多線程的技術照樣是用不上的,因此單線程、多進程的集羣不失爲一個時髦的解決方案。

做者:靈劍
連接:https://www.zhihu.com/question/23162208/answer/142424042
來源:知乎
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

緩存奔潰

參考:

Redis持久化

緩存降級

服務降級的目的,是爲了防止Redis服務故障,致使數據庫跟着一塊兒發生雪崩問題。所以,對於不重要的緩存數據,能夠採起服務降級策略,例如一個比較常見的作法就是,Redis出現問題,不去數據庫查詢,而是直接返回默認值給用戶。

使用緩存的合理性問題

參考:

Redis實戰(一) 使用緩存合理性

3、消息隊列

消息隊列的使用場景

主要解決應用耦合,異步消息,流量削鋒等問題

消息隊列使用的四種場景介紹

消息的重發補償解決思路

參考:

JMS消息傳送機制

消息的冪等性解決思路

參考:

MQ之如何作到消息冪等

消息的堆積解決思路

參考:

Sun Java System Message Queue 3.7 UR1 管理指南

本身如何實現消息隊列

參考:

本身動手實現消息隊列之JMS

如何保證消息的有序性

參考:

消息隊列的exclusive consumer功能是如何保證消息有序和防止腦裂的


 

框架篇

1、Spring

BeanFactory 和 ApplicationContext 有什麼區別

beanfactory顧名思義,它的核心概念就是bean工廠,用做於bean生命週期的管理,而applicationcontext這個概念就比較豐富了,單看名字(應用上下文)就能看出它包含的範圍更廣,它繼承自bean factory但不只僅是繼承自這一個接口,還有繼承了其餘的接口,因此它不只僅有bean factory相關概念,更是一個應用系統的上下文,其設計初衷應該是一個一應俱全的對外暴露的一個綜合的API。

Spring Bean 的生命週期

參考:

Spring Bean生命週期詳解

Spring IOC 如何實現

參考:

Spring:源碼解讀Spring IOC原理

說說 Spring AOP

參考:

Spring AOP詳解

Spring AOP 實現原理

參考:

Spring AOP 實現原理

動態代理(cglib 與 JDK)

java動態代理是利用反射機制生成一個實現代理接口的匿名類,在調用具體方法前調用InvokeHandler來處理。

而cglib動態代理是利用asm開源包,對代理對象類的class文件加載進來,經過修改其字節碼生成子類來處理。

一、若是目標對象實現了接口,默認狀況下會採用JDK的動態代理實現AOP
二、若是目標對象實現了接口,能夠強制使用CGLIB實現AOP
三、若是目標對象沒有實現了接口,必須採用CGLIB庫,spring會自動在JDK動態代理和CGLIB之間轉換

如何強制使用CGLIB實現AOP?
(1)添加CGLIB庫,SPRING_HOME/cglib/*.jar
(2)在spring配置文件中加入

JDK動態代理和CGLIB字節碼生成的區別?
(1)JDK動態代理只能對實現了接口的類生成代理,而不能針對類
(2)CGLIB是針對類實現代理,主要是對指定的類生成一個子類,覆蓋其中的方法
由於是繼承,因此該類或方法最好不要聲明成final

參考:

Spring的兩種代理JDK和CGLIB的區別淺談

Spring 事務實現方式

參考:

Spring事務管理實現方式之編程式事務與聲明式事務詳解

Spring 事務底層原理

參考:

深刻理解 Spring 事務原理

如何自定義註解實現功能

能夠結合spring的AOP,對註解進行攔截,提取註解。

大體流程爲:
1. 新建一個註解@MyLog,加在須要註解申明的方法上面
2. 新建一個類MyLogAspect,經過@Aspect註解使該類成爲切面類。
3. 經過@Pointcut 指定切入點 ,這裏指定的切入點爲MyLog註解類型,也就是被@MyLog註解修飾的方法,進入該切入點。
4. MyLogAspect中的方法經過加通知註解(@Before、@Around、@AfterReturning、@AfterThrowing、@After等各類通知)指定要作的業務操做。

Spring MVC 運行流程

1、先用文字描述

1.用戶發送請求到DispatchServlet

2.DispatchServlet根據請求路徑查詢具體的Handler

3.HandlerMapping返回一個HandlerExcutionChain給DispatchServlet

HandlerExcutionChain:Handler和Interceptor集合

4.DispatchServlet調用HandlerAdapter適配器

5.HandlerAdapter調用具體的Handler處理業務

6.Handler處理結束返回一個具體的ModelAndView給適配器

ModelAndView:model–>數據模型,view–>視圖名稱

7.適配器將ModelAndView給DispatchServlet

8.DispatchServlet把視圖名稱給ViewResolver視圖解析器

9.ViewResolver返回一個具體的視圖給DispatchServlet

10.渲染視圖

11.展現給用戶

2、畫圖解析

SpringMvc的配置

Spring MVC 啓動流程

參考:

SpringMVC啓動過程詳解(li)

Spring 的單例實現原理

參考:

Spring的單例模式底層實現

Spring 框架中用到了哪些設計模式

Spring框架中使用到了大量的設計模式,下面列舉了比較有表明性的:

代理模式—在AOP和remoting中被用的比較多。
單例模式—在spring配置文件中定義的bean默認爲單例模式。
模板方法—用來解決代碼重複的問題。好比. RestTemplate, JmsTemplateJpaTemplate。
工廠模式—BeanFactory用來建立對象的實例。
適配器–spring aop
裝飾器–spring data hashmapper
觀察者– spring 時間驅動模型
回調–Spring ResourceLoaderAware回調接口
前端控制器–spring用前端控制器DispatcherServlet對請求進行分發

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

參考:

說一說Spring家族

2、Netty

爲何選擇 Netty

Netty 是業界最流行的 NIO 框架之一,它的健壯性、功能、性能、可定製性和可擴展性在同類框架中都是數一數二的,它已經獲得成百上千的商用項目驗證,例如 Hadoop 的 RPC 框架 Avro 使用 Netty 做爲通訊框架。不少其它業界主流的 RPC 和分佈式服務框架,也使用 Netty 來構建高性能的異步通訊能力。

Netty 的優勢總結以下:

  • API 使用簡單,開發門檻低;
  • 功能強大,預置了多種編解碼功能,支持多種主流協議;
  • 定製能力強,能夠經過 ChannelHandler 對通訊框架進行靈活的擴展;
  • 性能高,經過與其它業界主流的 NIO 框架對比,Netty 的綜合性能最優;
  • 社區活躍,版本迭代週期短,發現的 BUG 能夠被及時修復,同時,更多的新功能會被加入;
  • 經歷了大規模的商業應用考驗,質量獲得驗證。在互聯網、大數據、網絡遊戲、企業應用、電信軟件等衆多行業獲得成功商用,證實了它徹底知足不一樣行業的商用標準。

正是由於這些優勢,Netty 逐漸成爲 Java NIO 編程的首選框架。

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

有關「爲什麼選擇Netty」的11個疑問及解答

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

它會致使Selector空輪詢,最終致使CPU 100%。官方聲稱在JDK1.6版本的update18修復了該問題,可是直到JDK1.7版本該問題仍舊存在,只不過該BUG發生機率下降了一些而已,它並無被根本解決。該BUG以及與該BUG相關的問題單能夠參見如下連接內容。

http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6403933

http://bugs.java.com/bugdatabase/view_bug.do?bug_id=2147719

異常堆棧以下:

java.lang.Thread.State: RUNNABLE  
        at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)  
        at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:210)  
        at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:65)  
        at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:69)  
        - locked <0x0000000750928190> (a sun.nio.ch.Util$2)  
        - locked <0x00000007509281a8> (a java.util.Collections$ UnmodifiableSet)  
        - locked <0x0000000750946098> (a sun.nio.ch.EPollSelectorImpl)  
        at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:80)  
        at net.spy.memcached.MemcachedConnection.handleIO(Memcached Connection.java:217)  
        at net.spy.memcached.MemcachedConnection.run(MemcachedConnection. java:836) 

什麼是TCP 粘包/拆包

參考:

TCP粘包,拆包及解決方法

TCP粘包/拆包的解決辦法

參考:

TCP粘包,拆包及解決方法

Netty 線程模型

參考:

Netty4實戰第十五章:選擇正確的線程模型

說說 Netty 的零拷貝

參考:

理解Netty中的零拷貝(Zero-Copy)機制

Netty 內部執行流程

參考:

Netty:數據處理流程

Netty 重連實現

參考:

Netty Client 重連實現


 

微服務篇

1、微服務

先後端分離是如何作的

參考:

實現先後端分離的心得

微服務哪些框架

Spring Cloud、Dubbo、Hsf等

你怎麼理解 RPC 框架

RPC的目的是讓你在本地調用遠程的方法,而對你來講這個調用是透明的,你並不知道這個調用的方法是部署哪裏。經過RPC能解耦服務,這纔是使用RPC的真正目的。

說說 RPC 的實現原理

參考:

你應該知道的 RPC 原理

從零開始實現RPC框架 - RPC原理及實現

說說 Dubbo 的實現原理

dubbo提供功能來說, 提供基礎功能-RPC調用 提供增值功能SOA服務治理
dubbo啓動時查找可用的遠程服務提供者,調用接口時不是最終調用本地實現,而是經過攔截調用(又用上JDK動態代理功能)過程通過一系列的的序列化、遠程通訊、協議解析最終調用到遠程服務提供者

參考:

Dubbo解析及原理淺析

你怎麼理解 RESTful

REST是 一種軟件架構風格、設計風格,它是一種面向資源的網絡化超媒體應用的架構風格。它主要是用於構建輕量級的、可維護的、可伸縮的 Web 服務。基於 REST 的服務被稱爲 RESTful 服務。REST 不依賴於任何協議,可是幾乎每一個 RESTful 服務使用 HTTP 做爲底層協議,RESTful使用http method標識操做,例如:

http://127.0.0.1/user/1 GET 根據用戶id查詢用戶數據
http://127.0.0.1/user POST 新增用戶
http://127.0.0.1/user PUT 修改用戶信息

http://127.0.0.1/user DELETE 刪除用戶信息

說說如何設計一個良好的 API

參考:

如何設計一個良好的API?

如何理解 RESTful API 的冪等性

參考:

如何理解RESTful的冪等性

如何保證接口的冪等性

參考:

後端接口的冪等性

說說 CAP 定理、 BASE 理論

參考:

CAP原理和BASE思想

怎麼考慮數據一致性問題

參考:

分佈式系統事務一致性解決方案

說說最終一致性的實現方案

能夠結合MQ實現最終一致性,例如電商系統,把生成訂單數據的寫操做邏輯經過事務控制,一些可有可無的業務例如日誌處理,通知,經過異步消息處理,最終到請求落地。

參考:

系統分佈式狀況下最終一致性方案梳理

你怎麼看待微服務

  • 小:微服務體積小
  • 獨:可以獨立的部署和運行。
  • 輕:使用輕量級的通訊機制和架構。
  • 鬆:爲服務之間是鬆耦合的。

微服務與 SOA 的區別

能夠把微服務當作去除了ESB的SOA。ESB是SOA架構中的中心總線,設計圖形應該是星形的,而微服務是去中心化的分佈式軟件架構。

參考:

SOA 與 微服務的區別

如何拆分服務

參考:

微服務架構(二): 如何把應用分解成多個服務

微服務如何進行數據庫管理

參考:

在微服務中如何管理數據

如何應對微服務的鏈式調用異常

參考:

踢開絆腳石:微服務難點之服務調用的解決方案

對於快速追蹤與定位問題

參考:

微服務架構下,如何實現分佈式跟蹤?

微服務的安全

參考:

論微服務安全

2、分佈式

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

1、解決java集羣的session共享的解決方案:
1.客戶端cookie加密。(通常用於內網中企業級的系統中,要求用戶瀏覽器端的cookie不能禁用,禁用的話,該方案會失效)。
2.集羣中,各個應用服務器提供了session複製的功能,tomcat和jboss都實現了這樣的功能。特色:性能隨着服務器增長急劇降低,容易引發廣播風暴;session數據須要序列化,影響性能。
3.session的持久化,使用數據庫來保存session。就算服務器宕機也沒事兒,數據庫中的session照樣存在。特色:每次請求session都要讀寫數據庫,會帶來性能開銷。使用內存數據庫,會提升性能,可是宕機會丟失數據(像支付寶的宕機,有同城災備、異地災備)。
4.使用共享存儲來保存session。和數據庫相似,就算宕機了也沒有事兒。其實就是專門搞一臺服務器,所有對session落地。特色:頻繁的進行序列化和反序列化會影響性能。
5.使用memcached來保存session。本質上是內存數據庫的解決方案。特色:存入memcached的數據須要序列化,效率極低。

2、分佈式事務的解決方案:
1.TCC解決方案:try confirm cancel。

參考:
爲何說傳統分佈式事務再也不適用於微服務架構?

Session 分佈式方案

1.客戶端cookie加密。(通常用於內網中企業級的系統中,要求用戶瀏覽器端的cookie不能禁用,禁用的話,該方案會失效)。
2.集羣中,各個應用服務器提供了session複製的功能,tomcat和jboss都實現了這樣的功能。特色:性能隨着服務器增長急劇降低,容易引發廣播風暴;session數據須要序列化,影響性能。
3.session的持久化,使用數據庫來保存session。就算服務器宕機也沒事兒,數據庫中的session照樣存在。特色:每次請求session都要讀寫數據庫,會帶來性能開銷。使用內存數據庫,會提升性能,可是宕機會丟失數據(像支付寶的宕機,有同城災備、異地災備)。
4.使用共享存儲來保存session。和數據庫相似,就算宕機了也沒有事兒。其實就是專門搞一臺服務器,所有對session落地。特色:頻繁的進行序列化和反序列化會影響性能。
5.使用memcached來保存session。本質上是內存數據庫的解決方案。特色:存入memcached的數據須要序列化,效率極低。

分佈式鎖的場景

好比交易系統的金額修改,同一時間只能又一我的操做,好比秒殺場景,同一時間只能一個用戶搶到,好比火車站搶票等等

分佈式鎖的實現方案

  1. 基於數據庫實現分佈式鎖
  2. 基於緩存實現分佈式鎖
  3. 基於Zookeeper實現分佈式鎖

參考:

分佈式鎖的多種實現方式

分佈式事務

參考:

深刻理解分佈式事務,高併發下分佈式事務的解決方案

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

參考:

負載均衡算法及手段

說說分庫與分表設計

參考:

分表與分庫使用場景以及設計方式

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

參考:

服務端指南 數據存儲篇 | MySQL(09) 分庫與分錶帶來的分佈式困境與應對之策


 

安全&性能

1、安全問題

安全要素與 STRIDE 威脅

防範常見的 Web 攻擊

服務端通訊安全攻防

HTTPS 原理剖析

HTTPS 降級攻擊

受權與認證

基於角色的訪問控制

基於數據的訪問控制

2、性能優化

性能指標有哪些

如何發現性能瓶頸

性能調優的常見手段

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


 

工程篇

1、需求分析

你如何對需求原型進行理解和拆分

說說你對功能性需求的理解

說說你對非功能性需求的理解

你針對產品提出哪些交互和改進意見

你如何理解用戶痛點

2、設計能力

說說你在項目中使用過的 UML 圖

你如何考慮組件化

你如何考慮服務化

你如何進行領域建模

你如何劃分領域邊界

說說你項目中的領域建模

說說概要設計

3、設計模式

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

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

說說你對設計原則的理解

23種設計模式的設計理念

設計模式之間的異同,例如策略模式與狀態模式的區別

設計模式之間的結合,例如策略模式+簡單工廠模式的實踐

設計模式的性能,例如單例模式哪一種性能更好。

4、業務工程

你係統中的先後端分離是如何作的

說說你的開發流程

你和團隊是如何溝通的

你如何進行代碼評審

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

說說你在項目中常常遇到的 Exception

說說你在項目中遇到感受最難Bug,怎麼解決的

說說你在項目中遇到印象最深困難,怎麼解決的

你以爲大家項目還有哪些不足的地方

你是否遇到過 CPU 100% ,如何排查與解決

你是否遇到過 內存 OOM ,如何排查與解決

說說你對敏捷開發的實踐

說說你對開發運維的實踐

介紹下工做中的一個對本身最有價值的項目,以及在這個過程當中的角色

5、軟實力

說說你的亮點

說說你最近在看什麼書

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

工做之餘作什麼事情

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

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

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

說說你所理解的技術專家

相關文章
相關標籤/搜索