螞蟻金服面試題及答案-總結

前言
相信有人在網上看到過一樣的題,這裏我也是從某篇公衆號把題抄下來,答案都是筆者自己在網上搜的,適合即時回答,所以很多知識沒有引入太深。

題目出自:http://www.54tianzhisheng.cn/2018/07/30/alipay01/, http://www.54tianzhisheng.cn/2018/07/31/alipay02/

一面
1、自我介紹、自己做的項目和技術領域

開放題

2、項目中的監控:那個監控指標常見的有哪些?

答:CPU、內存、IO 等等。建議下載個nmon工具,裏面有各個指標。

數據庫:Mysql(緩存命中、索引、單條SQL性能、數據庫線程數、數據池連接數)

中間件:1.消息2、負載均衡3、緩存(包括線程數、連接數、日誌)。

網絡: 吞吐量、吞吐率

應用: jvm內存、日誌、Full GC頻率

3、微服務涉及到的技術以及需要注意的問題有哪些?

4、註冊中心你瞭解了哪些?

答:Consul 、Eureka、ZooKeeper

5、consul 的可靠性你瞭解嗎?

6、consul 的機制你有沒有具體深入過?有沒有和其他的註冊中心對比過?

7、項目用 Spring 比較多,有沒有了解 Spring 的原理?AOP 和 IOC 的原理

答:(1). IoC(Inversion of Control)是指容器控制程序對象之間的關係,而不是傳統實現中,由程序代碼直接操控。控制權由應用代碼中轉到了外部容器,控制權的轉移是所謂反轉。 對於Spring而言,就是由Spring來控制對象的生命週期和對象之間的關係;IoC還有另外一個名字——“依賴注入(Dependency Injection)”。從名字上理解,所謂依賴注入,即組件之間的依賴關係由容器在運行期決定,即由容器動態地將某種依賴關係注入到組件之中。  

(2). 在Spring的工作方式中,所有的類都會在spring容器中登記,告訴spring這是個什麼東西,你需要什麼東西,然後spring會在系統運行到適當的時候,把你要的東西主動給你,同時也把你交給其他需要你的東西。所有的類的創建、銷燬都由 spring來控制,也就是說控制對象生存週期的不再是引用它的對象,而是spring。對於某個具體的對象而言,以前是它控制其他對象,現在是所有對象都被spring控制,所以這叫控制反轉。

(3). 在系統運行中,動態的向某個對象提供它所需要的其他對象。  

(4). 依賴注入的思想是通過反射機制實現的,在實例化一個類時,它通過反射調用類中set方法將事先保存在HashMap中的類屬性注入到類中。 總而言之,在傳統的對象創建方式中,通常由調用者來創建被調用者的實例,而在Spring中創建被調用者的工作由Spring來完成,然後注入調用者,即所謂的依賴注入or控制反轉。 注入方式有兩種:依賴注入和設置注入; IoC的優點:降低了組件之間的耦合,降低了業務對象之間替換的複雜性,使之能夠靈活的管理對象。

AOP(Aspect Oriented Programming)

(1). AOP面向方面編程基於IoC,是對OOP的有益補充;

(2). AOP利用一種稱爲“橫切”的技術,剖解開封裝的對象內部,並將那些影響了 多個類的公共行爲封裝到一個可重用模塊,並將其名爲“Aspect”,即方面。所謂“方面”,簡單地說,就是將那些與業務無關,卻爲業務模塊所共同調用的 邏輯或責任封裝起來,比如日誌記錄,便於減少系統的重複代碼,降低模塊間的耦合度,並有利於未來的可操作性和可維護性。

(3). AOP代表的是一個橫向的關 系,將“對象”比作一個空心的圓柱體,其中封裝的是對象的屬性和行爲;則面向方面編程的方法,就是將這個圓柱體以切面形式剖開,選擇性的提供業務邏輯。而 剖開的切面,也就是所謂的“方面”了。然後它又以巧奪天功的妙手將這些剖開的切面復原,不留痕跡,但完成了效果。

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

(5). Spring實現AOP:JDK動態代理和CGLIB代理 JDK動態代理:其代理對象必須是某個接口的實現,它是通過在運行期間創建一個接口的實現類來完成對目標對象的代理;其核心的兩個類是InvocationHandler和Proxy。 CGLIB代理:實現原理類似於JDK動態代理,只是它在運行期間生成的代理對象是針對目標類擴展的子類。CGLIB是高效的代碼生成包,底層是依靠ASM(開源的java字節碼編輯類庫)操作字節碼實現的,性能比JDK強;需要引入包asm.jar和cglib.jar。     使用AspectJ注入式切面和@AspectJ註解驅動的切面實際上底層也是通過動態代理實現的。

(6). AOP使用場景:                     

Authentication 權限檢查        

Caching 緩存        

Context passing 內容傳遞        

Error handling 錯誤處理        

Lazy loading 延遲加載        

Debugging  調試      

logging, tracing, profiling and monitoring 日誌記錄,跟蹤,優化,校準        

Performance optimization 性能優化,效率檢查        

Persistence  持久化        

Resource pooling 資源池        

Synchronization 同步        

Transactions 事務管理    

另外Filter的實現和struts2的攔截器的實現都是AOP思想的體現。

8、Spring Boot除了自動配置,相比傳統的 Spring 有什麼其他的區別?

爲Spring 生態系統的開發提供一種更簡潔的方式,提供了很多非功能性特性,例如:嵌入式 Server,Security,統計,健康檢查,外部配置等等,主要體現在以下幾點:

1.Spring Boot可以建立獨立的Spring應用程序;

2.內嵌瞭如Tomcat,Jetty和Undertow這樣的容器,也就是說可以直接跑起來,用不着再做部署工作了;

3.無需再像Spring那樣搞一堆繁瑣的xml文件的配置;

4.可以自動配置Spring。SpringBoot將原有的XML配置改爲Java配置,將bean注入改爲使用註解注入的方式(@Autowire),並將多個xml、properties配置濃縮在一個appliaction.yml配置文件中。

5.提供了一些現有的功能,如量度工具,表單數據驗證以及一些外部配置這樣的一些第三方功能;

6.整合常用依賴(開發庫,例如spring-webmvc、jackson-json、validation-api和tomcat等),提供的POM可以簡化Maven的配置。當我們引入核心依賴時,SpringBoot會自引入其他依賴。

9、Spring Cloud 有了解多少?

10、Spring Bean 的生命週期

一個Bean從創建到銷燬,如果是用BeanFactory來生成,管理Bean的話

Spring上下文中的Bean也類似,如下

    1、實例化一個Bean--也就是我們常說的new;

    2、按照Spring上下文對實例化的Bean進行配置--也就是IOC注入;

    3、如果這個Bean已經實現了BeanNameAware接口,會調用它實現的setBeanName(String)方法,此處傳遞的就是Spring配置文件中Bean的id值

    4、如果這個Bean已經實現了BeanFactoryAware接口,會調用它實現的setBeanFactory(setBeanFactory(BeanFactory)傳遞的是Spring工廠自身(可以用這個方式來獲取其它Bean,只需在Spring配置文件中配置一個普通的Bean就可以);

    5、如果這個Bean已經實現了ApplicationContextAware接口,會調用setApplicationContext(ApplicationContext)方法,傳入Spring上下文(同樣這個方式也可以實現步驟4的內容,但比4更好,因爲ApplicationContext是BeanFactory的子接口,有更多的實現方法);

    6、如果這個Bean關聯了BeanPostProcessor接口,將會調用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor經常被用作是Bean內容的更改,並且由於這個是在Bean初始化結束時調用那個的方法,也可以被應用於內存或緩存技術;

    7、如果Bean在Spring配置文件中配置了init-method屬性會自動調用其配置的初始化方法。

    8、如果這個Bean關聯了BeanPostProcessor接口,將會調用postProcessAfterInitialization(Object obj, String s)方法、;

    注:以上工作完成以後就可以應用這個Bean了,那這個Bean是一個Singleton的,所以一般情況下我們調用同一個id的Bean會是在內容地址相同的實例,當然在Spring配置文件中也可以配置非Singleton,這裏我們不做贅述。

    9、當Bean不再需要時,會經過清理階段,如果Bean實現了DisposableBean這個接口,會調用那個其實現的destroy()方法;

    10、最後,如果這個Bean的Spring配置中配置了destroy-method屬性,會自動調用其配置的銷燬方法。

另外我們這裏描述的是應用Spring上下文Bean的生命週期,如果應用Spring的工廠也就是BeanFactory的話去掉第5步就Ok了

11、HashMap 和 hashTable 區別?

區別:Hashtable是線程安全的,效率比較低

Hashtable既不支持Null key也不支持Null value。Hashtable的put()方法的註釋中有說明

Hashtable默認的初始大小爲11,之後每次擴充,容量變爲原來的2n+1。

HashMap默認的初始化大小爲16。之後每次擴充,容量變爲原來的2倍

Hashtable在計算元素的位置時需要進行一次除法運算,而除法運算是比較耗時的

HashMap爲了提高計算效率,將哈希表的大小固定爲了2的冪,這樣在取模預算時,不需要做除法,只需要做位運算。位運算比除法的效率要高很多。

HashMap是繼承自AbstractMap類,而HashTable是繼承自Dictionary類。不過它們都實現了同時實現了map、Cloneable(可複製)、Serializable(可序列化)這三個接口

12、Object 的 hashcode 方法重寫了,equals 方法要不要改?

不需要,Ojbect類中有兩個方法equals、hashCode,這兩個方法都是用來比較兩個對象是否相等的,如果兩個對象相等(equal),那麼必須擁有相同 的哈希碼(hash code)

即使兩個對象有相同的哈希值(hash code),他們不一定相等

重寫equals()方法就必須重寫hashCode(),但重寫hashcode方法不一定要重寫equals方法

13、Hashmap 線程不安全的出現場景

用ConcurrentHashMap 線程安全

多線程處理時hashmap線程不安全

首先hashmap裏這個size沒有用volatile關鍵字修飾,代表這不是一個內存可見的變量,線程操作數據的時候一般是從主存拷貝一個變量副本進行操作,操作完成過後在把size的值寫回到主存size的

線程不安全問題應該屬於併發問題之一的,屬於相對高級的問題了。這個時候的問題已經不僅僅侷限於代碼層面了,很多時候需要結合JVM一起分析了

14、線上服務 CPU 很高該怎麼做?有哪些措施可以找到問題

定位出現問題的堆棧信息排查具體問題

1、top命令:Linux命令。可以查看實時的CPU使用情況。也可以查看最近一段時間的CPU使用情況。

2、ps命令: Linux命令。強大的進程狀態監控命令。可以查看進程以及進程中線程的當前CPU使用情況。屬於當前狀態的採樣數據。

3、jstack:  Java提供的命令。可以查看某個進程的當前線程棧運行情況。根據這個命令的輸出可以定位某個進程的所有線程的當前運行狀態、運行代碼,以及是否死鎖等等。

4、pstack:Linux命令。可以查看某個進程的當前線程棧運行情況

 15、JDK 中有哪幾個線程池?順帶把線程池講了個遍

JUC提供了調度器對象Executors來創建線程池,可創建的線程池有四種

1、newFixedThreadPool創建一個指定工作線程數量的線程池。每當提交一個任務就創建一個工作線程,如果工作線程數量達到線程池初始的最大數,則將提交的任務存入到池隊列中。

2、newCachedThreadPool創建一個可緩存的線程池。這種類型的線程池特點是:

1).工作線程的創建數量幾乎沒有限制(其實也有限制的,數目爲Interger. MAX_VALUE), 這樣可靈活的往線程池中添加線程。

2).如果長時間沒有往線程池中提交任務,即如果工作線程空閒了指定的時間(默認爲1分鐘),則該工作線程將自動終止。終止後,如果你又提交了新的任務,則線程池重新創建一個工作線程。

3、newSingleThreadExecutor創建一個單線程化的Executor,即只創建唯一的工作者線程來執行任務,如果這個線程異常結束,會有另一個取代它,保證順序執行(我覺得這點是它的特色)。單工作線程最大的特點是可保證順序地執行各個任務,並且在任意給定的時間不會有多個線程是活動的 。

4、newScheduleThreadPool創建一個定長的線程池,而且支持定時的以及週期性的任務執行,類似於Timer。(這種線程池原理暫還沒完全瞭解透徹)

16、SQL 優化的常見方法有哪些

查詢條件減少使用函數,避免全表掃描
減少不必要的表連接
有些數據操作的業務邏輯可以放到應用層進行實現
可以使用with as
儘量避免使用遊標,因爲遊標的效率較差
不要把SQL語句寫得太複雜
不能循環執行查詢
用 exists 代替 in 
表關聯關係不要太糾結
查詢多用索引列取查,用charindex或者like[0-9]來代替%%
inner關聯的表可以先查出來,再去關聯leftjoin的表
可以進行表關聯數據拆分,即先查出核心數據,再通過核心數據查其他數據,這樣會快得多
參考SQL執行順序進行優化
表關聯時取別名,也能提高效率
使用視圖,給視圖建立索引進行優化
使用數據倉庫的形式,建立單獨的表存儲數據,根據時間戳定期更新數據。將多表關聯的數據集中抽取存入一張表中,查詢時單表查詢,提高了查詢效率
對查詢進行優化,應儘量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引
應儘量避免在 where 子句中對字段進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如:    
select id from t where num is null     
可以在num上設置默認值0,確保表中num列沒有null值,然後這樣查詢:   
select id from t where num=0       
   19.應儘量避免在 where 子句中使用!=或<>操作符,否則將引擎放棄使用索引而進行全表掃描

17、SQL 索引的順序,字段的順序

18、查看 SQL 是不是使用了索引?(有什麼工具)

在select語句前加上EXPLAIN即可

19、TCP 和 UDP 的區別?TCP 數據傳輸過程中怎麼做到可靠的?

UDP(User Data Protocol,用戶數據報協議)是與TCP相對應的協議。它是屬於TCP/IP協議族中的一種

1)爲了保證數據包的可靠傳遞,發送方必須把已發送的數據包保留在緩衝區; 
(2)併爲每個已發送的數據包啓動一個超時定時器; 
(3)如在定時器超時之前收到了對方發來的應答信息(可能是對本包的應答,也可以是對本包後續包的應答),則釋放該數據包占用的緩衝區; 
(4)否則,重傳該數據包,直到收到應答或重傳次數超過規定的最大次數爲止。
(5)接收方收到數據包後,先進行CRC校驗,如果正確則把數據交給上層協議,然後給發送方發送一個累計應答包,表明該數據已收到,如果接收方正好也有數據要發給發送方,應答包也可方在數據包中捎帶過去。
20、說下你知道的排序算法吧

常見的內部排序算法有:插入排序、希爾排序、選擇排序、冒泡排序、歸併排序、快速排序、堆排序、基數排序等

21、查找一個數組的中位數?

通過二分查找法來找中位數

基本思想是:假設ar1[i]是合併後的中位數,那麼ar1[i]大於ar1[]中前i-1個數,且大於ar2[]中前j=n-i-1個數。通過ar1[i]和ar2[j]、ar2[j+1]兩個數的比較,在ar1[i]的左邊或者ar1[i]右邊繼續進行二分查找。對於兩個數組 ar1[] 和ar2[], 先在 ar1[] 中做二分查找。如果在ar1[]中沒找到中位數, 繼續在ar2[]中查找。

算法流程:
1) 得到數組ar1[]最中間的數,假設下標爲i.
2) 計算對應在數組ar2[]的下標j,j = n-i-1 
3) 如果 ar1[i] >= ar2[j] and ar1[i] <= ar2[j+1],那麼 ar1[i] 和 ar2[j] 就是兩個中間元素,返回ar2[j] 和 ar1[i] 的平均值
4) 如果 ar1[i] 大於 ar2[j] 和 ar2[j+1] 那麼在ar1[i]的左部分做二分查找(i.e., arr[left ... i-1])
5) 如果 ar1[i] 小於 ar2[j] 和 ar2[j+1] 那麼在ar1[i]的右部分做二分查找(i.e., arr[i+1....right])
6) 如果到達數組ar1[]的邊界(left or right),則在數組ar2[]中做二分查找

時間複雜度:O(logn)。

二面
22、你有什麼問題想問我的嗎?
1、自我介紹、工作經歷、技術棧

2、項目中你學到了什麼技術?

3、微服務劃分的粒度?

4、微服務的高可用怎麼保證的?

負載均衡與反向代理,隔離,限流,降級,超時與重試,回滾,壓力測試與應急預案

5、常用的負載均衡,該怎麼用,你能說下嗎?

1、http重定向

當http代理(比如瀏覽器)向web服務器請求某個URL後,web服務器可以通過http響應頭信息中的Location標記來返回一個新的URL。這意味着HTTP代理需要繼續請求這個新的URL,完成自動跳轉。

2、DNS負載均衡

DNS 負責提供域名解析服務,當訪問某個站點時,實際上首先需要通過該站點域名的DNS服務器來獲取域名指向的IP地址,在這一過程中,DNS服務器完成了域名到IP地址的映射,同樣,這樣映射也可以是一對多的,這時候,DNS服務器便充當了負載均衡調度器,它就像http重定向轉換策略一樣,將用戶的請求分散到多臺服務器上,但是它的實現機制完全不同。

3、反向代理負載均衡

這個肯定大家都有所接觸,因爲幾乎所有主流的Web服務器都熱衷於支持基於反向代理的負載均衡。它的核心工作就是轉發HTTP請求。

相比前面的HTTP重定向和DNS解析,反向代理的調度器扮演的是用戶和實際服務器中間人的角色:

     1、任何對於實際服務器的HTTP請求都必須經過調度器

     2、調度器必須等待實際服務器的HTTP響應,並將它反饋給用戶(前兩種方式不需要經過調度反饋,是實際服務器直接發送給用戶)

4、IP負載均衡(LVS-NAT)

因爲反向代理服務器工作在HTTP層,其本身的開銷就已經嚴重製約了可擴展性,從而也限制了它的性能極限。那能否在HTTP層面以下實現負載均衡呢?

NAT服務器:它工作在傳輸層,它可以修改發送來的IP數據包,將數據包的目標地址修改爲實際服務器地址

5、直接路由(LVS-DR)

NAT是工作在網絡分層模型的傳輸層(第四層),而直接路由是工作在數據鏈路層(第二層),貌似更屌些。它通過修改數據包的目標MAC地址(沒有修改目標IP),將數據包轉發到實際服務器上,不同的是,實際服務器的響應數據包將直接發送給客戶羰,而不經過調度器

6、IP隧道(LVS-TUN)

基於IP隧道的請求轉發機制:將調度器收到的IP數據包封裝在一個新的IP數據包中,轉交給實際服務器,然後實際服務器的響應數據包可以直接到達用戶端。目前Linux大多支持,可以用LVS來實現,稱爲LVS-TUN,與LVS-DR不同的是,實際服務器可以和調度器不在同一個WANt網段,調度器通過 IP隧道技術來轉發請求到實際服務器,所以實際服務器也必須擁有合法的IP地址。

總體來說,LVS-DR和LVS-TUN都適合響應和請求不對稱的Web服務器,如何從它們中做出選擇,取決於你的網絡部署需要,因爲LVS-TUN可以將實際服務器根據需要部署在不同的地域,並且根據就近訪問的原則來轉移請求,所以有類似這種需求的,就應該選擇LVS-TUN。

6、網關能夠爲後端服務帶來哪些好處?

後端服務器可以專心處理業務請求,節省了大量連接管理的開銷

7、Spring Bean 的生命週期

8、xml 中配置的 init、destroy 方法怎麼可以做到調用具體的方法?

9、反射的機制

大家都知道,要讓Java程序能夠運行,那麼就得讓Java類要被Java虛擬機加載。Java類如果不被Java虛擬機加載,是不能正常運行的。現在我們運行的所有的程序都是在編譯期的時候就已經知道了你所需要的那個類的已經被加載了。

Java的反射機制是在編譯並不確定是哪個類被加載了,而是在程序運行的時候才加載、探知、自審。使用在編譯期並不知道的類。這樣的特點就是反射

反射機制通過void setAccessible(boolean flag)方法可以得到一個類的private的方法和屬性,使用這些private的方法和屬性

10、Object 類中的方法

1,構造函數 
2,hashCode和equale函數用來判斷對象是否相同, 
3,wait(),wait(long),wait(long,int),notify(),notifyAll() 
4,toString()和getClass, 
5,clone() 
6,finalize()用於在垃圾回收

11、hashcode 和 equals 方法常用地方

12、對象比較是否相同

equals通常用來比較兩個對象的內容是否相等,==用來比較兩個對象的地址是否相等

13、hashmap put 方法存放的時候怎麼判斷是否是重複的

先比較key的hashCode,再比較相等或equals的,所以重寫hashCode()和equals()方法即可實現添加重複元素。

14、Object toString 方法常用的地方,爲什麼要重寫該方法

常用在對象模型類

因爲假如User是一個用戶的對象,如果User.toString();結果是不正常的,因爲User對象中可能有多個屬性,如年齡,姓名等,這個toString後無法知道具體的是那個屬性轉換爲字符串

15、Set 和 List 區別?

Set(集):集合中的對象不按特定方式排序,並且沒有重複對象。它的有些實現類能對集合中的對象按特定方式排序。
List(列表):集合中的對象按索引位置排序,可以有重複對象,允許按照對象在集合中的索引位置檢索對象。

16、ArrayList 和 LinkedList 區別

 ArrayList是實現了基於動態數組的數據結構,LinkedList基於鏈表的數據結構

ArrayList 繼承AbstractList
LinkedList 繼承AbstractSequentialList
ArrayList 採用的是數組形式來保存對象的,這種方式將對象放在連續的位置中,所以最大的缺點就是插入刪除時非常麻煩

LinkedList 採用的將對象存放在獨立的空間中,而且在每個空間中還保存下一個鏈接的索引 但是缺點就是查找非常麻煩 要叢第一個索引開始

17、如果存取相同的數據,ArrayList 和 LinkedList 誰佔用空間更大?

對於隨機訪問get和set,ArrayList覺得優於LinkedList,因爲LinkedList要移動指針

對於新增和刪除操作add和remove,LinedList比較佔優勢,因爲ArrayList要移動數據,若要從數組中刪除或插入某一個對象,需要移動後段的數組元素,從而會重新調整索引順序,調整索引順序會消耗一定的時間,相反,LinkedList是使用鏈表實現的,若要從鏈表中刪除或插入某一個對象,只需要改變前後對象的引用即可

18、Set 存的順序是有序的嗎?

無序

Set是Map的一個馬甲,主要邏輯都交給Map實現

19、常見 Set 的實現有哪些?

HashSet

LinkedHashSet

TreeSet

20、TreeSet 對存入對數據有什麼要求呢?

TreeSet集合是用來對象元素進行排序的,同樣他也可以保證元素的唯一

21、HashSet 的底層實現呢?

22、TreeSet 底層源碼有看過嗎?

TreeSet的底層實現是TreeMap

public TreeSet(Comparator<? super E> comparator) {

        this(new TreeMap<>(comparator));

    }

23、HashSet 是不是線程安全的?爲什麼不是線程安全的?

說白了,HashSet就是限制了功能的HashMap,所以瞭解HashMap的實現原理

24、Java 中有哪些線程安全的 Map?

Concurrenthashmap

25、Concurrenthashmap 是怎麼做到線程安全的?

ConcurrentHashMap的大部分操作和HashMap是相同的,例如初始化,擴容和鏈表向紅黑樹的轉變等。但是,在ConcurrentHashMap中,大量使用了U.compareAndSwapXXX

的方法,這個方法是利用一個CAS算法實現無鎖化的修改值的操作,他可以大大降低鎖代理的性能消耗。這個算法的基本思想就是不斷地去比較當前內存中的變量值與你指定的

一個變量值是否相等,如果相等,則接受你指定的修改的值,否則拒絕你的操作。因爲當前線程中的值已經不是最新的值,你的修改很可能會覆蓋掉其他線程修改的結果。這一

點與樂觀鎖,SVN的思想是比較類似的。

同時,在ConcurrentHashMap中還定義了三個原子操作,用於對指定位置的節點進行操作。這三種原子操作被廣泛的使用在ConcurrentHashMap的get和put等方法中,

正是這些原子操作保證了ConcurrentHashMap的線程安全。

在ConcurrentHashMap沒有出現以前,jdk使用hashtable來實現線程安全,但是hashtable是將整個hash表鎖住,所以效率很低下。

ConcurrentHashMap將數據分別放到多個Segment中,默認16個,每一個Segment中又包含了多個HashEntry列表數組,

對於一個key,需要經過三次hash操作,才能最終定位這個元素的位置,這三次hash分別爲:

對於一個key,先進行一次hash操作,得到hash值h1,也即h1 = hash1(key);
將得到的h1的高几位進行第二次hash,得到hash值h2,也即h2 = hash2(h1高几位),通過h2能夠確定該元素的放在哪個Segment;
將得到的h1進行第三次hash,得到hash值h3,也即h3 = hash3(h1),通過h3能夠確定該元素放置在哪個HashEntry。
每一個Segment都擁有一個鎖,當進行寫操作時,只需要鎖定一個Segment,而其它Segment中的數據是可以訪問的。

26、HashTable 你瞭解過嗎?

Hashtable既不支持Null key也不支持Null value。Hashtable的put()方法的註釋中有說明

Hashtable是線程安全的,

Hashtable是線程安全的,它的每個方法中都加入了Synchronize方法,效率比較低

Hashtable默認的初始大小爲11,之後每次擴充,容量變爲原來的2n+1。

Hashtable在計算元素的位置時需要進行一次除法運算,而除法運算是比較耗時的。

27、如何保證線程安全問題?

28、synchronized、lock

synchronized是java中的一個關鍵字,也就是說是Java語言內置的特性

如果一個代碼塊被synchronized修飾了,當一個線程獲取了對應的鎖,並執行該代碼塊時,其他線程便只能一直等待,等待獲取鎖的線程釋放鎖,而這裏獲取鎖的線程釋放鎖只會有兩種情況:

  1)獲取鎖的線程執行完了該代碼塊,然後線程釋放對鎖的佔有;

  2)線程執行發生異常,此時JVM會讓線程自動釋放鎖

那麼如果這個獲取鎖的線程由於要等待IO或者其他原因(比如調用sleep方法)被阻塞了,但是又沒有釋放鎖,其他線程便只能乾巴巴地等待,試想一下,這多麼影響程序執行效率。

  因此就需要有一種機制可以不讓等待的線程一直無期限地等待下去(比如只等待一定的時間或者能夠響應中斷),通過Lock就可以辦到

再舉個例子:當有多個線程讀寫文件時,讀操作和寫操作會發生衝突現象,寫操作和寫操作會發生衝突現象,但是讀操作和讀操作不會發生衝突現象。

  但是採用synchronized關鍵字來實現同步的話,就會導致一個問題:

  如果多個線程都只是進行讀操作,所以當一個線程在進行讀操作時,其他線程只能等待無法進行讀操作。

  因此就需要一種機制來使得多個線程都只是進行讀操作時,線程之間不會發生衝突,通過Lock就可以辦到。

另外,通過Lock可以知道線程有沒有成功獲取到鎖。這個是synchronized無法辦到的

29、volatile 的原子性問題?爲什麼 i++ 這種不支持原子性?從計算機原理的設計來講下不能保證原子性的原因

30、happens before 原理

31、cas 操作

java.util.concurrent包中藉助CAS實現了區別於synchronized同步鎖的一種樂觀鎖

cas是比較並交換算法

 CAS有3個操作數,內存值V,舊的預期值A,要修改的新值B。當且僅當預期值A和內存值V相同時,將內存值V修改爲B,否則什麼都不做

JDK提供了AtomicReference類來保證引用對象之間的原子性,就可以把多個變量放在一個對象裏來進行CAS操作。

32、lock 和 synchronized 的區別?

    1)Lock是一個接口,而synchronized是Java中的關鍵字,synchronized是內置的語言實現;

  2)synchronized在發生異常時,會自動釋放線程佔有的鎖,因此不會導致死鎖現象發生;而Lock在發生異常時,如果沒有主動通過unLock()去釋放鎖,則很可能造成死鎖現象,因此使用Lock時需要在finally塊中釋放鎖;

  3)Lock可以讓等待鎖的線程響應中斷,而synchronized卻不行,使用synchronized時,等待的線程會一直等待下去,不能夠響應中斷;

  4)通過Lock可以知道有沒有成功獲取鎖,而synchronized卻無法辦到。

  5)Lock可以提高多個線程進行讀操作的效率。

  在性能上來說,如果競爭資源不激烈,兩者的性能是差不多的,而當競爭資源非常激烈時(即有大量線程同時競爭),此時Lock的性能要遠遠優於synchronized。所以說,在具體使用時要根據適當情況選擇。

 

類別

synchronized

Lock

存在層次

Java的關鍵字,在jvm層面上

是一個類

鎖的釋放

1、以獲取鎖的線程執行完同步代碼,釋放鎖 2、線程執行發生異常,jvm會讓線程釋放鎖

在finally中必須釋放鎖,不然容易造成線程死鎖

鎖的獲取

假設A線程獲得鎖,B線程等待。如果A線程阻塞,B線程會一直等待

分情況而定,Lock有多個鎖獲取的方式,具體下面會說道,大致就是可以嘗試獲得鎖,線程可以不用一直等待

鎖狀態

無法判斷

可以判斷

鎖類型

可重入 不可中斷 非公平

可重入 可判斷 可公平(兩者皆可)

性能

少量同步

大量同步

33、公平鎖和非公平鎖

公平和非公平鎖的隊列都基於鎖內部維護的一個雙向鏈表,表結點Node的值就是每一個請求當前鎖的線程。公平鎖則在於每次都是依次從隊首取值

非公平鎖在等待鎖的過程中, 如果有任意新的線程妄圖獲取鎖,都是有很大的機率直接獲取到鎖的

(在ReentrantLock中很明顯可以看到其中同步包括兩種,分別是公平的FairSync和非公平的NonfairSync。公平鎖的作用就是嚴格按照線程啓動的順序來執行的,不允許其他線程插隊執行的;而非公平鎖是允許插隊的。

默認情況下ReentrantLock是通過非公平鎖來進行同步的,包括synchronized關鍵字都是如此,因爲這樣性能會更好。因爲從線程進入了RUNNABLE狀態,可以執行開始,到實際線程執行是要比較久的時間的。而且,在一個鎖釋放之後,其他的線程會需要重新來獲取鎖。其中經歷了持有鎖的線程釋放鎖,其他線程從掛起恢復到RUNNABLE狀態,其他線程請求鎖,獲得鎖,線程執行,這一系列步驟。如果這個時候,存在一個線程直接請求鎖,可能就避開掛起到恢復RUNNABLE狀態的這段消耗,所以性能更優化)

34、Java 讀寫鎖

35、讀寫鎖設計主要解決什麼問題?

多線程,

讀操作可以共享,寫操作是排他的,讀可以有多個在讀,寫只有唯一個在寫,同時寫的時候不允許讀

解決了讀和讀可以同時進行,讀和寫不能同時進行,寫和寫不能同時進行

36、你項目除了寫 Java 代碼,還有前端代碼,那你知道前端有哪些框架嗎?

Vue layer react element

37、MySQL 分頁查詢語句

LIMIT [offset,] rows

offset指定要返回的第一行的偏移量,rows第二個指定返回行的最大數目

38、MySQL 事務特性和隔離級別

事務的基本要素(ACID)
1、原子性(Atomicity):事務開始後所有操作,要麼全部做完,要麼全部不做,不可能停滯在中間環節。事務執行過程中出錯,會回滾到事務開始前的狀態,所有的操作就像沒有發生一樣。也就是說事務是一個不可分割的整體,就像化學中學過的原子,是物質構成的基本單位。

   2、一致性(Consistency):事務開始前和結束後,數據庫的完整性約束沒有被破壞 。比如A向B轉賬,不可能A扣了錢,B卻沒收到。

   3、隔離性(Isolation):同一時間,只允許一個事務請求同一數據,不同的事務之間彼此沒有任何干擾。比如A正在從一張銀行卡中取錢,在A取錢的過程結束前,B不能向這張卡轉賬。

   4、持久性(Durability):事務完成後,事務對數據庫的所有更新將被保存到數據庫,不能回滾。

二、事務的併發問題

 

1、髒讀:事務A讀取了事務B更新的數據,然後B回滾操作,那麼A讀取到的數據是髒數據

  2、不可重複讀:事務 A 多次讀取同一數據,事務 B 在事務A多次讀取的過程中,對數據作了更新並提交,導致事務A多次讀取同一數據時,結果 不一致。

  3、幻讀:系統管理員A將數據庫中所有學生的成績從具體分數改爲ABCDE等級,但是系統管理員B就在這個時候插入了一條具體分數的記錄,當系統管理員A改結束後發現還有一條記錄沒有改過來,就好像發生了幻覺一樣,這就叫幻讀。

 

MySQL事務隔離級別

事務隔離級別

髒讀

不可重複讀

幻讀

讀未提交(read-uncommitted)

不可重複讀(read-committed)

可重複讀(repeatable-read)

串行化(serializable)

 

39、不可重複讀會出現在什麼場景?

40、sql having 的使用場景

如果需要對組函數的結果作爲條件,那麼不能使用where子句,必須使用having子句

41、前端瀏覽器地址的一個 http 請求到後端整個流程是怎麼樣?

能夠說下嗎?

域名解析 --> 發起TCP的3次握手 --> 建立TCP連接後發起http請求 -->服務器響應http請求,瀏覽器得到html代碼 -->瀏覽器解析html代碼,並請求html代碼中的資源(如js、css、圖片等) --> 瀏覽器對頁面進行渲染呈現給用戶

42、http 默認端口,https 默認端口

HTTP協議代理服務器常用端口號:80/8080/3128/8081/9080
HTTPS服務器,默認的端口號爲443/tcp 443/udp

43、DNS 你知道是幹嘛的嗎?

DNS是指:域名服務器(Domain Name Server)。在Internet上域名與IP地址之間是一一對應的,域名雖然便於人們記憶,但機器之間只能互相認識IP地址,它們之間的轉換工作稱爲域名解析,域名解析需要由專門的域名解析服務器來完成,DNS就是進行域名解析的服務器

44、你們開發用的 ide 是啥?你能說下 idea 的常用幾個快捷鍵吧?

45、代碼版本管理你們用的是啥?

46、git rebase 和 merge 有什麼區別?

47、你們公司加班多嗎?


 

注:有些問題待補充。


原文:https://blog.csdn.net/weixin_38003389/article/details/83747310 
版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章