1. 程式人生 > >Java程式設計師面試必備:Volatile全方位解析

Java程式設計師面試必備:Volatile全方位解析

前言

volatile是Java程式設計師必備的基礎,也是面試官非常喜歡問的一個話題,本文跟大家一起開啟vlatile學習之旅,如果有不正確的地方,也麻煩大家指出哈,一起相互學習~

  • 1.volatile的用法
  • 2.vlatile變數的作用
  • 3.現代計算機的記憶體模型(計算機模型,匯流排,MESI協議,嗅探技術)
  • 4.Java記憶體模型(JMM)
  • 5.併發程式設計的3個特性(原子性、可見性、有序性、happen-before、as-if-serial、指令重排)
  • 6.volatile的底層原理(如何保證可見性,如何保證指令重排,記憶體屏障)
  • 7.volatile的典型場景(狀態標誌,DCL單例模式)
  • 8.volatile常見面試題&&答案解析
  • 公眾號:撿田螺的小男孩

「github 地址」

https://github.com/whx123/JavaHome

1.volatile的用法

volatile關鍵字是Java虛擬機器提供的的「最輕量級的同步機制」,它作為一個修飾符出現,用來「修飾變數」,但是這裡不包括區域性變數哦。我們來看個demo吧,程式碼如下:

/**
 *  @Author 撿田螺的小男孩
 *  @Date 2020/08/02
 *  @Desc volatile的可見性探索
 */
public class VolatileTest  {

    public static void main(String[] args) throws InterruptedException {
        Task task = new Task();

        Thread t1 = new Thread(task, "執行緒t1");
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                    System.out.println("開始通知執行緒停止");
                    task.stop = true; //修改stop變數值。
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }, "執行緒t2");
        t1.start();  //開啟執行緒t1
        t2.start();  //開啟執行緒t2
        Thread.sleep(1000);
    }
}

class Task implements Runnable {
    boolean stop = false;
    int i = 0;

    @Override
    public void run() {
        long s = System.currentTimeMillis();
        while (!stop) {
            i++;
        }
        System.out.println("執行緒退出" + (System.currentTimeMillis() - s));
    }
}

「執行結果:」 可以發現執行緒t2,雖然把stop設定為true了,但是執行緒t1對t2的「stop變數視而不可見」,因此,它一直在死迴圈running中。如果給變數stop加上volatile修飾,執行緒t1是可以停下來的,執行結果如下:

volatile boolean stop = false;

2. vlatile修飾變數的作用

從以上例子,我們可以發現變數stop,加了vlatile修飾之後,執行緒t1對stop就可見了。其實,vlatile的作用就是:「保證變數對所有執行緒可見性」。當然,vlatile還有個作用就是,「禁止指令重排」,但是它「不保證原子性」。

所以當面試官問你「volatile的作用或者特性」,都可以這麼回答:

  • 保證變數對所有執行緒可見性;
  • 禁止指令重排序
  • 不保證原子性

3. 現代計算機的記憶體模型(計算機模型,MESI協議,嗅探技術,匯流排)

為了更好理解volatile,先回顧一下計算機的記憶體模型與JMM(Java記憶體模型)吧~

計算機模型

計算機執行程式時,指令是由CPU處理器執行的,而打交道的資料是在主記憶體當中的。

由於計算機的儲存裝置與處理器的運算速度有幾個數量級的差距,總不能每次CPU執行完指令,然後等主記憶體慢悠悠存取資料吧, 所以現代計算機系統加入一層讀寫速度接近處理器運算速度的快取記憶體(Cache),以作為來作為記憶體與處理器之間的緩衝。

在多路處理器系統中,每個處理器都有自己的快取記憶體,而它們共享同一主記憶體。「計算機抽象記憶體模型」如下:

  • 程式執行時,把需要用到的資料,從主記憶體拷貝一份到快取記憶體。
  • CPU處理器計算時,從它的快取記憶體中讀取,把計算完的資料寫入快取記憶體。
  • 當程式運算結束,把快取記憶體的資料重新整理會主記憶體。

隨著科學技術的發展,為了效率,快取記憶體又衍生出一級快取(L1),二級快取(L2),甚至三級快取(L3);

當多個處理器的運算任務都涉及同一塊主記憶體區域,可能導致「快取資料不一致」問題。如何解決這個問題呢?有兩種方案

  • 1、通過在匯流排加LOCK#鎖的方式。
  • 2、通過快取一致性協議(Cache Coherence Protocol)

匯流排

匯流排(Bus)是計算機各種功能部件之間傳送資訊的公共通訊幹線,它是由導線組成的傳輸線束, 按照計算機所傳輸的資訊種類,計算機的匯流排可以劃分為資料匯流排、地址匯流排和控制匯流排,分別用來傳輸資料、資料地址和控制訊號。

CPU和其他功能部件是通過匯流排通訊的,如果在匯流排加LOCK#鎖,那麼在鎖住匯流排期間,其他CPU是無法訪問記憶體,這樣一來,「效率就比較低了」。

MESI協議

為了解決一致性問題,還可以通過快取一致性協議。即各個處理器訪問快取時都遵循一些協議,在讀寫時要根據協議來進行操作,這類協議有MSI、MESI(IllinoisProtocol)、MOSI、Synapse、Firefly及DragonProtocol等。比較著名的就是Intel的MESI(Modified Exclusive Shared Or Invalid)協議,它的核心思想是:

當CPU寫資料時,如果發現操作的變數是共享變數,即在其他CPU中也存在該變數的副本,會發出訊號通知其他CPU將該變數的快取行置為無效狀態,因此當其他CPU需要讀取這個變數時,發現自己快取中快取該變數的快取行是無效的,那麼它就會從記憶體重新讀取。

CPU中每個快取行標記的4種狀態(M、E、S、I),也瞭解一下吧:

快取狀態 描述
M,被修改(Modified) 該快取行只被該CPU快取,與主存的值不同,會在它被其他CPU讀取之前寫入記憶體,並設定為Shared
E,獨享的(Exclusive) 該快取行只被該CPU快取,與主存的值相同,被其他CPU讀取時置為Shared,被其他CPU寫時置為Modified
S,共享的(Shared) 該快取行可能被多個CPU快取,各個快取中的資料與主存資料相同
I,無效的(Invalid) 該快取行資料是無效,需要時需重新從主存載入

MESI協議是如何實現的?如何保證當前處理器的內部快取、主記憶體和其他處理器的快取資料在總線上保持一致的?「多處理器匯流排嗅探」

嗅探技術

在多處理器下,為了保證各個處理器的快取是一致的,就會實現快取快取一致性協議,每個處理器通過嗅探在總線上傳播的資料來檢查自己的快取值是不是過期了,如果處理器發現自己快取行對應的記憶體地址被修改,就會將當前處理器的快取行設定無效狀態,當處理器對這個資料進行修改操作的時候,會重新從系統記憶體中把資料庫讀到處理器快取中。

4. Java記憶體模型(JMM)

  • Java虛擬機器規範試圖定義一種Java記憶體模型,來「遮蔽掉各種硬體和作業系統的記憶體訪問差異」,以實現讓Java程式在各種平臺上都能達到一致的記憶體訪問效果。
  • Java記憶體模型「類比」於計算機記憶體模型。
  • 為了更好的執行效能,java記憶體模型並沒有限制執行引擎使用處理器的特定暫存器或快取來和主記憶體打交道,也沒有限制編譯器進行調整程式碼順序優化。所以Java記憶體模型「會存在快取一致性問題和指令重排序問題的」。
  • Java記憶體模型規定所有的變數都是存在主記憶體當中(類似於計算機模型中的實體記憶體),每個執行緒都有自己的工作記憶體(類似於計算機模型的快取記憶體)。這裡的「變數」包括例項變數和靜態變數,但是「不包括區域性變數」,因為區域性變數是執行緒私有的。
  • 執行緒的工作記憶體儲存了被該執行緒使用的變數的主記憶體副本,「執行緒對變數的所有操作都必須在工作記憶體中進行」,而不能直接操作操作主記憶體。並且每個執行緒不能訪問其他執行緒的工作記憶體。

舉個例子吧,假設i的初始值是0,執行以下語句:

i = i+1;

首先,執行執行緒t1從主記憶體中讀取到i=0,到工作記憶體。然後在工作記憶體中,賦值i+1,工作記憶體就得到i=1,最後把結果寫回主記憶體。因此,如果是單執行緒的話,該語句執行是沒問題的。但是呢,執行緒t2的本地工作記憶體還沒過期,那麼它讀到的資料就是髒資料了。如圖:

Java記憶體模型是圍繞著如何在併發過程中如何處理「原子性、可見性和有序性」這3個特徵來建立的,我們再來一起回顧一下~

5.併發程式設計的3個特性(原子性、可見性、有序性)

原子性

原子性,指操作是不可中斷的,要麼執行完成,要麼不執行,基本資料型別的訪問和讀寫都是具有原子性,當然(long和double的非原子性協定除外)。我們來看幾個小例子:

i =666; // 語句1
i = j;   // 語句2
i = i+1;  //語句 3
i++;   // 語句4
  • 語句1操作顯然是原子性的,將數值666賦值給i,即執行緒執行這個語句時,直接將數值666寫入到工作記憶體中。
  • 語句2操作看起來也是原子性的,但是它實際上涉及兩個操作,先去讀j的值,再把j的值寫入工作記憶體,兩個操作分開都是原子操作,但是合起來就不滿足原子性了。
  • 語句3讀取i的值,加1,再寫回主存,這個就不是原子性操作了。
  • 語句4 等同於語句3,也是非原子性操作。

可見性

  • 可見性就是指當一個執行緒修改了共享變數的值時,其他執行緒能夠立即得知這個修改。
  • Java記憶體模型是通過在變數修改後將新值同步回主記憶體,在變數讀取前從主記憶體重新整理變數值這種依賴主記憶體作為傳遞媒介的方式來實現可見性的,無論是普通變數還是volatile變數都是如此。
  • volatile變數,保證新值能立即同步回主記憶體,以及每次使用前立即從主記憶體重新整理,所以我們說volatile保證了多執行緒操作變數的可見性。
  • synchronized和Lock也能夠保證可見性,執行緒在釋放鎖之前,會把共享變數值都刷回主存。final也可以實現可見性。

有序性

Java虛擬機器這樣描述Java程式的有序性的:如果在本執行緒內觀察,所有的操作都是有序的;如果在一個執行緒中,觀察另一個執行緒,所有的操作都是無序的。

後半句意思就是,在Java記憶體模型中,「允許編譯器和處理器對指令進行重排序」,會影響到多執行緒併發執行的正確性;前半句意思就是「as-if-serial」的語義,即不管怎麼重排序(編譯器和處理器為了提高並行度),(單執行緒)程式的執行結果不會被改變。

比如以下程式程式碼:

double pi  = 3.14;    //A
double r   = 1.0;     //B
double area = pi * r * r; //C

步驟C依賴於步驟A和B,因為指令重排的存在,程式執行順訊可能是A->B->C,也可能是B->A->C,但是C不能在A或者B前面執行,這將違反as-if-serial語義。

看段程式碼吧,假設程式先執行read方法,再執行add方法,結果一定是輸出sum=2嘛?

bool flag = false;
int b = 0;

public void read() {
   b = 1;              //1
   flag = true;        //2
}

public void add() {
   if (flag) {         //3
       int sum =b+b;   //4
       System.out.println("bb sum is"+sum); 
   } 
}

如果是單執行緒,結果應該沒問題,如果是多執行緒,執行緒t1對步驟1和2進行了「指令重排序」呢?結果sum就不是2了,而是0,如下圖所示:

這是為啥呢?「指令重排序」瞭解一下,指令重排是指在程式執行過程中,「為了提高效能」, 「編譯器和CPU可能會對指令進行重新排序」。CPU重排序包括指令並行重排序和記憶體系統重排序,重排序型別和重排序執行過程如下:

實際上,可以給flag加上volatile關鍵字,來保證有序性。當然,也可以通過synchronized和Lock來保證有序性。synchronized和Lock保證某一時刻是隻有一個執行緒執行同步程式碼,相當於是讓執行緒順序執行程式程式碼了,自然就保證了有序性。

實際上Java記憶體模型的有序性並不是僅靠volatile、synchronized和Lock來保證有序性的。這是因為Java語言中,有一個先行發生原則(happens-before):

  • 「程式次序規則」:在一個執行緒內,按照控制流順序,書寫在前面的操作先行發生於書寫在後面的操作。
  • 「管程鎖定規則」:一個unLock操作先行發生於後面對同一個鎖額lock操作
  • 「volatile變數規則」:對一個變數的寫操作先行發生於後面對這個變數的讀操作
  • 「執行緒啟動規則」:Thread物件的start()方法先行發生於此執行緒的每個一個動作
  • 「執行緒終止規則」:執行緒中所有的操作都先行發生於執行緒的終止檢測,我們可以通過Thread.join()方法結束、Thread.isAlive()的返回值手段檢測到執行緒已經終止執行
  • 「執行緒中斷規則」:對執行緒interrupt()方法的呼叫先行發生於被中斷執行緒的程式碼檢測到中斷事件的發生
  • 「物件終結規則」:一個物件的初始化完成先行發生於他的finalize()方法的開始
  • 「傳遞性」:如果操作A先行發生於操作B,而操作B又先行發生於操作C,則可以得出操作A先行發生於操作C

根據happens-before的八大規則,我們回到剛的例子,一起分析一下。給flag加上volatile關鍵字,look look它是如何保證有序性的,

volatile bool flag = false;
int b = 0;

public void read() {
   b = 1;              //1
   flag = true;        //2
}

public void add() {
   if (flag) {         //3
       int sum =b+b;   //4
       System.out.println("bb sum is"+sum); 
   } 
}
  • 首先呢,flag加上volatile關鍵字,那就禁止了指令重排,也就是1 happens-before 2了
  • 根據「volatile變數規則」,2 happens-before 3
  • 由「程式次序規則」,得出 3 happens-before 4
  • 最後由「傳遞性」,得出1 happens-before 4,因此妥妥的輸出sum=2啦~

6.volatile底層原理

以上討論學習,我們知道volatile的語義就是保證變數對所有執行緒可見性以及禁止指令重排優化。那麼,它的底層是如何保證可見性和禁止指令重排的呢?

圖解volatile是如何保證可見性的?

在這裡,先看幾個圖吧,哈哈~

假設flag變數的初始值false,現在有兩條執行緒t1和t2要訪問它,就可以簡化為以下圖:

如果執行緒t1執行以下程式碼語句,並且flag沒有volatile修飾的話;t1剛修改完flag的值,還沒來得及重新整理到主記憶體,t2又跑過來讀取了,很容易就資料flag不一致了,如下:

flag=true;

如果flag變數是由volatile修飾的話,就不一樣了,如果執行緒t1修改了flag值,volatile能保證修飾的flag變數後,可以「立即同步回主記憶體」。如圖:

細心的朋友會發現,執行緒t2不還是flag舊的值嗎,這不還有問題嘛?其實volatile還有一個保證,就是「每次使用前立即先從主記憶體重新整理最新的值」,執行緒t1修改完後,執行緒t2的變數副本會過期了,如圖:

顯然,這裡還不是底層,實際上volatile保證可見性和禁止指令重排都跟「記憶體屏障」有關,我們編譯volatile相關程式碼看看~

DCL單例模式(volatile)&編譯對比

DCL單例模式(Double Check Lock,雙重檢查鎖)比較常用,它是需要volatile修飾的,所以就拿這段程式碼編譯吧

public class Singleton {  
    private volatile static Singleton instance;  
    private Singleton (){}  
    public static Singleton getInstance() {  
    if (instance == null) {  
        synchronized (Singleton.class) {  
        if (instance == null) {  
            instance = new Singleton();  
        }  
        }  
    }  
    return instance;  
    }  
}  

編譯這段程式碼後,觀察有volatile關鍵字和沒有volatile關鍵字時的instance所生成的彙編程式碼發現,有volatile關鍵字修飾時,會多出一個lock addl $0x0,(%esp),即多出一個lock字首指令

0x01a3de0f: mov    $0x3375cdb0,%esi   ;...beb0cd75 33  
                                        ;   {oop('Singleton')}  
0x01a3de14: mov    %eax,0x150(%esi)   ;...89865001 0000  
0x01a3de1a: shr    $0x9,%esi          ;...c1ee09  
0x01a3de1d: movb   $0x0,0x1104800(%esi)  ;...c6860048 100100  
0x01a3de24: lock addl $0x0,(%esp)     ;...f0830424 00  
                                        ;*putstatic instance  
                                        ; - Singleton::getInstance@24 

lock指令相當於一個「記憶體屏障」,它保證以下這幾點:

  • 1.重排序時不能把後面的指令重排序到記憶體屏障之前的位置
  • 2.將本處理器的快取寫入記憶體
  • 3.如果是寫入動作,會導致其他處理器中對應的快取無效。

顯然,第2、3點不就是volatile保證可見性的體現嘛,第1點就是禁止指令重排列的體現。

記憶體屏障

記憶體屏障四大分類:(Load 代表讀取指令,Store代表寫入指令)

記憶體屏障型別 抽象場景 描述
LoadLoad屏障 Load1; LoadLoad; Load2 在Load2要讀取的資料被訪問前,保證Load1要讀取的資料被讀取完畢。
StoreStore屏障 Store1; StoreStore; Store2 在Store2寫入執行前,保證Store1的寫入操作對其它處理器可見
LoadStore屏障 Load1; LoadStore; Store2 在Store2被寫入前,保證Load1要讀取的資料被讀取完畢。
StoreLoad屏障 Store1; StoreLoad; Load2 在Load2讀取操作執行前,保證Store1的寫入對所有處理器可見。

為了實現volatile的記憶體語義,Java記憶體模型採取以下的保守策略

  • 在每個volatile寫操作的前面插入一個StoreStore屏障。
  • 在每個volatile寫操作的後面插入一個StoreLoad屏障。
  • 在每個volatile讀操作的前面插入一個LoadLoad屏障。
  • 在每個volatile讀操作的後面插入一個LoadStore屏障。

有些小夥伴,可能對這個還是有點疑惑,記憶體屏障這玩意太抽象了。我們照著程式碼看下吧:

記憶體屏障保證前面的指令先執行,所以這就保證了禁止了指令重排啦,同時記憶體屏障保證快取寫入記憶體和其他處理器快取失效,這也就保證了可見性,哈哈~

7.volatile的典型場景

通常來說,使用volatile必須具備以下2個條件:

  • 1)對變數的寫操作不依賴於當前值
  • 2)該變數沒有包含在具有其他變數的不變式中

實際上,volatile場景一般就是「狀態標誌」,以及「DCL單例模式」。

7.1 狀態標誌

深入理解Java虛擬機器,書中的例子:

Map configOptions;
char[] configText;
// 此變數必須定義為 volatile
volatile boolean initialized = false;

// 假設以下程式碼線上程 A 中執行
// 模擬讀取配置資訊, 當讀取完成後將 initialized 設定為 true 以告知其他執行緒配置可用
configOptions = new HashMap();
configText = readConfigFile(fileName);
processConfigOptions(configText, configOptions);
initialized = true;
      
// 假設以下程式碼線上程 B 中執行
// 等待 initialized 為 true, 代表執行緒 A 已經把配置資訊初始化完成
while(!initialized) {
   sleep();
}
// 使用執行緒 A 中初始化好的配置資訊
doSomethingWithConfig();

7.2 DCL單例模式

class Singleton{
    private volatile static Singleton instance = null;
     
    private Singleton() {   
    }
     
    public static Singleton getInstance() {
        if(instance==null) {
            synchronized (Singleton.class) {
                if(instance==null)
                    instance = new Singleton();
            }
        }
        return instance;
    }
}

8. volatile相關經典面試題

  • 談談volatile的特性
  • volatile的記憶體語義
  • 說說併發程式設計的3大特性
  • 什麼是記憶體可見性,什麼是指令重排序?
  • volatile是如何解決java併發中可見性的問題
  • volatile如何防止指令重排
  • volatile可以解決原子性嘛?為什麼?
  • volatile底層的實現機制
  • 相關推薦

    Java程式設計師面試必備Volatile全方位解析

    前言 volatile是Java程式設計師必備的基礎,也是面試官非常喜歡問的一個話題,本文跟大家一起開啟vlatile學習之旅,如果有不正確的地方,也麻煩大家指出哈,一起相互學習~ 1.volatile的用法2.vlatile變數的作用3.現代計算機的記憶體模型(計算機模型,匯流排,MESI協議,嗅探技術)

    java程式設計師面試必備Java 設計模式之單例模式

    有些時候,我們想要一個類在整個系統中僅存在一個例項。比如說,系統給我們提供了一個印表機硬體設施,但是我們在系統中多次new 印表機,創建出多個印表機的例項去完成列印任務,那麼這個時候就會出現資源衝突現象,這就要求我們必須想一個辦法,去確保系統中存在唯一的一個印表機例項,解決方

    Java 程式設計師 面試必備知識

                         前言正文自我介紹Java篇計算機網路作業系統資料庫相關XML常識性知識總結前言準備了接近兩個月的面試筆試,現在終於是可以休息下了。真真是應了那句老話“臺上一分鐘, 臺下十年功。”。人嘛,越努力,才會越幸運。機會總是留給有準備的人的。下面分享一下我的Java實習生準備所

    Java程式設計師經驗分享如何在面試中介紹自己的專案經驗?

    在面試時,經過寒暄後,一般面試官會讓你介紹專案經驗。常見的問法是:“說下你最近的(或最拿得出手的)一個專案”。 可能不少程式設計師對此沒準備,說起來磕磕巴巴,甚至有人說出專案經驗從時間段或技術等方面和簡歷上的不匹配,這樣就會造成如下的後果: 第一印象就不好了,至少會感覺該候選人表述

    #Java程式設計師面試碰到一段程式碼線上等解答!網友看不懂,下一題

    作為一名程式設計師,想要有高深的技術,那麼良好的邏輯思維能力是不可或缺的!很多企業在面試程式設計師的時候,都會出一些面試題來測試面試者,看看他們技術和邏輯能力能不能達到入職的標準,其實這些題不算太難,只要有一些相關的經驗,也是可以答到關鍵點上! 如果有想學習java的程式設計師,可來我們的jav

    高階java程式設計師必備面試知識點

    1.springMVC 2.hibernate 3.mybatis 4.OSGI (面向Java的動態模型系統) 5.dubbo/zookeeper 6.redis/mongodb/memcached  7.資料庫:叢集、鎖、讀寫分離,正規化,索引,sql調優 8.設計模式

    阿里巴巴Java程式設計師面試的11個題目,網友居然一個都不會!

    JAVA程式設計師是不是都以阿里、京東這些大的一線網際網路公司為目標?阿里巴巴java程式設計師

    8年開發java程式設計師教你JAVA開發應該學習什麼?讓你不迷茫

    java入門學習有哪些內容?很多想學習java的學生都不知道怎麼學java,特別是沒有基礎的學生,今天8年開發的老程式設計師,給大家整理了一下,java入門學習有哪些內容: 第一階段 計算機基本原理,Java語言發展簡史,Java開發環境的搭建,體驗Java程式的開發,Java語法格式

    #程式設計師面試能力得到賞識,差點拿到Offer!網友很傻很天真

    俗話說“是金子哪裡都會發光”,在如今飛速發展的網際網路時代,技術更新迭代得非常快,所以在這個行業中,一切都是以技術為尊,技術好代表著你的能力就強,能夠跟上時代的腳步,那麼你在行業中的競爭力就強。 然而近日有一位程式設計師在面試的時候,稱自己的技術得到了HR的賞識,可是還是面試還是沒有通過

    Java程式設計師面試如何超常發揮?

    面試時,你是不是也遇到過這樣的情況,明明感覺自己表現發揮的很好,甚至進入到二面環節,到最後卻沒能拿不到入職offer,連自己“死在”哪塊都不清楚。現實工作中這樣的例子不在少數,究其原因就是面試是對個人素質的綜合考量,專案經驗+基本技術+個人潛力(也就是值不值得培養),這是Java程式設計師成

    Java程式設計師面試寶典(第4版)

    網站 更多書籍點選進入>> CiCi島 下載 電子版僅供預覽及學習交流使用,下載後請24小時內刪除,支援正版,喜歡的請購買正版書籍 電子書下載(皮皮雲盤-點選“普通下載”) 購買正版 封頁 編輯推薦 揭開知名IT企業面試、筆試

    Java程式設計師面試筆試寶典

    網站 更多書籍點選進入>> CiCi島 下載 電子版僅供預覽及學習交流使用,下載後請24小時內刪除,支援正版,喜歡的請購買正版書籍 電子書下載(皮皮雲盤-點選“普通下載”) 購買正版 封頁 編輯推薦 ★在這裡,眾多知名企業面試

    阿里最新的java程式設計師面試題目

    目錄 技術一面(23問) 技術二面(3大塊) 效能優化(21點) 專案實戰(34塊) JAVA方向技術考察點(15點) JAVA開發技術面試中可能問到的問題(17問) 阿里技術面試1 1.Java IO流的層次結構? 2.請說出常用的異

    Java 程式設計師面試技巧

      對於每一個求職者,有一份優秀的簡歷是很必要的,企業通過簡歷的篩選,會給予求職者面試的機會。然而,很多求職者就是在面試過程中與鍾情的工作失之交臂。如何在面試中取得成功呢?“細節決定成敗” ,有很多求職者有很強的專業技術,因為在面試過程中忽略了一些細節,從而失去了一次工作機

    Java程式設計師面試準備

    其實本來真的沒打算寫這篇文章,主要是LZ得記憶力不是很好,不像一些記憶力強的人,面試完以後,幾乎能把自己和麵試官的對話都給記下來。LZ自己當初面試完以後,除了記住一些聊過的知識點以外,具體的內容基本上忘得一乾二淨,所以寫這篇文章其實是很有難度的。 但是,最近問LZ的人實在是

    Java程式設計師面試大綱—錯過了金三銀四,你還要錯過2018嗎

    跳槽時時刻刻都在發生,但是我建議大家跳槽之前,先想清楚為什麼要跳槽。切不可跟風,看到同事一個個都走了,自己也盲目的開始面試起來(期間也沒有準備充分),到底是因為技術原因(影響自己的發展,偏移自己規劃的軌跡),還是錢給少了,不受重視。 準備不充分的面試,完全是浪費時間,更是對

    Java程式設計師面試寶典筆記記錄-第4章Java基礎部分(下)

    導言   本次博文對何昊出版的《java程式設計師面試寶典》的第四章關於Java一部分基礎知識(4.7-4.10)的概括筆記,刪除其中部分程式碼,試題和一部分相對簡單的內容題目。 相關題目 Java

    三年Java程式設計師面試實戰

    出於一些原因近期做了一次工作變動,在職交接近一個半月時間大概面試了十五家公司,並且得到了自己比較滿意的offer,最後基本上無縫銜接了新工作。總體來說,雖然準備的很充分,但面試期間還是暴露了許多問題,所以做下總結,供大家和自己以後參考,主要分四部分講述: 簡歷方面,格式內容

    Java程式設計師面試寶典筆記記錄(終)-第9章海量資料部分筆記

    前言   本次博文對何昊出版的《java程式設計師面試寶典》的第9章海量資料部分的概括筆記,刪除部分內容,是本系列筆記部落格的最後一個博文。 相關知識 Hash法   對映關係,給定資料元素,關鍵字是

    直擊程式設計師面試現場百度面試官都問了我些啥?

    今天小編逛論壇的時候看見一位大牛程式設計師拿到了百度的offer,而現在群裡的小夥伴正好都在到處面試想找一份好點的工作,這位程式設計師也很無私的把他面試的經過以及面試的問題寫出來了,雖然,這些題目確實比較難,對於一個新人來講,很多知識面都是暫時接觸不到,接觸到也很難理解的,但是,小編還是希望能