面試:第十五章:螞蟻金服面試以及答案

一面

1、自我介紹、自己做的項目和技術(shù)領(lǐng)域

開放題

2、項目中的監(jiān)控:那個監(jiān)控指標(biāo)常見的有哪些?

答:CPU、內(nèi)存、IO 等等。建議下載個nmon工具,里面有各個指標(biāo)。

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

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

網(wǎng)絡(luò): 吞吐量、吞吐率

應(yīng)用: jvm內(nèi)存、日志、Full GC頻率

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

4、注冊中心你了解了哪些?

答:Consul 、Eureka、ZooKeeper

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

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

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

答:(1). IoC(Inversion of Control)是指容器控制程序?qū)ο笾g的關(guān)系,而不是傳統(tǒng)實現(xiàn)中,由程序代碼直接操控。控制權(quán)由應(yīng)用代碼中轉(zhuǎn)到了外部容器,控制權(quán)的轉(zhuǎn)移是所謂反轉(zhuǎn)。 對于Spring而言,就是由Spring來控制對象的生命周期和對象之間的關(guān)系;IoC還有另外一個名字——“依賴注入(Dependency Injection)”。從名字上理解,所謂依賴注入,即組件之間的依賴關(guān)系由容器在運行期決定,即由容器動態(tài)地將某種依賴關(guān)系注入到組件之中。  

(2). 在Spring的工作方式中,所有的類都會在spring容器中登記,告訴spring這是個什么東西,你需要什么東西,然后spring會在系統(tǒng)運行到適當(dāng)?shù)臅r候,把你要的東西主動給你,同時也把你交給其他需要你的東西。所有的類的創(chuàng)建、銷毀都由 spring來控制,也就是說控制對象生存周期的不再是引用它的對象,而是spring。對于某個具體的對象而言,以前是它控制其他對象,現(xiàn)在是所有對象都被spring控制,所以這叫控制反轉(zhuǎn)。

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

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

AOP(Aspect Oriented Programming)

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

(2). AOP利用一種稱為“橫切”的技術(shù),剖解開封裝的對象內(nèi)部,并將那些影響了 多個類的公共行為封裝到一個可重用模塊,并將其名為“Aspect”,即方面。所謂“方面”,簡單地說,就是將那些與業(yè)務(wù)無關(guān),卻為業(yè)務(wù)模塊所共同調(diào)用的 邏輯或責(zé)任封裝起來,比如日志記錄,便于減少系統(tǒng)的重復(fù)代碼,降低模塊間的耦合度,并有利于未來的可操作性和可維護性。

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

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

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

(6). AOP使用場景:           

Authentication 權(quán)限檢查     

Caching 緩存     

Context passing 內(nèi)容傳遞     

Error handling 錯誤處理     

Lazy loading 延遲加載     

Debugging 調(diào)試    

logging, tracing, profiling and monitoring 日志記錄,跟蹤,優(yōu)化,校準(zhǔn)     

Performance optimization 性能優(yōu)化,效率檢查     

Persistence 持久化     

Resource pooling 資源池     

Synchronization 同步     

Transactions 事務(wù)管理   

另外Filter的實現(xiàn)和struts2的攔截器的實現(xiàn)都是AOP思想的體現(xiàn)。

8、Spring Boot除了自動配置,相比傳統(tǒng)的 Spring 有什么其他的區(qū)別?

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

1.Spring Boot可以建立獨立的Spring應(yīng)用程序;

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

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

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

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

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

9、Spring Cloud 有了解多少?

Spring Cloud是一系列框架的有序集合。它利用Spring Boot的開發(fā)便利性巧妙地簡化了分布式系統(tǒng)基礎(chǔ)設(shè)施的開發(fā),如服務(wù)發(fā)現(xiàn)注冊、配置中心、消息總線、負載均衡、斷路器、數(shù)據(jù)監(jiān)控等,都可以用Spring Boot的開發(fā)風(fēng)格做到一鍵啟動和部署。Spring Cloud并沒有重復(fù)制造輪子,它只是將目前各家公司開發(fā)的比較成熟、經(jīng)得起實際考驗的服務(wù)框架組合起來,通過Spring Boot風(fēng)格進行再封裝屏蔽掉了復(fù)雜的配置和實現(xiàn)原理,最終給開發(fā)者留出了一套簡單易懂、易部署和易維護的分布式系統(tǒng)開發(fā)工具包。

10、Spring Bean 的生命周期

一個Bean從創(chuàng)建到銷毀,如果是用BeanFactory來生成,管理Bean的話

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

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

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

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

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

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

  6、如果這個Bean關(guān)聯(lián)了BeanPostProcessor接口,將會調(diào)用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor經(jīng)常被用作是Bean內(nèi)容的更改,并且由于這個是在Bean初始化結(jié)束時調(diào)用那個的方法,也可以被應(yīng)用于內(nèi)存或緩存技術(shù);

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

  8、如果這個Bean關(guān)聯(lián)了BeanPostProcessor接口,將會調(diào)用postProcessAfterInitialization(Object obj, String s)方法、;

  注:以上工作完成以后就可以應(yīng)用這個Bean了,那這個Bean是一個Singleton的,所以一般情況下我們調(diào)用同一個id的Bean會是在內(nèi)容地址相同的實例,當(dāng)然在Spring配置文件中也可以配置非Singleton,這里我們不做贅述。

  9、當(dāng)Bean不再需要時,會經(jīng)過清理階段,如果Bean實現(xiàn)了DisposableBean這個接口,會調(diào)用那個其實現(xiàn)的destroy()方法;

  10、最后,如果這個Bean的Spring配置中配置了destroy-method屬性,會自動調(diào)用其配置的銷毀方法。

另外我們這里描述的是應(yīng)用Spring上下文Bean的生命周期,如果應(yīng)用Spring的工廠也就是BeanFactory的話去掉第5步就Ok了

11、HashMap 和 hashTable 區(qū)別?

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

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

Hashtable默認的初始大小為11,之后每次擴充,容量變?yōu)樵瓉淼?n+1。

HashMap默認的初始化大小為16。之后每次擴充,容量變?yōu)樵瓉淼?倍

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

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

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

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

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

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

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

13、Hashmap 線程不安全的出現(xiàn)場景

用ConcurrentHashMap 線程安全

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

首先hashmap里這個size沒有用volatile關(guān)鍵字修飾,代表這不是一個內(nèi)存可見的變量,線程操作數(shù)據(jù)的時候一般是從主存拷貝一個變量副本進行操作,操作完成過后在把size的值寫回到主存size的

線程不安全問題應(yīng)該屬于并發(fā)問題之一的,屬于相對高級的問題了。這個時候的問題已經(jīng)不僅僅局限于代碼層面了,很多時候需要結(jié)合JVM一起分析了

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

定位出現(xiàn)問題的堆棧信息排查具體問題

1、top命令:Linux命令??梢圆榭磳崟r的CPU使用情況。也可以查看最近一段時間的CPU使用情況。

2、ps命令: Linux命令。強大的進程狀態(tài)監(jiān)控命令??梢圆榭催M程以及進程中線程的當(dāng)前CPU使用情況。屬于當(dāng)前狀態(tài)的采樣數(shù)據(jù)。

3、jstack: Java提供的命令??梢圆榭茨硞€進程的當(dāng)前線程棧運行情況。根據(jù)這個命令的輸出可以定位某個進程的所有線程的當(dāng)前運行狀態(tài)、運行代碼,以及是否死鎖等等。

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

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

JUC提供了調(diào)度器對象Executors來創(chuàng)建線程池,可創(chuàng)建的線程池有四種

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

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

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

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

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

4、newScheduleThreadPool創(chuàng)建一個定長的線程池,而且支持定時的以及周期性的任務(wù)執(zhí)行,類似于Timer。(這種線程池原理暫還沒完全了解透徹)

16、SQL 優(yōu)化的常見方法有哪些

查詢條件減少使用函數(shù),避免全表掃描

減少不必要的表連接

有些數(shù)據(jù)操作的業(yè)務(wù)邏輯可以放到應(yīng)用層進行實現(xiàn)

可以使用with as

盡量避免使用游標(biāo),因為游標(biāo)的效率較差

不要把SQL語句寫得太復(fù)雜

不能循環(huán)執(zhí)行查詢

用 exists 代替 in

表關(guān)聯(lián)關(guān)系不要太糾結(jié)

查詢多用索引列取查,用charindex或者like[0-9]來代替%%

inner關(guān)聯(lián)的表可以先查出來,再去關(guān)聯(lián)leftjoin的表

可以進行表關(guān)聯(lián)數(shù)據(jù)拆分,即先查出核心數(shù)據(jù),再通過核心數(shù)據(jù)查其他數(shù)據(jù),這樣會快得多

參考SQL執(zhí)行順序進行優(yōu)化

表關(guān)聯(lián)時取別名,也能提高效率

使用視圖,給視圖建立索引進行優(yōu)化

使用數(shù)據(jù)倉庫的形式,建立單獨的表存儲數(shù)據(jù),根據(jù)時間戳定期更新數(shù)據(jù)。將多表關(guān)聯(lián)的數(shù)據(jù)集中抽取存入一張表中,查詢時單表查詢,提高了查詢效率

對查詢進行優(yōu)化,應(yīng)盡量避免全表掃描,首先應(yīng)考慮在 where 及 order by 涉及的列上建立索引

應(yīng)盡量避免在 where 子句中對字段進行 null 值判斷,否則將導(dǎo)致引擎放棄使用索引而進行全表掃描,如:   

select id from t where num is null   

可以在num上設(shè)置默認值0,確保表中num列沒有null值,然后這樣查詢:  

select id from t where num=0    

  19.應(yīng)盡量避免在 where 子句中使用!=或<>操作符,否則將引擎放棄使用索引而進行全表掃描

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

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

在select語句前加上EXPLAIN即可

19、TCP 和 UDP 的區(qū)別?TCP 數(shù)據(jù)傳輸過程中怎么做到可靠的?

UDP(User Data Protocol,用戶數(shù)據(jù)報協(xié)議)是與TCP相對應(yīng)的協(xié)議。它是屬于TCP/IP協(xié)議族中的一種

1)為了保證數(shù)據(jù)包的可靠傳遞,發(fā)送方必須把已發(fā)送的數(shù)據(jù)包保留在緩沖區(qū);

(2)并為每個已發(fā)送的數(shù)據(jù)包啟動一個超時定時器;

(3)如在定時器超時之前收到了對方發(fā)來的應(yīng)答信息(可能是對本包的應(yīng)答,也可以是對本包后續(xù)包的應(yīng)答),則釋放該數(shù)據(jù)包占用的緩沖區(qū);

(4)否則,重傳該數(shù)據(jù)包,直到收到應(yīng)答或重傳次數(shù)超過規(guī)定的最大次數(shù)為止。

(5)接收方收到數(shù)據(jù)包后,先進行CRC校驗,如果正確則把數(shù)據(jù)交給上層協(xié)議,然后給發(fā)送方發(fā)送一個累計應(yīng)答包,表明該數(shù)據(jù)已收到,如果接收方正好也有數(shù)據(jù)要發(fā)給發(fā)送方,應(yīng)答包也可方在數(shù)據(jù)包中捎帶過去。

20、說下你知道的排序算法吧

常見的內(nèi)部排序算法有:插入排序、希爾排序、選擇排序、冒泡排序、歸并排序、快速排序、堆排序、基數(shù)排序等

21、查找一個數(shù)組的中位數(shù)?

通過二分查找法來找中位數(shù)

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

算法流程:

1) 得到數(shù)組ar1[]最中間的數(shù),假設(shè)下標(biāo)為i.

2) 計算對應(yīng)在數(shù)組ar2[]的下標(biāo)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) 如果到達數(shù)組ar1[]的邊界(left or right),則在數(shù)組ar2[]中做二分查找

時間復(fù)雜度:O(logn)。

二面

22、你有什么問題想問我的嗎?

1、自我介紹、工作經(jīng)歷、技術(shù)棧

2、項目中你學(xué)到了什么技術(shù)?

3、微服務(wù)劃分的粒度?

4、微服務(wù)的高可用怎么保證的?

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

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

1、http重定向

當(dāng)http代理(比如瀏覽器)向web服務(wù)器請求某個URL后,web服務(wù)器可以通過http響應(yīng)頭信息中的Location標(biāo)記來返回一個新的URL。這意味著HTTP代理需要繼續(xù)請求這個新的URL,完成自動跳轉(zhuǎn)。

2、DNS負載均衡

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

3、反向代理負載均衡

這個肯定大家都有所接觸,因為幾乎所有主流的Web服務(wù)器都熱衷于支持基于反向代理的負載均衡。它的核心工作就是轉(zhuǎn)發(fā)HTTP請求。

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

   1、任何對于實際服務(wù)器的HTTP請求都必須經(jīng)過調(diào)度器

   2、調(diào)度器必須等待實際服務(wù)器的HTTP響應(yīng),并將它反饋給用戶(前兩種方式不需要經(jīng)過調(diào)度反饋,是實際服務(wù)器直接發(fā)送給用戶)

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

因為反向代理服務(wù)器工作在HTTP層,其本身的開銷就已經(jīng)嚴(yán)重制約了可擴展性,從而也限制了它的性能極限。那能否在HTTP層面以下實現(xiàn)負載均衡呢?

NAT服務(wù)器:它工作在傳輸層,它可以修改發(fā)送來的IP數(shù)據(jù)包,將數(shù)據(jù)包的目標(biāo)地址修改為實際服務(wù)器地址

5、直接路由(LVS-DR)

NAT是工作在網(wǎng)絡(luò)分層模型的傳輸層(第四層),而直接路由是工作在數(shù)據(jù)鏈路層(第二層),貌似更屌些。它通過修改數(shù)據(jù)包的目標(biāo)MAC地址(沒有修改目標(biāo)IP),將數(shù)據(jù)包轉(zhuǎn)發(fā)到實際服務(wù)器上,不同的是,實際服務(wù)器的響應(yīng)數(shù)據(jù)包將直接發(fā)送給客戶羰,而不經(jīng)過調(diào)度器

6、IP隧道(LVS-TUN)

基于IP隧道的請求轉(zhuǎn)發(fā)機制:將調(diào)度器收到的IP數(shù)據(jù)包封裝在一個新的IP數(shù)據(jù)包中,轉(zhuǎn)交給實際服務(wù)器,然后實際服務(wù)器的響應(yīng)數(shù)據(jù)包可以直接到達用戶端。目前Linux大多支持,可以用LVS來實現(xiàn),稱為LVS-TUN,與LVS-DR不同的是,實際服務(wù)器可以和調(diào)度器不在同一個WANt網(wǎng)段,調(diào)度器通過 IP隧道技術(shù)來轉(zhuǎn)發(fā)請求到實際服務(wù)器,所以實際服務(wù)器也必須擁有合法的IP地址。

總體來說,LVS-DR和LVS-TUN都適合響應(yīng)和請求不對稱的Web服務(wù)器,如何從它們中做出選擇,取決于你的網(wǎng)絡(luò)部署需要,因為LVS-TUN可以將實際服務(wù)器根據(jù)需要部署在不同的地域,并且根據(jù)就近訪問的原則來轉(zhuǎn)移請求,所以有類似這種需求的,就應(yīng)該選擇LVS-TUN。

6、網(wǎng)關(guān)能夠為后端服務(wù)帶來哪些好處?

后端服務(wù)器可以專心處理業(yè)務(wù)請求,節(jié)省了大量連接管理的開銷

7、Spring Bean 的生命周期

8、xml 中配置的 init、destroy 方法怎么可以做到調(diào)用具體的方法?

9、反射的機制

大家都知道,要讓Java程序能夠運行,那么就得讓Java類要被Java虛擬機加載。Java類如果不被Java虛擬機加載,是不能正常運行的?,F(xiàn)在我們運行的所有的程序都是在編譯期的時候就已經(jīng)知道了你所需要的那個類的已經(jīng)被加載了。

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

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

10、Object 類中的方法

1,構(gòu)造函數(shù)

2,hashCode和equale函數(shù)用來判斷對象是否相同,

3,wait(),wait(long),wait(long,int),notify(),notifyAll()

4,toString()和getClass,

5,clone()

6,finalize()用于在垃圾回收

11、hashcode 和 equals 方法常用地方

12、對象比較是否相同

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

13、hashmap put 方法存放的時候怎么判斷是否是重復(fù)的

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

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

常用在對象模型類

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

15、Set 和 List 區(qū)別?

Set(集):集合中的對象不按特定方式排序,并且沒有重復(fù)對象。它的有些實現(xiàn)類能對集合中的對象按特定方式排序。

List(列表):集合中的對象按索引位置排序,可以有重復(fù)對象,允許按照對象在集合中的索引位置檢索對象。

16、ArrayList 和 LinkedList 區(qū)別

 ArrayList是實現(xiàn)了基于動態(tài)數(shù)組的數(shù)據(jù)結(jié)構(gòu),LinkedList基于鏈表的數(shù)據(jù)結(jié)構(gòu)

ArrayList 繼承AbstractList

LinkedList 繼承AbstractSequentialList

ArrayList 采用的是數(shù)組形式來保存對象的,這種方式將對象放在連續(xù)的位置中,所以最大的缺點就是插入刪除時非常麻煩

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

17、如果存取相同的數(shù)據(jù),ArrayList 和 LinkedList 誰占用空間更大?

對于隨機訪問get和set,ArrayList覺得優(yōu)于LinkedList,因為LinkedList要移動指針

對于新增和刪除操作add和remove,LinedList比較占優(yōu)勢,因為ArrayList要移動數(shù)據(jù),若要從數(shù)組中刪除或插入某一個對象,需要移動后段的數(shù)組元素,從而會重新調(diào)整索引順序,調(diào)整索引順序會消耗一定的時間,相反,LinkedList是使用鏈表實現(xiàn)的,若要從鏈表中刪除或插入某一個對象,只需要改變前后對象的引用即可

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

無序

Set是Map的一個馬甲,主要邏輯都交給Map實現(xiàn)

19、常見 Set 的實現(xiàn)有哪些?

HashSet

LinkedHashSet

TreeSet

20、TreeSet 對存入對數(shù)據(jù)有什么要求呢?

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

21、HashSet 的底層實現(xiàn)呢?

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

TreeSet的底層實現(xiàn)是TreeMap

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

    this(new TreeMap<>(comparator));

  }

23、HashSet 是不是線程安全的?為什么不是線程安全的?

說白了,HashSet就是限制了功能的HashMap,所以了解HashMap的實現(xiàn)原理

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

Concurrenthashmap

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

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

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

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

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

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

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

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

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

對于一個key,需要經(jīng)過三次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都擁有一個鎖,當(dāng)進行寫操作時,只需要鎖定一個Segment,而其它Segment中的數(shù)據(jù)是可以訪問的。

26、HashTable 你了解過嗎?

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

Hashtable是線程安全的,

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

Hashtable默認的初始大小為11,之后每次擴充,容量變?yōu)樵瓉淼?n+1。

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

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

28、synchronized、lock

synchronized是java中的一個關(guān)鍵字,也就是說是Java語言內(nèi)置的特性

如果一個代碼塊被synchronized修飾了,當(dāng)一個線程獲取了對應(yīng)的鎖,并執(zhí)行該代碼塊時,其他線程便只能一直等待,等待獲取鎖的線程釋放鎖,而這里獲取鎖的線程釋放鎖只會有兩種情況:

1)獲取鎖的線程執(zhí)行完了該代碼塊,然后線程釋放對鎖的占有;

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

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

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

再舉個例子:當(dāng)有多個線程讀寫文件時,讀操作和寫操作會發(fā)生沖突現(xiàn)象,寫操作和寫操作會發(fā)生沖突現(xiàn)象,但是讀操作和讀操作不會發(fā)生沖突現(xiàn)象。

但是采用synchronized關(guān)鍵字來實現(xiàn)同步的話,就會導(dǎo)致一個問題:

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

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

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

29、volatile 的原子性問題?為什么 i++ 這種不支持原子性?從計算機原理的設(shè)計來講下不能保證原子性的原因

30、happens before 原理

31、cas 操作

java.util.concurrent包中借助CAS實現(xiàn)了區(qū)別于synchronized同步鎖的一種樂觀鎖

cas是比較并交換算法

 CAS有3個操作數(shù),內(nèi)存值V,舊的預(yù)期值A(chǔ),要修改的新值B。當(dāng)且僅當(dāng)預(yù)期值A(chǔ)和內(nèi)存值V相同時,將內(nèi)存值V修改為B,否則什么都不做

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

32、lock 和 synchronized 的區(qū)別?

  1)Lock是一個接口,而synchronized是Java中的關(guān)鍵字,synchronized是內(nèi)置的語言實現(xiàn);

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

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

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

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

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

 

類別

synchronized

Lock

存在層次

Java的關(guān)鍵字,在jvm層面上

是一個類

鎖的釋放

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

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

鎖的獲取

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

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

鎖狀態(tài)

無法判斷

可以判斷

鎖類型

可重入 不可中斷 非公平

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

性能

少量同步

大量同步

33、公平鎖和非公平鎖

公平和非公平鎖的隊列都基于鎖內(nèi)部維護的一個雙向鏈表,表結(jié)點Node的值就是每一個請求當(dāng)前鎖的線程。公平鎖則在于每次都是依次從隊首取值

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

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

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

34、Java 讀寫鎖

35、讀寫鎖設(shè)計主要解決什么問題?

多線程,

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

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

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

Vue layer react element

37、MySQL 分頁查詢語句

LIMIT [offset,] rows

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

38、MySQL 事務(wù)特性和隔離級別

事務(wù)的基本要素(ACID)

1、原子性(Atomicity):事務(wù)開始后所有操作,要么全部做完,要么全部不做,不可能停滯在中間環(huán)節(jié)。事務(wù)執(zhí)行過程中出錯,會回滾到事務(wù)開始前的狀態(tài),所有的操作就像沒有發(fā)生一樣。也就是說事務(wù)是一個不可分割的整體,就像化學(xué)中學(xué)過的原子,是物質(zhì)構(gòu)成的基本單位。

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

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

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

二、事務(wù)的并發(fā)問題

1、臟讀:事務(wù)A讀取了事務(wù)B更新的數(shù)據(jù),然后B回滾操作,那么A讀取到的數(shù)據(jù)是臟數(shù)據(jù)

2、不可重復(fù)讀:事務(wù) A 多次讀取同一數(shù)據(jù),事務(wù) B 在事務(wù)A多次讀取的過程中,對數(shù)據(jù)作了更新并提交,導(dǎo)致事務(wù)A多次讀取同一數(shù)據(jù)時,結(jié)果 不一致。

3、幻讀:系統(tǒng)管理員A將數(shù)據(jù)庫中所有學(xué)生的成績從具體分?jǐn)?shù)改為ABCDE等級,但是系統(tǒng)管理員B就在這個時候插入了一條具體分?jǐn)?shù)的記錄,當(dāng)系統(tǒng)管理員A改結(jié)束后發(fā)現(xiàn)還有一條記錄沒有改過來,就好像發(fā)生了幻覺一樣,這就叫幻讀

MySQL事務(wù)隔離級別

事務(wù)隔離級別

臟讀

不可重復(fù)讀

幻讀

讀未提交(read-uncommitted)

不可重復(fù)讀(read-committed)

可重復(fù)讀(repeatable-read)

串行化(serializable)

39、不可重復(fù)讀會出現(xiàn)在什么場景?

40、sql having 的使用場景

如果需要對組函數(shù)的結(jié)果作為條件,那么不能使用where子句,必須使用having子句

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

能夠說下嗎?

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

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

HTTP協(xié)議代理服務(wù)器常用端口號:80/8080/3128/8081/9080

HTTPS服務(wù)器,默認的端口號為443/tcp 443/udp

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

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

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

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

46、git rebase 和 merge 有什么區(qū)別?

47、你們公司加班多嗎?

 

注:有些問題待補充。