面試:面經筆記 2017.7

按牛客網討論區筆經面經的發表時間排序。html

 


 

阿里內推,螞蟻金服---java開發工程師第一次電話面試

1.TCP三次握手java

(記住1.過程;2.狀態變化;3.幾個常見問題)linux

第一次:客戶端給服務器發送syn包x;SYN_SENTc++

第二次:服務器接收到syn包,返回一個syn包y 和 一個ack包x+1; SYN_RECV面試

第三次:客戶端收到syn+ack包,向服務器發送ack包。ESTABLISHEDredis

爲何三次握手?算法

防止已失效的鏈接請求報文段重傳。spring

四次揮手?數據庫

把三次握手的第二次分解,先發ack包,再發fin包。express

第一次:主動關閉方發送fin包x,關閉數據傳送; FIN_WAIT1  CLOSE_WAIT

第二次:被動方發送ack包x+1; FIN_WAIT2

第三次:被動方發送fin包y,關閉數據傳送; TIME_WAIT  LASH_ACK

第四次:主動方發送ack包y+1;

爲何四次握手?

被動方收到FIN包時,並不會當即關閉socket,因此先回復一個ack包。等到被動方全部數據發送完,再發fin包。

爲何TIME_WAIT/等待2MSL?

MSL是報文最大生存時間;主動方發出最後一個ACK包進入TIME_WAIT狀態,目的是防止最後一個ACK包對方沒接收到,那麼對方在超時後將重發第三次握手的FIN包。 A->ACK->B,等待ACK到達對方時間MSL,等待FIN超時重傳MSL,因此若是2MSL時間沒有收到FIN,說明對方安全收到FIN。

 

2.在瀏覽器訪問一個網址的過程?

  1.首先瀏覽器經過DNS解析網址的IP地址,經過IP找到服務器路徑;

  2.根據IP地址向服務器發送一個HTTP請求;

  3.服務器收到請求,返回響應;

  4.瀏覽器對網頁解析,渲染顯示。

涉及各層協議?

應用層:HTTP、DNS、(DNS解析域名爲目的IP,經過IP找到服務器路徑,客戶端向服務器發起HTTP會話)

傳輸層:TCP、 (HTTP會話會被分紅報文段,添加源、目的端口;TCP協議進行主要工做)

網際層:IP、(ARP)、ICMP、(爲數據包選擇路由,IP協議進行主要工做)

鏈路層:PPP、(ARP)(發送IP數據包到達服務器的地址,ARP協議將IP地址轉成MAC地址)

 

3.Linux文件的權限;

4.排序算法有哪些?時間複雜度是?

(還須要記住最好最壞時間複雜度、穩定性)

O(n^2):

選擇排序:O(n^2)、O(n^2); 不穩定

冒泡排序:O(n)、O(n^2); 穩定

插入排序:O(n)、O(n^2); 穩定

O(nlogn):

快速排序:O(nlogn)、O(n^2);空間:O(logn) 不穩定

歸併排序:O(nlogn)、O(nlogn);空間:O(n)  穩定

堆排序:O(nlogn)、O(nlogn);空間:O(1) 穩定

 

5.在線編程?

 


 

阿里一面17分鐘

1.==和equals的區別?

(1.基本類型; 2.基本類型封裝;3.String;4.非字符串變量)

equals()是Object類的方法;

(1) 若是是基本類型比較,那麼只能用==來比較,用equals會編譯錯誤,由於不是對象。int a = 3;

(2) 對於基本類型的包裝類型,好比Boolean、Character、Byte、Shot、Integer、Long、Float、Double等的引用變量,==是比較地址的,而equals是比較內容的。Integer n1 = new Integer(30);

(2.5)對於String a = 「a」; Integer b = 1;這種類型的特有對象建立方式,==的時候值是相同的。

(3)對於字符串變量來講,使用「==」和「equals()」方法比較字符串時,其比較方法不一樣。

「==」比較兩個變量自己的值,即兩個對象在內存中的首地址。

「equals()」比較字符串中所包含的內容是否相同。

String s1 = "123"; 
String s2 = "123"; 

String s4 = new String("123"); 
String s5 = new String("123"); 

s1==s2 true;   s1.equals(s2) true;   

s4==s5 false;   s4.equals(s5) true;

s1==s4 false;   s1.equals(s4) true;

s1/s2分別指向字符串常量"123"建立的對象,在常量池裏只有一個對象,內容爲"123";

s4/s5兩個引用對象指向的對象內容相同,可是new操做符建立的,內存中分配兩塊空間給這兩個對象,因此內存地址不一樣。

(4)對於非字符串變量來講,"=="和"equals"方法的做用是相同的都是用來比較其對象在堆內存的首地址,即用來比較兩個引用變量是否指向同一個對象。

 

2.string是否是基本數據類型,

不是,String是類類型,基本類型有八種:

整型4種:byte/short/int/long  字節數:1/2/4/8

字符型1種:char  2

浮點型2種:float/double  4/8

布爾型1種:boolean 1/8

一個字節等於8位,等於256個數,就是-128到127

大寫的B表示Bytes=字節;小寫的b表示bit=位;1byte=8bit;

自動轉換:(小可轉大,大轉小會失去精度)

byte -> short/char -> int -> long -> float -> double

 

3.char能不能存放漢字?

能,一個char字符能夠存儲一箇中文漢字。

 

4.error/exception/runtime exception區別?

Error和Exception都實現了Throwable接口 
Error指的是JVM層面的錯誤,好比內存不足OutOfMemoryError
Exception 指的是代碼邏輯的異常,好比下標越界OutOfIndexException

Exception分爲可查異常CheckedException和運行時異常RuntimeException:

可查異常是必須處理的異常,要麼try catch住,要麼往外拋,誰調用,誰處理,好比 FileNotFoundException、IOException、SQLException等。若是不處理,編譯器就不讓你經過。

運行時異常 又叫作非可查異常,在編譯過程當中,不要求必須進行顯示捕捉。

常見的Runtime Excepiton?

NullPointerException 空指針異常
ArithmeticException 算術異常,好比除數爲零
ClassCastException 類型轉換異常
ConcurrentModificationException 同步修改異常,遍歷一個集合的時候,刪除集合的元素,就會拋出該異常 
IndexOutOfBoundsException 數組下標越界異常
NegativeArraySizeException 爲數組分配的空間是負數異常

爲何分兩種異常?

Java之因此會設計運行時異常的緣由之一,是由於下標越界,空指針這些運行時異常太過於廣泛,若是都須要進行捕捉,代碼的可讀性就會變得很糟糕。

 

5.object類的方法?

9種;(簡要介紹各方法)

  1.對象的複製/獲取/String/釋放:clone/getClass/toString/finalize;

  2.hash:equals/hashCode;

  3.多線程:wait/notify/notifyAll

clone:實現對象的淺複製;

getClass:得到運行時類對象;

finalize:用於釋放資源;

equals:比較對象是否相等;基本類型不能夠用equals,對於String類型「equals」和「==」做用不一樣;

hashcode:用於hash尋找;

wait:使當前線程等待該對象的鎖,當前線程必須是該對象的擁有者,也就是具備該對象的鎖;wait()方法一直等待,直到得到鎖或者被中斷。wait(longtimeout)設定一個超時間隔,若是在規定時間內沒有得到鎖就返回。

調用該方法後當前線程進入睡眠狀態,直到如下事件發生:

(1)其餘線程調用了該對象的notify方法。

(2)其餘線程調用了該對象的notifyAll方法。

(3)其餘線程調用了interrupt中斷該線程。

(4)時間間隔到了。

此時該線程就能夠被調度了,若是是被中斷的話就拋出一個InterruptedException異常。

notify:喚醒在該對象上等待的某個線程

6.jvm垃圾回收

7.linux查看日誌文件的方式?

 


 

螞蟻金服Java面經

1.Java都學了些什麼?
答:集合、IO、多線程、框架等等

2.說說多線程
答:說了一下多線程的實現,同步,優化

(tips:對於大範圍的內容要整理出目錄,否則會很亂。)

進程和線程的區別 感受有點偏題就不寫了

多線程的實現?

三種方法:1.繼承Thread類;2.實現Runnable接口;3.使用Executor建立線程池;

多線程的同步?

(1)同步方法:synchronized修飾的方法;

(2)同步代碼塊:同步是一種高開銷的操做,所以應該儘可能減小同步的內容。一般沒有必要同步整個方法,使用synchronized代碼塊同步關鍵代碼便可。

  同步方法和同步代碼塊的區別是什麼?

  答:同步方法默認用this或者當前類class對象做爲鎖; 同步代碼塊能夠選擇以什麼來加鎖,比同步方法要更細顆粒度,咱們能夠選擇只同步會發生同步問題的部分代碼而不是整個方法。

(3)使用volatile實現同步:每次線程要訪問volatile修飾的變量時都是從內存中讀取,而不是從緩存當中讀取,所以每一個線程訪問到的變量值都是同樣的。這樣就保證了同步。

(4)使用重入鎖實現線程同步:ReentrantLock是concurrent包的類;經常使用方法有lock()和unlock();能夠建立公平鎖;支持非阻塞的tryLock(可超時);須要手動釋放鎖。

(5)使用ThreadLocal實現線程同步:每一個線程都建立一個變量副本,修改副本不會影響其餘線程的副本。ThreadLocal並不能替代同步機制,二者面向的問題領域不一樣。同步機制是爲了同步多個線程對相同資源的併發訪問,是爲了多個線程之間進行通訊的有效方式;而ThreadLocal是隔離多個線程的數據共享,從根本上就不在多個線程之間共享資源(變量)。

多線程的優化?

影響多線程性能的問題:死鎖、過多串行化、過多鎖競爭等;

預防和處理死鎖的方法:

  1)儘可能不要在釋放鎖以前競爭其餘鎖;通常能夠經過細化同步方法來實現;

  2)順序索取鎖資源;

  3)嘗試定時鎖tryLock();

下降鎖競爭方法:

  1)縮小鎖的範圍,減少鎖的粒度;

  2)使用讀寫分離鎖ReadWriteLock來替換獨佔鎖:來實現讀-讀併發,讀-寫串行,寫-寫串行的特性。這種方式更進一步提升了可併發性,由於有些場景大部分是讀操做,所以不必串行工做。


3.說一下線程池,線程池裏面的線程的狀態有哪些?

線程池:

(1.建立;2.參數;)

線程池的頂級接口是Executor,是執行線程的工具;真正的線程池接口是ExecutorService。ThreadPoolExecutor是ExecutorService的默認實現。

ThreadPoolExecutor的參數有:

corePoolSize - 池中所保存的線程數,包括空閒線程。

maximumPoolSize-池中容許的最大線程數。

keepAliveTime - 當線程數大於核心時,此爲終止前多餘的空閒線程等待新任務的最長時間。

unit - keepAliveTime 參數的時間單位。

workQueue - 執行前用於保持任務的隊列。此隊列僅保持由 execute方法提交的 Runnable任務。

threadFactory - 執行程序建立新線程時使用的工廠。

handler - 因爲超出線程範圍和隊列容量而使執行被阻塞時所使用的處理程序。

線程的狀態:(把那張圖將熟悉)

包括New、Runnable、Running、Blocked、Dead狀態;

1)New:Thread t = new Thread();

2)Runnable:t.start()後進入Runnable狀態;位於可運行線程池中,等待被線程調度選中,得到CPU使用權;

3)Running:Runnable狀態的線程得到了cpu時間片;

4)Blocked:三種狀況;

  1.等待阻塞:o.wait(),釋放鎖;進入等待隊列;o.notify()/notifyAll() 進入鎖池;

  2.同步阻塞:同步鎖被別的線程佔用;進入鎖池;

  3.其餘阻塞:1)Thread.sleep();2)t2.join();3)等待用戶輸入(發出I/O請求);不會釋放鎖;當sleep時間結束,t2線程結束,I/O處理完成後進入Runnable狀態;

5)Dead:run()/main()執行結束 或者 異常退出;線程結束生命週期。

 

4.數據結構學了些什麼?

數組、HashMap、棧、隊列、鏈表、樹;(HashMap也算?)

(把方向引向本身擅長的部分)

 

5.Hashmap和Hashtable的區別?

相同點:都實現了Map接口;

不一樣點-兩個方面:null值,同步;

HashMap容許鍵和值是null,HashTable不容許;

HashTable是同步的,HashMap不是;

 

6.Hashmap的數據結構,Hash的具體實現(這塊答得很差)

(講HashMap:1.結構+原理;2.其餘參數-容量、負荷係數、閾值;)

  1)HashMap是有數組+鏈表組成,Entry數組是HashMap的主體,鏈表是爲了解決Hash衝突;

  2)HashMap的Entry數組的元素能夠看做是一個個散列桶,每一個桶是一個單鏈表;每一個Entry內部類有四個字段:key/value/hash/next;

  3)執行put時,根據key的hashcode定位到桶;遍歷單鏈表,利用key.equals()檢查key是否存在;若是存在則覆蓋;不然新建Entry放在頭部;

  4)執行get時,根據key的hashcode定位到桶;遍歷單鏈表,利用key.equals()獲取對應的Entry,返回它的value;

  5)參數:容量capacity(默認16)、負載係數loadFactor(默認0.75)、閾值threshold=容量*負載係數。數組容量capacity必須是2的n次方,當鍵值對個數>threshold(12)時,擴容:將數組擴容爲原來容量的二倍。

幾點補充:

  1)根據hashcode定位桶步驟:

int hash = hash(key.hashCode());     //計算key.hashcode()的hash值,hash函數由hashmap本身實現
int i = indexFor(hash, table.length);//獲取將要存放的數組下標

 也就是首先計算key的hashcode(),再對該值map的自定義hash()(將hash值打散,使插入的Entry落在不一樣的桶上,提升查詢效率),再根據獲得的hash值調用indexFor()方法;indexFor(h,length)方法:將hash值與entry數組的長度-1按位與;

    /**
     * "按位與"來獲取數組下標
     */
    static int indexFor(int h, int length) {
        return h & (length - 1);
    }

  2)爲何保持Entry數組大小2的n次方?

當length老是2的n次方時,h& (length-1)運算等價於對length取餘,也就是h%length,可是&比%具備更高的效率。

參考:HashMap源碼

 

7.設計模式有了解嗎?
答:談了一下單例模式、工廠模式、代理模式,順便說了一下Spring的AOP是基於代理模式的,能夠實現日誌記錄等功能。

代理模式

 

8.數據庫事務你瞭解嗎?髒讀是什麼,幻讀是什麼?

(說一下事務的四個特性+四個衝突+四個隔離級別) 

 


 

阿里內推一面,已跪

[阿里] [c++]

1.講一下Linux下如何將源文件逐步編譯成目標文件的過程 

2.你簡歷上寫熟悉TCP/IP協議,那你說一下TCP的報頭吧。

/*TCP頭定義,共20個字節*/
typedef struct _TCP_HEADER 
{
 short m_sSourPort;              // 源端口號16bit
 short m_sDestPort;              // 目的端口號16bit


 unsigned int m_uiSequNum;         // 序列號32bit
 unsigned int m_uiAcknowledgeNum;  // 確認號32bit


 short m_sHeaderLenAndFlag;        // 前4位:TCP頭長度;中6位:保留;後6位:標誌位
 short m_sWindowSize;            // 窗口大小16bit


 short m_sCheckSum;              // 檢驗和16bit
 short m_surgentPointer;           // 緊急數據偏移量16bit
}__attribute__((packed))TCP_HEADER, *PTCP_HEADER;

參考:IP頭、TCP頭、UDP頭

 

3. 你簡歷上寫的掌握經常使用的數據結構和排序算法,那你說一個你熟悉的排序算法吧,冒泡就不用說了 。(注:原理+複雜度+手寫代碼)

排序主要用這六種:

O(n^2)的有:冒泡排序、插入排序、選擇排序;

O(nlogn)的有:快排、歸併排序、堆排序;

冒泡排序:原理是無序區兩兩比較,每趟獲得一個最大的放在無序區最後;

  算法:外循環是趟數[0,n-1), 內循環是無序區個數[0, n-i-1);循環體是比較[j]和[j+1];

插入排序:是把數組分紅有序區和無序區兩部分,每次從無序區取出一位做爲tar值,從後向前遍歷有序區,大於tar則後移,最後放到目標位置;

  算法:外循環是無序區長度[1,n);定義a[i]爲tar值;內循環j指向i,比較a[j-1]與tar,大於則日後順移a[j-1];最後a[j]賦值;

選擇排序:也是分爲有序區和無序區,每次從無序區選擇一位最小的放到有序區末尾;

  算法:外循環是趟數[0,n-1), 內循環是無序區個數[i+1,n);循環體是比較[i]和[j];

快排:每次排序肯定一個數的位置,比該數小的移到左邊,大的移到右邊。一趟快排的算法是:

  • 設置兩個首尾指針lo、hi;
  • 以第一個元素做爲key值;
  • 從hi向前搜索,若是大於key則hi--,小於key則[lo]=[hi]把[hi]移到前面;
  • 從lo向後搜搜,若是小於key則lo++,大於key則[hi]=[lo]把[lo]移到後面;
  • 重複三、4步驟,直到lo=hi;返回lo位置。

上述過程就是partition函數;以partition函數返回的位置,對左右兩邊遞歸。

  算法:(如上)partition(a,lo,hi)函數:定義key,while循環(lo<hi),內部(lo<hi && a[hi]>=key);最後a[lo]賦值,返回lo; sort(a,lo,hi)函數:判斷(lo<hi),index,遞歸;

歸併排序:將數組分紅若干個小數組,將已有序的數組兩兩歸併獲得徹底有序數組。每趟歸併的算法是:

  • 申請空間tmp[],大小是兩個已排數組的和,[hi-lo+1];
  • 設定兩個指針,分別指向兩個已排數組的起始位置;
  • 比較兩個指針元素的值,選擇小的元素放到tmp[]裏,並移動指針;
  • 重複步驟3,直到某一指針到數組尾;
  • 將另外一序列剩下的全部元素複製到tmp[]裏;
  • 將tmp[]數組覆蓋原num[]數組;

  算法:merge(a,lo,mid,hi)方法:tmp[]數組,左右指針+臨時指針,比較兩數組小的保存,保存剩餘數組,賦值數組;mergeSort(a,lo,hi) mid, if()判斷:左右遞歸,merge();注意左右遞歸必定是左邊(lo,mid),右邊(mid+1, hi);由於mid偏左,否則會死循環。

堆排序:堆排序包括兩個過程,首先是根據元素建堆,時間複雜度O(n),而後將堆的根節點取出(與最後一個節點交換),將前面N-1個節點進行堆調整。直至全部節點都取出。堆調整時間複雜是O(lgn),調用了n-1次,因此堆排序時間複雜度是O(nlgn);

  • 建堆:建堆是不斷調整堆的過程;從len/2出開始調整(最後一個父節點)。最後一層父節點最多下調1次,倒數第二層最多下調2次,頂點最多下調H=logN次。而最後一層父節點共有2^(H-1)個,倒數第二層公有2^(H-2),頂點只有1(2^0)個,因此總共的時間複雜度爲s = 1 * 2^(H-1) + 2 * 2^(H-2) + ... + (H-1) * 2^1 + H * 2^0。將H代入後s= 2N - 2 - log2(N),近似的時間複雜度就是O(N)。
  • 調整堆:思想是比較節點i和它的孩子節點left(i),right(i),若i不是最大則調換。

 


  

螞蟻金服java工程師面經 

 
1 自我介紹
2 介紹項目,在項目中圖片存儲在公有云上加密問題,項目中爲何用redis以及怎麼實現相關功能的
 
 
3 說說你學java都學了哪些內容
基礎的:面向對象、操做符、控制流程(條件判斷、循環語句)、數組、類和對象、接口與繼承等;
中級的:異常處理、集合框架、多線程等;
J2EE的:Servlet、JSP等;
框架:Spring、Spring MVC、MyBatis、Spring Boot、Spring Data JPA;
 
 
 
4 項目中用過的開源框架,爲何要用springboot 和 hibernate
 
 
5 spring的核心功能是什麼,介紹一下 AOP以及怎麼實現的,jdk代理和cglib代理的區別
 
核心功能是IoC反轉控制和AOP面向切面編程;
AOP(Aspect-OrientedProgramming,面向方面編程), 能夠說是OOP(Object-Oriented Programing,面向對象編程)的 補充和完善。OOP引入封裝、繼承和多態性等概念來創建一種對象層次結構,用以模擬公共行爲的一個集合 。當咱們須要爲分散的對象引入公共行爲的時候,OOP則顯得無能爲力。也就是說,OOP容許你定義從上到下的關係,但並不適合定義從左到右的關係。例如日誌功能。日誌代碼每每水平地散佈在全部對象層次中,而與它所散佈到的對象的核心功能毫無關係。對於其餘類型的代碼,如安全性、異常處理和透明的持續性也是如此。這種散佈在各處的無關的代碼被稱爲橫切(cross-cutting)代碼,在OOP設計中,它致使了大量代碼的重複,而不利於各個模塊的重用。
而AOP技術則偏偏相反,它利用一種稱爲「橫切」的技術,剖解開封裝的對象內部,並將那些影響了多個類的公共行爲封裝到一個可重用模塊,並將其名爲「Aspect」,即方面。所謂「方面」,簡單地說,就是將那些與業務無關,卻爲業務模塊所共同調用的邏輯或責任封裝起來,便於減小系統的重複代碼,下降模塊間的耦合度,並有利於將來的可操做性和可維護性。
實現AOP的技術,主要分爲兩大類:一是採用動態代理技術,利用截取消息的方式,對該消息進行裝飾,以取代原有對象行爲的執行;二是採用靜態織入的方式,引入特定的語法建立「方面」,從而使得編譯器能夠在編譯期間織入有關「方面」的代碼。
JDK動態代理和CGLIB字節碼生成的區別?
 * JDK動態代理只能對實現了接口的類生成代理,而不能針對類
 * CGLIB是針對類實現代理,主要是對指定的類生成一個子類,覆蓋其中的方法。
參考: AOP原理(好,讀!)、 JDK與CGLib
 
 
6 數據庫的四大特性, 事務的隔離級別,幻讀。
 
四大特性是:ACID 原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、持久性(Durability)+介紹四個特性概念;
事務隔離級別:讀未提交(Read uncommitted)、讀已提交(Read committed)、可重複讀(Repeatable read)和串行化(Serializable)+介紹;
四大沖突問題:髒讀、不可重複讀、幻讀、更新丟失;
 
 
7 計算機網絡都學了什麼(相似說書上的目錄), OSI七層每層的任務,數據鏈路層的功能(答得不全)和協議。
 
包括:OSI參考模型以及各層的學習、TCP/IP協議、HTTP這些;
OSI七層自底向上是:物理層、數據鏈路層、網絡層、傳輸層、會話層、表示層、應用層;
各層功能和協議:
物理層:經過媒介傳輸比特,肯定機械及電氣規範(比特Bit)
數據鏈路層:將比特組裝成幀和點到點的傳遞( 幀Frame) PPP點對點協議、ARP地址解析協議;
網絡層:負責數據包從源到宿的傳遞和網際互連( 包Packet) IP、ICMP、RARP、RIP
傳輸層:提供端到端的可靠報文傳遞和錯誤恢復( 段Segment) TCP、UDP
會話層:創建、管理和終止會話(會話協議數據單元SPDU)
表示層:對數據進行翻譯、加密和壓縮(表示協議數據單元PPDU)
應用層:容許訪問OSI環境的手段(應用協議數據單元APDU)FTP、DNS、HTTP
(注:ARP在OSI裏是鏈路層,在TCP/IP裏是網絡層)
 
 
8 數據結構都學了什麼, 排序算法最快的是哪一種說說原理,哪些是不用申請額外空間的
數組、鏈表、隊列、棧、樹;
 
9 樹的非遞歸遍歷以及三種遍歷知道哪兩種不能肯定一棵樹
中序前序後序,非遞歸使用Stack棧來實現;
中序:向左一直遍歷而且放入stack裏,直到最左邊,pop、add和遍歷右邊;
前序:先放入root,pop,而後依次放入右邊和左邊的;
後序:前序的次序變換一下,而且用llist.add(0,val);
 
10 介紹一下 二叉平衡樹
二叉平衡樹就是兩個子樹的深度差不超過1;
判斷二叉平衡樹的算法實現:
自頂向下:depth求深度,要求兩個字數深刻差不超過1而且兩個字數均爲平衡樹;
自底向上:不平衡的子樹用-1標註;
 
11 是否看過jdk 源碼,說說你說看過的
集合框架的HashMap、Concurrent下的ConHashMap、Executor等;
(todo)
 
12 說說 concurrent包下的類,而後問了一下Reentrantlock.
Concurrent包下的類包括:
併發集合類:ConcurrentHashMap、CopyOnWriteArrayList、CopyOnWriteArraySet、ArrayBlockingQueue、LinkedBlockingQueue;
原子類:AtomicInteger
線程池:ThreadPoolExecutor、Executor;
鎖:ReentrantLock、ReentrantReadWriteLock;
(重點準備!)
 
13 之後的職業規劃
 

 

人生第一次技術面試 螞蟻金服 

 

1.ArrayList和LinkedList的區別

三個方面:1.實現;2.查詢、增刪;3.內存;

 

2.知道樂觀鎖,悲觀鎖麼?什麼狀況下用樂觀什麼狀況下用悲觀麼?

樂觀鎖:默認讀數據的時候不會修改,因此不會上鎖;

悲觀鎖:默認讀數據的時候會修改,因此會上鎖;

樂觀鎖適用於多讀寫比較少的狀況,省去鎖的開銷,加大系統的吞吐量。

 

3.volatile關鍵字的做用?i++是原子性的麼?

  在當前的Java內存模型下,線程能夠把變量保存在本地內存(好比機器的寄存器)中,而不是直接在主存中進行讀寫。這就可能形成一個線程在主存中修改了一個變量的值,而另一個線程還繼續使用它在寄存器中的變量值的拷貝,形成數據的不一致。 

  要解決這個問題,只須要像在本程序中的這樣,把該變量聲明爲volatile(不穩定的)便可,這就指示JVM,這個變量是不穩定的,每次使用它都到主存中進行讀取。通常說來,多任務環境下各任務間共享的標誌都應該加volatile修飾。 

  Volatile修飾的成員變量在每次被線程訪問時,都強迫從共享內存中重讀該成員變量的值。並且,當成員變量發生變化時,強迫線程將變化值回寫到共享內存。這樣在任什麼時候刻,兩個不一樣的線程老是看到某個成員變量的同一個值。 

  使用volatile關鍵字修飾變量,線程要訪問變量時都是從內存中讀取,而不是從緩存當中讀取,所以每一個線程訪問到的變量值都是同樣的。

  i++不是原子操做,分爲三個階段:內存到寄存器、寄存器自增、寫會內存;這三個階段中間均可以被中斷分離開.

 

4.Java內存模型?爲何設置工做內存和主內存?

PS:JVM內存模型和JMM(Java內存模型)沒有關係。JMM的目的是爲了解決Java多線程對共享數據的讀寫一致性問題。

 
全部線程共享主內存
每一個線程有本身的工做內存
refreshing local memory to/from main memory must  comply to JMM rules
 
每一個線程都有本身的執行空間(即工做內存),線程執行的時候用到某變量,首先要將變量從主內存拷貝的本身的工做內存空間,而後對變量進行操做:讀取,修改,賦值等,這些均在工做內存完成,操做完成後再將變量寫回主內存;
 
工做內存可類比高速緩存,爲了得到更好的執行性能。
 
參考: 線程內存模型
 
5. GC的過程。
對象根據被存活的時間被分爲:年輕代、年老代、永久代;
年輕代:對象被建立時,內存分配首先發生在年輕代,年輕代分爲三個區域:Eden區、S0、S1;
建立時分配在Eden去,滿的時候執行Minor GC,消亡的對象清理,剩餘的複製到S0;Eden再滿時,Minor GC,存活的複製到S1,將S0消亡的清除,能夠晉級的到Old,存的的到S1。切換屢次,仍然存活的複製到老年代。
年老代:內存不足時執行Full GC,標記整理。
 
6. GC時會對程序有什麼影響?當發現虛擬機頻繁GC時應該怎麼辦?
"stop-the-world" 機制簡稱STW,即,在執行垃圾收集算法時,Java應用程序的其餘全部除了垃圾收集器線程以外的線程都被掛起。
頻繁GC:須要調優,好比控制新生代老年代比例,控制進入老年代前生存次數,控制年輕代eden和survivor比例(默認8:1)等;
 
7.Java8有什麼新特性,知道 lambda表達式麼?

1.Lambda表達式的形式化表示以下所示

Parameters -> an expression 

2.若是Lambda表達式中要執行多個語句塊,須要將多個語句塊以{}進行包裝,若是有返回值,須要顯示指定return語句,以下所示:

Parameters -> {expressions;};

3.若是Lambda表達式不須要參數,可使用一個空括號表示,以下示例所示

() -> {for (int i = 0; i < 1000; i++) doSomething();};

5.若是Lambda表達式只有一個參數,而且參數的類型是能夠由編譯器推斷出來的,則能夠以下所示使用Lambda表達式,便可以省略參數的類型及括號

Stream.of(datas).forEach(param -> {System.out.println(param.length());});

參考:lambda表達式 

 

9.設計模式知道麼?

單例模式、工廠模式、觀察者模式;

單例模式:

1.特色:

  • 只能有一個實例;
  • 必須本身建立本身的惟一實例;
  • 必須給其餘對象提供這一實例;

2.單例模式有兩種寫法:餓漢式和懶漢式;餓漢式是一旦類加載了,就把單例初始化完成;而懶漢式只有在調用getInstance的時候,才初始化這個單例。

3.懶漢式單例:

a.寫代碼(構造方法,建立實例,get);

b.非線程安全;

c.三種線程安全的代碼+優缺點

  syn:每次獲取都須要同步,影響性能;

  雙重檢查:判空後鎖住類;爲何要第二次檢查?建立實例的操做非原子化;在getInstance中作了兩次null檢查,確保了只有第一次調用單例的時候纔會作同步,這樣也是線程安全的,同時避免了每次都同步的性能損耗;

  靜態內部類:LazyHolder;利用了classloader的機制來保證初始化instance時只有一個線程,因此也是線程安全的,同時沒有性能損耗;

4.餓漢式單例:線程安全;在類建立的同事就實例化一個靜態對象出來。

工廠模式:

見印象筆記/設計模式;工廠方法模式和抽象工廠模式區別;

觀察者模式:

角色:抽象觀察者-update、具體觀察者、抽象被觀察者-attach/detach/notify、具體被觀察者;

使用場景:一個對象狀態更新,其餘對象同步更新,只須要將本身更新通知給其餘對象而不須要知道其餘對象細節。解耦,各自變換互不影響。

 

10.項目難點?

相關文章
相關標籤/搜索