久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

工作兩年多,,XX 征信 面試,,offer已到手

 田維常 2021-07-13

回復(fù)“000”獲取程序員必備電子書

大家好,我是老田,,今天給大家分享的是一位兩年多工作經(jīng)驗的小伙伴面試經(jīng)歷,,恭喜他成功上岸,收到了offer,!本文大部分內(nèi)容是這位朋友所寫,,我對一小部分內(nèi)容進(jìn)行修正和調(diào)整,話不多說,,咱們直入主題,。

面試官到了后,看著簡歷,,然后來一句千年不變的:先做一個自我介紹,,然后我就大致做了一個簡短的自我介紹。隨后面試官,,隨便問了為什么離職,?還問了項目情況,最后開始技術(shù)面試,。

1,、說說你對HashMap的理解

這道題,有點(diǎn)泛,,所以只能把自己知道都回答一遍,,能回答越多越好。

關(guān)于這道題,,我們可以從幾個方面去回答:

數(shù)據(jù)結(jié)構(gòu)

JDK1.7之前采用的是數(shù)組+鏈表,。

JDK1.8后采用的是數(shù)組+鏈表(紅黑樹),當(dāng)鏈表的長度大于8,,并且數(shù)組長度為64時,,如果再往此鏈表上添加數(shù)據(jù),,那么該鏈表就會轉(zhuǎn)為紅黑樹,。

put方法過程

看流程圖,這樣印象更深刻:


線程安全問題

在多線程環(huán)境下,,1.7 會產(chǎn)生死循環(huán),、數(shù)據(jù)丟失、數(shù)據(jù)覆蓋的問題,1.8 中會有數(shù)據(jù)覆蓋的問題,,以 1.8 為例,,當(dāng) A 線程判斷 index 位置為空后正好掛起,B 線程開始往 index 位置的寫入節(jié)點(diǎn)數(shù)據(jù),,這時 A 線程恢復(fù)現(xiàn)場,,執(zhí)行賦值操作,就把 A 線程的數(shù)據(jù)給覆蓋了,;還有++size 這個地方也會造成多線程同時擴(kuò)容等問題,。

2、hash沖突解決方案有哪些

這個題是知道就知道,,不知道就是不知道,,理論性很強(qiáng),說白了背就得了,。

一共有四種方法:

1,、再哈希法:如果hash出的index已經(jīng)有值,就再hash,,不行繼續(xù)hash,,直至找到空的index位置,要相信瞎貓總能碰上死耗子,。這個辦法最容易想到,。但有2個缺點(diǎn):

  • 比較浪費(fèi)空間,消耗效率,。根本原因還是數(shù)組的長度是固定不變的,,不斷hash找出空的index,可能越界,,這時就要創(chuàng)建新數(shù)組,,而老數(shù)組的數(shù)據(jù)也需要遷移。隨著數(shù)組越來越大,,消耗不可小覷,。
  • get不到,或者說get算法復(fù)雜,。進(jìn)是進(jìn)去了,,想出來就沒那么容易了。

2,、開放地址方法:如果hash出的index已經(jīng)有值,,通過算法在它前面或后面的若干位置尋找空位,這個和再hash算法差別不大,。

3,、建立公共溢出區(qū): 把沖突的hash值放到另外一塊溢出區(qū)。

4、鏈?zhǔn)降刂贩ǎ?/strong> 把產(chǎn)生hash沖突的hash值以鏈表形式存儲在index位置上,。HashMap用的就是該方法,。優(yōu)點(diǎn)是不需要另外開辟新空間,也不會丟失數(shù)據(jù),,尋址也比較簡單,。但是隨著hash鏈越來越長,尋址也是更加耗時,。好的hash算法就是要讓鏈盡量短,,最好一個index上只有一個值。也就是盡可能地保證散列地址分布均勻,,同時要計算簡單,。

3、說說你對Spring IOC的理解

傳說中的傻屌面試題,,但是又不得不問的面試題,,所以一定要回答的好,給面試官一個好的印象,。

IOC就是控制反轉(zhuǎn),,是指創(chuàng)建對象的控制權(quán)的轉(zhuǎn)移。以前創(chuàng)建對象的主動權(quán)和時機(jī)是由自己把控的,,而現(xiàn)在這種權(quán)力轉(zhuǎn)移到Spring容器中,,并由容器根據(jù)配置文件去創(chuàng)建實(shí)例和管理各個實(shí)例之間的依賴關(guān)系。對象與對象之間松散耦合,,也利于功能的復(fù)用,。DI依賴注入,和控制反轉(zhuǎn)是同一個概念的不同角度的描述,,即 應(yīng)用程序在運(yùn)行時依賴IoC容器來動態(tài)注入對象需要的外部資源,。

最直觀的表達(dá)就是,IOC讓對象的創(chuàng)建不用去new了,,可以由spring自動生產(chǎn),,使用java的反射機(jī)制,根據(jù)配置文件在運(yùn)行時動態(tài)的去創(chuàng)建對象以及管理對象,,并調(diào)用對象的方法的,。

Spring的IOC有三種注入方式 :構(gòu)造器注入、setter方法注入,、根據(jù)注解注入,。

IoC讓相互協(xié)作的組件保持松散的耦合,而AOP編程允許你把遍布于應(yīng)用各層的功能分離出來形成可重用的功能組件,。

4,、Spring AOP在工作中有用過嗎?

應(yīng)該是后端開發(fā)必備,,不管是吹牛逼,,還是實(shí)戰(zhàn),這都是必備的,。

有用過,。

AOP(Aspect-Oriented Programming,面向切面編程)能夠?qū)⒛切┡c業(yè)務(wù)無關(guān),,卻為業(yè)務(wù)模塊所共同調(diào)用的邏輯或責(zé)任(例如事務(wù)處理,、日志管理、權(quán)限控制等)封裝起來,,便于減少系統(tǒng)的重復(fù)代碼,,降低模塊間的耦合度,并有利于未來的可擴(kuò)展性和可維護(hù)性,。

Spring AOP是基于動態(tài)代理的,,如果要代理的對象實(shí)現(xiàn)了某個接口,那么Spring AOP就會使用JDK動態(tài)代理去創(chuàng)建代理對象,;而對于沒有實(shí)現(xiàn)接口的對象,,就無法使用JDK動態(tài)代理,轉(zhuǎn)而使用CGlib動態(tài)代理生成一個被代理對象的子類來作為代理,。

當(dāng)然也可以使用AspectJ,,Spring AOP中已經(jīng)集成了AspectJ,AspectJ應(yīng)該算得上是Java生態(tài)系統(tǒng)中最完整的AOP框架了,。使用AOP之后我們可以把一些通用功能抽象出來,,在需要用到的地方直接使用即可,這樣可以大大簡化代碼量,。我們需要增加新功能也方便,,提高了系統(tǒng)的擴(kuò)展性。日志功能,、事務(wù)管理和權(quán)限管理等場景都用到了AOP,。

5、@Controller和@RestController有什么區(qū)別,?

這是個基礎(chǔ)性的問題,,但天天都在用,卻沒有關(guān)心過兩者的區(qū)別,。

@RestControllerspring 4.0.1版本后新增的內(nèi)容,,@Controllerspring 2.5.0版本后新增的內(nèi)容。兩者在實(shí)際使用中都用于定義控制層,,用于控制業(yè)務(wù)邏輯層的跳轉(zhuǎn),。

對比源碼可知@RestController相對@Controller增加了@RestponseBody注釋,。

@RestController相對于@Controller增加了@ResponseBody返回機(jī)制。相當(dāng)于@Controller+@ResponseBody兩個注解的結(jié)合,,返回json數(shù)據(jù)不需要在方法前面加@ResponseBody注解了,,但使用@RestController這個注解,就不能返回jsp,html頁面,,視圖解析器無法解析jsp,html頁面,。

6、熟悉Bean的生命周期嗎,?

造輪子必備,,寫碼業(yè)務(wù)代碼的基本上不太關(guān)心這種,但是面試被問概率卻是相當(dāng)?shù)母摺?/span>

首先說一下Servlet的生命周期:實(shí)例化,,初始init,,接收請求service,銷毀destroy,;

Spring上下文中的Bean生命周期也類似,,如下:

(1)實(shí)例化Bean:

對于BeanFactory容器,當(dāng)客戶向容器請求一個尚未初始化的bean時,,或初始化bean的時候需要注入另一個尚未初始化的依賴時,,容器就會調(diào)用createBean進(jìn)行實(shí)例化。對于ApplicationContext容器,,當(dāng)容器啟動結(jié)束后,,通過獲取BeanDefinition對象中的信息,實(shí)例化所有的bean,。

(2)設(shè)置對象屬性(依賴注入):

實(shí)例化后的對象被封裝在BeanWrapper對象中,,緊接著,Spring根據(jù)BeanDefinition中的信息 以及 通過BeanWrapper提供的設(shè)置屬性的接口完成依賴注入,。

(3)處理Aware接口:

接著,,Spring會檢測該對象是否實(shí)現(xiàn)了xxxAware接口,并將相關(guān)的xxxAware實(shí)例注入給Bean:

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

②如果這個Bean已經(jīng)實(shí)現(xiàn)了BeanFactoryAware接口,,會調(diào)用它實(shí)現(xiàn)的setBeanFactory()方法,,傳遞的是Spring工廠自身。

③如果這個Bean已經(jīng)實(shí)現(xiàn)了ApplicationContextAware接口,,會調(diào)用setApplicationContext(ApplicationContext)方法,,傳入Spring上下文;

(4)BeanPostProcessor:

如果想對Bean進(jìn)行一些自定義的處理,,那么可以讓Bean實(shí)現(xiàn)了BeanPostProcessor接口,,那將會調(diào)用postProcessBeforeInitialization(Object obj, String s)方法,。

(5)InitializingBean 與 init-method:

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

(6)如果這個Bean實(shí)現(xiàn)了BeanPostProcessor接口,,將會調(diào)用postProcessAfterInitialization(Object obj, String s)方法;由于這個方法是在Bean初始化結(jié)束時調(diào)用的,,所以可以被應(yīng)用于內(nèi)存或緩存技術(shù);

以上幾個步驟完成后,,Bean就已經(jīng)被正確創(chuàng)建了,,之后就可以使用這個Bean了。

(7)DisposableBean:

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

(8)destroy-method:

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


7,、說說Synchronized和ReentrantLock的區(qū)別

看樣子是在考察一個很平常的題目,但是面試官可能會因為你回答了兩者區(qū)別后,,引發(fā)其他相關(guān)問題,,也有可能葬送了大好機(jī)會。

相似點(diǎn)

這兩種同步方式有很多相似之處,,它們都是加鎖方式同步,,而且都是阻塞式的同步,也就是說當(dāng)如果一個線程獲得了對象鎖,,進(jìn)入了同步塊,,其他訪問該同步塊的線程都必須阻塞在同步塊外面等待,而進(jìn)行線程阻塞和喚醒的代價是比較高的.

區(qū)別

這兩種方式最大區(qū)別就是對于Synchronized來說,,它是java語言的關(guān)鍵字,,是原生語法層面的互斥,需要jvm實(shí)現(xiàn),。而ReentrantLock它是JDK 1.5之后提供的API層面的互斥鎖,,需要lock()和unlock()方法配合try/finally語句塊來完成。

synchronized經(jīng)過編譯,,會在同步塊的前后分別形成monitorenter和monitorexit這個兩個字節(jié)碼指令,。在執(zhí)行monitorenter指令時,首先要嘗試獲取對象鎖,。如果這個對象沒被鎖定,,或者當(dāng)前線程已經(jīng)擁有了那個對象鎖,,把鎖的計算器加1,,相應(yīng)的,,在執(zhí)行monitorexit指令時會將鎖計算器就減1,當(dāng)計算器為0時,,鎖就被釋放了,。如果獲取對象鎖失敗,,那當(dāng)前線程就要阻塞,直到對象鎖被另一個線程釋放為止,。

由于ReentrantLock是java.util.concurrent包下提供的一套互斥鎖,,相比Synchronized,ReentrantLock類提供了一些高級功能,,主要有以下3項:

1.等待可中斷,,持有鎖的線程長期不釋放的時候,正在等待的線程可以選擇放棄等待,,這相當(dāng)于Synchronized來說可以避免出現(xiàn)死鎖的情況,。

2.公平鎖,多個線程等待同一個鎖時,,必須按照申請鎖的時間順序獲得鎖,,Synchronized鎖非公平鎖,ReentrantLock默認(rèn)的構(gòu)造函數(shù)是創(chuàng)建的非公平鎖,,可以通過參數(shù)true設(shè)為公平鎖,,但公平鎖表現(xiàn)的性能不是很好。

3.鎖綁定多個條件,,一個ReentrantLock對象可以同時綁定對個對象,。

8、了解volatile關(guān)鍵字嗎,?

這種題目,,簡單也可以說,詳細(xì)點(diǎn)也可以說,,深層次的也可以說,。就看面試官需要你回答那個層次,。

一旦一個共享變量(類的成員變量,、類的靜態(tài)成員變量)被volatile修飾之后,那么就具備了兩層語義:

  • 1.保證了不同線程對這個變量進(jìn)行操作時的可見性,,即一個線程修改了某個變量的值,,這新值對其他線程來說是立即可見的。2.禁止進(jìn)行指令重排序,。
  • volatile本質(zhì)是在告訴jvm當(dāng)前變量在寄存器(工作內(nèi)存)中的值是不確定的,,需要從主存中讀?。籹ynchronized則是鎖定當(dāng)前變量,,只有當(dāng)前線程可以訪問該變量,,其他線程被阻塞住。
  • volatile僅能使用在變量級別,;synchronized則可以使用在變量,、方法、和類級別的,。
  • volatile僅能實(shí)現(xiàn)變量的修改可見性,,并不能保證原子性;synchronized則可以保證變量的修改可見性和原子性,。
  • volatile不會造成線程的阻塞,;synchronized可能會造成線程的阻塞,。

volatile標(biāo)記的變量不會被編譯器優(yōu)化,;synchronized標(biāo)記的變量可以被編譯器優(yōu)化。

9,、說說你對并發(fā)編程中CAS的理解

千萬別把并發(fā)編程中的CAS和單點(diǎn)登錄搞混了哈

CAS叫做CompareAndSwap,,比較并交換,主要是通過處理器的指令來保證操作的原子性,,它包含三個操作數(shù):

  1. 變量內(nèi)存地址,,V表示
  2. 舊的預(yù)期值,A表示
  3. 準(zhǔn)備設(shè)置的新值,,B表示

當(dāng)執(zhí)行CAS指令時,,只有當(dāng)V等于A時,才會用B去更新V的值,,否則就不會執(zhí)行更新操作,。

CAS的缺點(diǎn)主要有3點(diǎn)

ABA問題:ABA的問題指的是在CAS更新的過程中,當(dāng)讀取到的值是A,,然后準(zhǔn)備賦值的時候仍然是A,,但是實(shí)際上有可能A的值被改成了B,然后又被改回了A,,這個CAS更新的漏洞就叫做ABA,。只是ABA的問題大部分場景下都不影響并發(fā)的最終效果。

Java中有AtomicStampedReference來解決這個問題,,他加入了預(yù)期標(biāo)志和更新后標(biāo)志兩個字段,,更新時不光檢查值,還要檢查當(dāng)前的標(biāo)志是否等于預(yù)期標(biāo)志,,全部相等的話才會更新,。

循環(huán)時間長開銷大:自旋CAS的方式如果長時間不成功,,會給CPU帶來很大的開銷。

只能保證一個共享變量的原子操作:只對一個共享變量操作可以保證原子性,,但是多個則不行,,多個可以通過AtomicReference來處理或者使用鎖synchronized實(shí)現(xiàn)。

9,、線程有哪些狀態(tài),?

這個題目網(wǎng)上答案都有些差別,有的說是5個有的是6個,。很多是跟著別人寫,,但是寫偏了。五種有五種的說法,,六種有六種的說法,,我們是Java開發(fā),肯定關(guān)注的是Java中線程的狀態(tài),,并且在Thread類中有個內(nèi)部類State就是表示線程狀態(tài)的,,注釋里還有每個狀態(tài)的相關(guān)解釋。


Java中線程的狀態(tài)分為6種,。

  1. 初始(NEW):新創(chuàng)建了一個線程對象,,但還沒有調(diào)用start()方法。
  2. 運(yùn)行(RUNNABLE):Java線程中將就緒(ready)和運(yùn)行中(running)兩種狀態(tài)籠統(tǒng)的稱為“運(yùn)行”,。線程對象創(chuàng)建后,,其他線程(比如main線程)調(diào)用了該對象的start()方法。該狀態(tài)的線程位于可運(yùn)行線程池中,,等待被線程調(diào)度選中,,獲取CPU的使用權(quán),此時處于就緒狀態(tài)(ready),。就緒狀態(tài)的線程在獲得CPU時間片后變?yōu)檫\(yùn)行中狀態(tài)(running),。
  3. 阻塞(BLOCKED):表示線程阻塞于鎖。
  4. 等待(WAITING):進(jìn)入該狀態(tài)的線程需要等待其他線程做出一些特定動作(通知或中斷),。
  5. 超時等待(TIMED_WAITING):該狀態(tài)不同于WAITING,,它可以在指定的時間后自行返回。
  6. 終止(TERMINATED):表示該線程已經(jīng)執(zhí)行完畢,。

想獲取面試官的青睞,,還是得說說線程的狀態(tài)流轉(zhuǎn),可以根據(jù)下面這張圖來描述:


10,、有用過線程池嗎,?是怎么用的?

這個線程池在面試中也基本上是必問的題目。

有用過,,

創(chuàng)建線程有兩種方式

  • ThreadPoolExecutor
  • Executors

使用ThreadPoolExecutor是JDK原生態(tài)創(chuàng)建線程池,,也可以使用Executors工具類來創(chuàng)建線程池,并Executors大多數(shù)都是基于ThreadPoolExecutor進(jìn)行二次封裝,。

以下是Executors方式創(chuàng)建線程池的幾種方式:

  • newSingleThreadExecutor:創(chuàng)建一個單線程的線程池,,此線程池保證所有任務(wù)的執(zhí)行順序按照任務(wù)的提交順序執(zhí)行。
  • newFixedThreadPool:創(chuàng)建固定大小的線程池,,每次提交一個任務(wù)就創(chuàng)建一個線程,,直到線程達(dá)到線程池的最大大小。
  • newCachedThreadPool:創(chuàng)建一個可緩存的線程池,,此線程池不會對線程池大小做限制,,線程池大小完全依賴于操作系統(tǒng)(或者說JVM)能夠創(chuàng)建的最大線程大小。
  • newScheduledThreadPool:創(chuàng)建一個大小無限的線程池,,此線程池支持定時以及周期性執(zhí)行任務(wù)的需求,。
  • newSingleThreadExecutor:創(chuàng)建一個單線程的線程池。此線程池支持定時以及周期性執(zhí)行任務(wù)的需求,。
  • newWorkStealingPoo0l:Java 8 新增創(chuàng)建線程池的方法,,創(chuàng)建時如果不設(shè)置任何參數(shù),則以當(dāng)前機(jī)器CPU 處理器數(shù)作為線程個數(shù),,此線程池會并行處理任務(wù),,不能保證執(zhí)行順序,。

通常不建議使用Executors來創(chuàng)建線程池,,因為該方式中很多參數(shù)都已經(jīng)給你設(shè)置好了,所以在使用的時候,,如果使用不當(dāng)或者對參數(shù)沒有認(rèn)證考察可能會產(chǎn)生很多意想不到的問題:比如隊列多大,,造成OOM等。所以,,通常都建議使用ThreadPoolExecutor創(chuàng)建線程池,。

11、說說線程池中那幾個核心參數(shù)和含義

這道題目,,基本上快成必考面試題了,,不過我還是記住了,還有就是在某些面試中,,喜歡問線程池的原理,,其實(shí)也是側(cè)面的讓你講解線程池的這些核心參數(shù)的含義。

corePoolSize:核心線程數(shù)

線程池維護(hù)的最小線程數(shù)量,,核心線程創(chuàng)建后不會被回收(注意:設(shè)置allowCoreThreadTimeout=true后,,空閑的核心線程超過存活時間也會被回收)。

大于核心線程數(shù)的線程,在空閑時間超過keepAliveTime后會被回收,。

線程池剛創(chuàng)建時,,里面沒有一個線程,當(dāng)調(diào)用 execute() 方法添加一個任務(wù)時,,如果正在運(yùn)行的線程數(shù)量小于

corePoolSize,,則馬上創(chuàng)建新線程并運(yùn)行這個任務(wù)。

maximumPoolSize:最大線程數(shù)

線程池允許創(chuàng)建的最大線程數(shù)量,。

當(dāng)添加一個任務(wù)時,,核心線程數(shù)已滿,線程池還沒達(dá)到最大線程數(shù),,并且沒有空閑線程,,工作隊列已滿的情況下,創(chuàng)建一個新線程,,然后從工作隊列的頭部取出一個任務(wù)交由新線程來處理,,而將剛提交的任務(wù)放入工作隊列尾部。

keepAliveTime:空閑線程存活時間

當(dāng)一個可被回收的線程的空閑時間大于keepAliveTime,,就會被回收,。

可被回收的線程:

  1. 設(shè)置allowCoreThreadTimeout=true的核心線程。
  2. 大于核心線程數(shù)的線程(非核心線程),。

unit:時間單位

keepAliveTime的時間單位:

TimeUnit.NANOSECONDS
TimeUnit.MICROSECONDS
TimeUnit.MILLISECONDS // 毫秒
TimeUnit.SECONDS
TimeUnit.MINUTES
TimeUnit.HOURS
TimeUnit.DAYS

workQueue:工作隊列

新任務(wù)被提交后,,會先添加到工作隊列,任務(wù)調(diào)度時再從隊列中取出任務(wù),。工作隊列實(shí)現(xiàn)了BlockingQueue接口,。

JDK默認(rèn)的工作隊列有五種:

  1. ArrayBlockingQueue 數(shù)組型阻塞隊列:數(shù)組結(jié)構(gòu),初始化時傳入大小,,有界,,F(xiàn)IFO,使用一個重入鎖,,默認(rèn)使用非公平鎖,,入隊和出隊共用一個鎖,互斥,。
  2. LinkedBlockingQueue 鏈表型阻塞隊列:鏈表結(jié)構(gòu),,默認(rèn)初始化大小為Integer.MAX_VALUE,有界(近似無解),,F(xiàn)IFO,,使用兩個重入鎖分別控制元素的入隊和出隊,用Condition進(jìn)行線程間的喚醒和等待,。
  3. SynchronousQueue 同步隊列:容量為0,,添加任務(wù)必須等待取出任務(wù),,這個隊列相當(dāng)于通道,不存儲元素,。
  4. PriorityBlockingQueue 優(yōu)先阻塞隊列:無界,,默認(rèn)采用元素自然順序升序排列。
  5. DelayQueue 延時隊列:無界,,元素有過期時間,,過期的元素才能被取出。

threadFactory:線程工廠

創(chuàng)建線程的工廠,,可以設(shè)定線程名,、線程編號等。

12,、有了解過JVM嗎,?

沒有了解過JVM的,這道題是吱吱嗚嗚的,,瞎說一通,,然后尷尬的結(jié)束。

JVM是Java Virtual Machine(Java虛擬機(jī))的縮寫 ,,JVM在執(zhí)行Java程序時,,會把它管理的內(nèi)存劃分為若干個的區(qū)域,每個區(qū)域都有自己的用途和創(chuàng)建銷毀時間,。如下圖所示,,可以分為兩大部分,線程私有區(qū)和共享區(qū),。

下圖是根據(jù)自己理解畫的一個JVM內(nèi)存模型架構(gòu)圖:

JVM內(nèi)存分為線程私有區(qū)和線程共享區(qū),。

線程私有區(qū)

1、程序計數(shù)器

當(dāng)同時進(jìn)行的線程數(shù)超過CPU數(shù)或其內(nèi)核數(shù)時,,就要通過時間片輪詢分派CPU的時間資源,,不免發(fā)生線程切換,。這時,,每個線程就需要一個屬于自己的計數(shù)器來記錄下一條要運(yùn)行的指令。如果執(zhí)行的是JAVA方法,,計數(shù)器記錄正在執(zhí)行的java字節(jié)碼地址,,如果執(zhí)行的是native方法,則計數(shù)器為空,。

2,、虛擬機(jī)棧

線程私有的,與線程在同一時間創(chuàng)建,。管理JAVA方法執(zhí)行的內(nèi)存模型,。每個方法執(zhí)行時都會創(chuàng)建一個楨棧來存儲方法的的變量表,、操作數(shù)棧、動態(tài)鏈接方法,、返回值,、返回地址等信息。棧的大小決定了方法調(diào)用的可達(dá)深度(遞歸多少層次,,或嵌套調(diào)用多少層其他方法,,-Xss參數(shù)可以設(shè)置虛擬機(jī)棧大小),,棧的大小可以是固定也可以動態(tài)擴(kuò)展,。

如果請求的棧深度大于最大可用深度,則拋出stackOverflowError,;

如果棧是可動態(tài)擴(kuò)展的,,但沒有內(nèi)存空間支持?jǐn)U展,則拋出OutofMemoryError,。

使用jclasslib工具可以查看class類文件的結(jié)構(gòu),。下圖為棧幀結(jié)構(gòu)圖:


一個線程對應(yīng)一個虛擬機(jī)棧,一個虛擬機(jī)棧對應(yīng)多個棧幀,,每個棧幀的的入棧和出棧表示一個方法的調(diào)用,。

3、本地方法棧

與虛擬機(jī)棧作用相似,。但它不是為Java方法服務(wù)的,,而是本地方法(C語言)。由于規(guī)范對這塊沒有強(qiáng)制要求,,不同虛擬機(jī)實(shí)現(xiàn)方法不同,。

線程共享區(qū)

1、方法區(qū)

線程共享的,,用于存放被虛擬機(jī)加載的類的元數(shù)據(jù)信息,,如常量、靜態(tài)變量和即時編譯器編譯后的代碼,。若要分代,,算是永久代(老年代),以前類大多“static”的,,很少被卸載或收集,,現(xiàn)回收廢棄常量和無用的類。其中運(yùn)行時常量池存放編譯生成的各種常量,。(如果hotspot虛擬機(jī)確定一個類的定義信息不會被使用,,也會將其回收?;厥盏幕緱l件至少有:所有該類的實(shí)例被回收,,而且裝載該類的ClassLoader被回收),。

2、堆

存放對象實(shí)例和數(shù)組,,是垃圾回收的主要區(qū)域,,分為新生代和老年代。剛創(chuàng)建的對象在新生代的Eden區(qū)中,,經(jīng)過GC后進(jìn)入新生代的S0區(qū)中,,再經(jīng)過GC進(jìn)入新生代的S1區(qū)中,15次GC后仍存在就進(jìn)入老年代,。這是按照一種回收機(jī)制進(jìn)行劃分的,,不是固定的。若堆的空間不夠?qū)嵗峙?,則OutOfMemoryError,。

13、類加載機(jī)制是什么,?

更偏向于類裝載,,因為在描述這個過程的時候。,,第一步就是加載,,這樣更容易辨別。

JVM類加載分為5個過程:加載,,驗證,,準(zhǔn)備,解析,,初始化,,使用,卸載,,如下圖所示:

下面來看看加載,,驗證,準(zhǔn)備,,解析,,初始化這5個過程的具體動作。

加載

加載主要是將.class文件(并不一定是.class,??梢允荶IP包,網(wǎng)絡(luò)中獲?。┲械亩M(jìn)制字節(jié)流讀入到JVM中。在加載階段,,JVM需要完成3件事:1)通過類的全限定名獲取該類的二進(jìn)制字節(jié)流,;2)將字節(jié)流所代表的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時數(shù)據(jù)結(jié)構(gòu),;3)在內(nèi)存中生成一個該類的java.lang.Class對象,作為方法區(qū)這個類的各種數(shù)據(jù)的訪問入口,。

連接

驗證

驗證是連接階段的第一步,,主要確保加載進(jìn)來的字節(jié)流符合JVM規(guī)范。驗證階段會完成以下4個階段的檢驗動作:1)文件格式驗證 2)元數(shù)據(jù)驗證(是否符合Java語言規(guī)范) 3)字節(jié)碼驗證(確定程序語義合法,,符合邏輯) 4)符號引用驗證(確保下一步的解析能正常執(zhí)行)

準(zhǔn)備

主要為靜態(tài)變量在方法區(qū)分配內(nèi)存,,并設(shè)置默認(rèn)初始值。

解析

是虛擬機(jī)將常量池內(nèi)的符號引用替換為直接引用的過程,。

初始化

初始化階段是類加載過程的最后一步,,主要是根據(jù)程序中的賦值語句主動為類變量賦值。注:1)當(dāng)有父類且父類為初始化的時候,,先去初始化父類,;2)再進(jìn)行子類初始化語句。

14,、垃圾回收算法有哪些,?

我見過有的面試官,上來啥也不問,,直接問垃圾回收算法有哪些,,隨便看看,學(xué)學(xué)就知道了,。

GC最基礎(chǔ)的算法有三種:標(biāo)記 -清除算法,、復(fù)制算法、標(biāo)記-壓縮算法,。

我們常用的垃圾回收器一般都采用分代收集算法,,然后針對不同的代進(jìn)行使用不同的算法。

  • 標(biāo)記 -清除算法,,“標(biāo)記-清除”(Mark-Sweep)算法,,如它的名字一樣,算法分為“標(biāo)記”和“清除”兩個階段:首先標(biāo)記出所有需要回收的對象,,在標(biāo)記完成后統(tǒng)一回收掉所有被標(biāo)記的對象,。
  • 復(fù)制算法,“復(fù)制”(Copying)的收集算法,,它將可用內(nèi)存按容量劃分為大小相等的兩塊,,每次只使用其中的一塊。當(dāng)這一塊的內(nèi)存用完了,,就將還存活著的對象復(fù)制到另外一塊上面,,然后再把已使用過的內(nèi)存空間一次清理掉。
  • 標(biāo)記-壓縮算法,,標(biāo)記過程仍然與“標(biāo)記-清除”算法一樣,,但后續(xù)步驟不是直接對可回收對象進(jìn)行清理,,而是讓所有存活的對象都向一端移動,然后直接清理掉端邊界以外的內(nèi)存
  • 分代收集算法,,“分代收集”(Generational Collection)算法,,把Java堆分為新生代和老年代,這樣就可以根據(jù)各個年代的特點(diǎn)采用最適當(dāng)?shù)氖占惴ā?/section>

15,、熟悉哪些JVM調(diào)優(yōu)參數(shù),?

不能說我們要把下面的全部背下來,但是最起碼的堆相關(guān)參數(shù)的應(yīng)該有所知道,,肯定知道的越多越好,。

「堆棧內(nèi)存相關(guān)」

  • -Xms 設(shè)置初始堆的大小
  • -Xmx 設(shè)置最大堆的大小
  • -Xmn 設(shè)置年輕代大小,相當(dāng)于同時配置-XX:NewSize和-XX:MaxNewSize為一樣的值
  • -Xss  每個線程的堆棧大小
  • -XX:NewSize 設(shè)置年輕代大小(for 1.3/1.4)
  • -XX:MaxNewSize 年輕代最大值(for 1.3/1.4)
  • -XX:NewRatio 年輕代與年老代的比值(除去持久代)
  • -XX:SurvivorRatio Eden區(qū)與Survivor區(qū)的的比值
  • -XX:PretenureSizeThreshold 當(dāng)創(chuàng)建的對象超過指定大小時,,直接把對象分配在老年代,。
  • -XX:MaxTenuringThreshold設(shè)定對象在Survivor復(fù)制的最大年齡閾值,超過閾值轉(zhuǎn)移到老年代

「垃圾收集器相關(guān)」

-XX:+UseParallelGC:選擇垃圾收集器為并行收集器,。

  • -XX:ParallelGCThreads=20:配置并行收集器的線程數(shù)
  • -XX:+UseConcMarkSweepGC:設(shè)置年老代為并發(fā)收集,。
  • -XX:CMSFullGCsBeforeCompaction=5 由于并發(fā)收集器不對內(nèi)存空間進(jìn)行壓縮、整理,,所以運(yùn)行一段時間以后會產(chǎn)生“碎片”,,使得運(yùn)行效率降低。此值設(shè)置運(yùn)行5次GC以后對內(nèi)存空間進(jìn)行壓縮,、整理,。
  • -XX:+UseCMSCompactAtFullCollection:打開對年老代的壓縮??赡軙绊懶阅?,但是可以消除碎片

「輔助信息相關(guān)」

  • -XX:+PrintGCDetails 打印GC詳細(xì)信息
  • -XX:+HeapDumpOnOutOfMemoryError讓JVM在發(fā)生內(nèi)存溢出的時候自動生成內(nèi)存快照,排查問題用
  • -XX:+DisableExplicitGC禁止系統(tǒng)System.gc(),防止手動誤觸發(fā)FGC造成問題.
  • -XX:+PrintTLAB 查看TLAB空間的使用情況

16,、熟悉分布式鎖嗎,?有哪些實(shí)現(xiàn)方案?

變向的喜歡問,,你們項目中有用到分布式鎖嗎,?是怎么使用的,為什么這么使用,?這么使用會不會有問題,,有什么問題,遇到這問題了怎么解決,?

項目中有用到分布式鎖,,使用Zookeeper的實(shí)現(xiàn)方案。

分布式鎖實(shí)現(xiàn)方案,常見有如下幾種:

  • 基于表主鍵唯一做分布式鎖
  • 通過數(shù)據(jù)庫mvcc實(shí)現(xiàn)樂觀鎖
  • 基于Redis實(shí)現(xiàn)分布式鎖
  • 基于Redlock算法實(shí)現(xiàn)分布式鎖
  • 基于Zookeeper實(shí)現(xiàn)分布式鎖

17,、哪一種方案是最好的,?

沒有最好的方案,,只有相對最優(yōu)方案,。

1、Redis的分布式鎖中redisson一般為單實(shí)例,,當(dāng)單實(shí)例不可用時,,會阻塞業(yè)務(wù)流程。主從方式,、主從數(shù)據(jù)異步,,會存在鎖失效的問題。RedLock一般要求至少3臺以上的redis主從實(shí)例,,維護(hù)成本相對來說比較高,。

2、ZK鎖具備高可用,、可重入,、阻塞鎖特性,可解決失效死鎖問題,。但是因為需要頻繁的創(chuàng)建和刪除節(jié)點(diǎn),,性能上不如Redis方式。

3,、 ETCD分布式鎖的實(shí)現(xiàn)原理與zk鎖類似,,但是ETCD分布式鎖更加可靠強(qiáng)大。其Lease功能保證分布式鎖的安全性,;watch功能支持監(jiān)聽某個固定的key,,也支持watch一個范圍的key(前綴機(jī)制);revision功能可通過 Revision 的大小就可以知道進(jìn)行寫操作的順序,??梢员苊?“羊群效應(yīng)” (也稱 “驚群效應(yīng)”),實(shí)現(xiàn)公平鎖,。前綴機(jī)制與watch功能配合使用解決了死鎖問題,。總之ETCD的靈感來源于Zookeeper,,但實(shí)現(xiàn)的時候做了很多的改進(jìn),,如:高負(fù)載下的穩(wěn)定讀寫、數(shù)據(jù)模型的多版本并發(fā)控制,、穩(wěn)定的watch功能,,通知訂閱者監(jiān)聽值得變化、可以容忍腦裂現(xiàn)場的發(fā)生、客戶端的協(xié)議使用gRPC協(xié)議,支持go,、c++,、Java等。

4,、數(shù)據(jù)庫實(shí)現(xiàn)分布式鎖,,對數(shù)據(jù)庫表侵入較大,每個表需要增加version等字段,,高并發(fā)下存在很多更新失敗,。數(shù)據(jù)庫寫入是磁盤io,性能方面差一些,。數(shù)據(jù)庫能支持的最大QPS也有限制,,很難滿足高并發(fā)的需要。

總結(jié)

小伙伴本次面試中發(fā)揮的還是挺好的,,最終收獲offer,,恭喜這位朋友。

最后,,希望大家平時就算不面試,,也要為日后的面試做準(zhǔn)備,做一個能進(jìn)能退的人,。

機(jī)會總是留給有準(zhǔn)備的人,,加油!

    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多