更新時(shí)間:2019-10-04 09:00:00 來源:動(dòng)力節(jié)點(diǎn) 瀏覽2815次
多線程、并發(fā)及線程的基礎(chǔ)問題
1)Java中能創(chuàng)建volatile數(shù)組嗎?
能,Java中可以創(chuàng)建volatile類型數(shù)組,不過只是一個(gè)指向數(shù)組的引用,而不是整個(gè)數(shù)組。我的意思是,如果改變引用指向的數(shù)組,將會(huì)受到volatile的保護(hù),但是如果多個(gè)線程同時(shí)改變數(shù)組的元素,volatile標(biāo)示符就不能起到之前的保護(hù)作用了。
2)volatile能使得一個(gè)非原子操作變成原子操作嗎?
一個(gè)典型的例子是在類中有一個(gè)long類型的成員變量。如果你知道該成員變量會(huì)被多個(gè)線程訪問,如計(jì)數(shù)器、價(jià)格等,你最好是將其設(shè)置為volatile。為什么?因?yàn)镴ava中讀取long類型變量不是原子的,需要分成兩步,如果一個(gè)線程正在修改該long變量的值,另一個(gè)線程可能只能看到該值的一半(前32位)。但是對(duì)一個(gè)volatile型的long或double變量的讀寫是原子。
3)volatile修飾符的有過什么實(shí)踐?
一種實(shí)踐是用volatile修飾long和double變量,使其能按原子類型來讀寫。double和long都是64位寬,因此對(duì)這兩種類型的讀是分為兩部分的,第一次讀取第一個(gè)32位,然后再讀剩下的32位,這個(gè)過程不是原子的,但Java中volatile型的long或double變量的讀寫是原子的。volatile修復(fù)符的另一個(gè)作用是提供內(nèi)存屏障(memorybarrier),例如在分布式框架中的應(yīng)用。簡單的說,就是當(dāng)你寫一個(gè)volatile變量之前,Java內(nèi)存模型會(huì)插入一個(gè)寫屏障(writebarrier),讀一個(gè)volatile變量之前,會(huì)插入一個(gè)讀屏障(readbarrier)。意思就是說,在你寫一個(gè)volatile域時(shí),能保證任何線程都能看到你寫的值,同時(shí),在寫之前,也能保證任何數(shù)值的更新對(duì)所有線程是可見的,因?yàn)閮?nèi)存屏障會(huì)將其他所有寫的值更新到緩存。
4)volatile類型變量提供什么保證?
volatile變量提供順序和可見性保證,例如,JVM或者JIT為了獲得更好的性能會(huì)對(duì)語句重排序,但是volatile類型變量即使在沒有同步塊的情況下賦值也不會(huì)與其他語句重排序。volatile提供happens-before的保證,確保一個(gè)線程的修改能對(duì)其他線程是可見的。某些情況下,volatile還能提供原子性,如讀64位數(shù)據(jù)類型,像long和double都不是原子的,但volatile類型的double和long就是原子的。
5)10個(gè)線程和2個(gè)線程的同步代碼,哪個(gè)更容易寫?
從寫代碼的角度來說,兩者的復(fù)雜度是相同的,因?yàn)橥酱a與線程數(shù)量是相互獨(dú)立的。但是同步策略的選擇依賴于線程的數(shù)量,因?yàn)樵蕉嗟木€程意味著更大的競爭,所以你需要利用同步技術(shù),如鎖分離,這要求更復(fù)雜的代碼和專業(yè)知識(shí)。
6)你是如何調(diào)用wait()方法的?使用if塊還是循環(huán)?為什么?
wait()方法應(yīng)該在循環(huán)調(diào)用,因?yàn)楫?dāng)線程獲取到CPU開始執(zhí)行的時(shí)候,其他條件可能還沒有滿足,所以在處理前,循環(huán)檢測條件是否滿足會(huì)更好。下面是一段標(biāo)準(zhǔn)的使用wait和notify方法的代碼:
//Thestandardidiomforusingthewaitmethod
synchronized(obj){
while(conditiondoesnothold)
obj.wait();//(Releaseslock,andreacquiresonwakeup)
...//Performactionappropriatetocondition
}
7)什么是多線程環(huán)境下的偽共享(falsesharing)?
偽共享是多線程系統(tǒng)(每個(gè)處理器有自己的局部緩存)中一個(gè)眾所周知的性能問題。偽共享發(fā)生在不同處理器的上的線程對(duì)變量的修改依賴于相同的緩存行,如下圖所示:

有經(jīng)驗(yàn)程序員的Java面試題
偽共享問題很難被發(fā)現(xiàn),因?yàn)榫€程可能訪問完全不同的全局變量,內(nèi)存中卻碰巧在很相近的位置上。如其他諸多的并發(fā)問題,避免偽共享的最基本方式是仔細(xì)審查代碼,根據(jù)緩存行來調(diào)整你的數(shù)據(jù)結(jié)構(gòu)。
8)什么是Busyspin?我們?yōu)槭裁匆褂盟?/p>
Busyspin是一種在不釋放CPU的基礎(chǔ)上等待事件的技術(shù)。它經(jīng)常用于避免丟失CPU緩存中的數(shù)據(jù)(如果線程先暫停,之后在其他CPU上運(yùn)行就會(huì)丟失)。所以,如果你的工作要求低延遲,并且你的線程目前沒有任何順序,這樣你就可以通過循環(huán)檢測隊(duì)列中的新消息來代替調(diào)用sleep()或wait()方法。它唯一的好處就是你只需等待很短的時(shí)間,如幾微秒或幾納秒。LMAX分布式框架是一個(gè)高性能線程間通信的庫,該庫有一個(gè)BusySpinWaitStrategy類就是基于這個(gè)概念實(shí)現(xiàn)的,使用busyspin循環(huán)EventProcessors等待屏障。
9)Java中怎么獲取一份線程dump文件?
在Linux下,你可以通過命令kill-3PID(Java進(jìn)程的進(jìn)程ID)來獲取Java應(yīng)用的dump文件。在Windows下,你可以按下Ctrl+Break來獲取。這樣JVM就會(huì)將線程的dump文件打印到標(biāo)準(zhǔn)輸出或錯(cuò)誤文件中,它可能打印在控制臺(tái)或者日志文件中,具體位置依賴應(yīng)用的配置。如果你使用Tomcat。
10)Swing是線程安全的?
不是,Swing不是線程安全的。你不能通過任何線程來更新Swing組件,如JTable、JList或JPanel,事實(shí)上,它們只能通過GUI或AWT線程來更新。這就是為什么Swing提供invokeAndWait()和invokeLater()方法來獲取其他線程的GUI更新請(qǐng)求。這些方法將更新請(qǐng)求放入AWT的線程隊(duì)列中,可以一直等待,也可以通過異步更新直接返回結(jié)果。你也可以在參考答案中查看和學(xué)習(xí)到更詳細(xì)的內(nèi)容。
11)什么是線程局部變量?
線程局部變量是局限于線程內(nèi)部的變量,屬于線程自身所有,不在多個(gè)線程間共享。Java提供ThreadLocal類來支持線程局部變量,是一種實(shí)現(xiàn)線程安全的方式。但是在管理環(huán)境下(如web服務(wù)器)使用線程局部變量的時(shí)候要特別小心,在這種情況下,工作線程的生命周期比任何應(yīng)用變量的生命周期都要長。任何線程局部變量一旦在工作完成后沒有釋放,Java應(yīng)用就存在內(nèi)存泄露的風(fēng)險(xiǎn)。
12)用wait-notify寫一段代碼來解決生產(chǎn)者-消費(fèi)者問題?
請(qǐng)參考答案中的示例代碼。只要記住在同步塊中調(diào)用wait()和notify()方法,如果阻塞,通過循環(huán)來測試等待條件。
13)用Java寫一個(gè)線程安全的單例模式(Singleton)?
請(qǐng)參考答案中的示例代碼,這里面一步一步教你創(chuàng)建一個(gè)線程安全的Java單例類。當(dāng)我們說線程安全時(shí),意思是即使初始化是在多線程環(huán)境中,仍然能保證單個(gè)實(shí)例。Java中,使用枚舉作為單例類是最簡單的方式來創(chuàng)建線程安全單例模式的方式。
14)Java中sleep方法和wait方法的區(qū)別?
雖然兩者都是用來暫停當(dāng)前運(yùn)行的線程,但是sleep()實(shí)際上只是短暫停頓,因?yàn)樗粫?huì)釋放鎖,而wait()意味著條件等待,這就是為什么該方法要釋放鎖,因?yàn)橹挥羞@樣,其他等待的線程才能在滿足條件時(shí)獲取到該鎖。
15)什么是不可變對(duì)象(immutableobject)?Java中怎么創(chuàng)建一個(gè)不可變對(duì)象?
不可變對(duì)象指對(duì)象一旦被創(chuàng)建,狀態(tài)就不能再改變。任何修改都會(huì)創(chuàng)建一個(gè)新的對(duì)象,如String、Integer及其它包裝類。詳情參見答案,一步一步指導(dǎo)你在Java中創(chuàng)建一個(gè)不可變的類。
16)我們能創(chuàng)建一個(gè)包含可變對(duì)象的不可變對(duì)象嗎?
是的,我們是可以創(chuàng)建一個(gè)包含可變對(duì)象的不可變對(duì)象的,你只需要謹(jǐn)慎一點(diǎn),不要共享可變對(duì)象的引用就可以了,如果需要變化時(shí),就返回原對(duì)象的一個(gè)拷貝。最常見的例子就是對(duì)象中包含一個(gè)日期對(duì)象的引用。
數(shù)據(jù)類型和Java基礎(chǔ)面試問題
17)Java中應(yīng)該使用什么數(shù)據(jù)類型來代表價(jià)格?
如果不是特別關(guān)心內(nèi)存和性能的話,使用BigDecimal,否則使用預(yù)定義精度的double類型。
18)怎么將byte轉(zhuǎn)換為String?
可以使用String接收byte[]參數(shù)的構(gòu)造器來進(jìn)行轉(zhuǎn)換,需要注意的點(diǎn)是要使用的正確的編碼,否則會(huì)使用平臺(tái)默認(rèn)編碼,這個(gè)編碼可能跟原來的編碼相同,也可能不同。
19)Java中怎樣將bytes轉(zhuǎn)換為long類型?
這個(gè)問題你來回答:-)
20)我們能將int強(qiáng)制轉(zhuǎn)換為byte類型的變量嗎?如果該值大于byte類型的范圍,將會(huì)出現(xiàn)什么現(xiàn)象?
是的,我們可以做強(qiáng)制轉(zhuǎn)換,但是Java中int是32位的,而byte是8位的,所以,如果強(qiáng)制轉(zhuǎn)化是,int類型的高24位將會(huì)被丟棄,byte類型的范圍是從-128到128。
3年工作經(jīng)驗(yàn)的Java面試題
21解釋Java堆空間及GC?
當(dāng)通過Java命令啟動(dòng)Java進(jìn)程的時(shí)候,會(huì)為它分配內(nèi)存。內(nèi)存的一部分用于創(chuàng)建堆空間,當(dāng)程序中創(chuàng)建對(duì)象的時(shí)候,就從對(duì)空間中分配內(nèi)存。GC是JVM內(nèi)部的一個(gè)進(jìn)程,回收無效對(duì)象的內(nèi)存用于將來的分配。

JVM底層面試題及答案
22)你能保證GC執(zhí)行嗎?
不能,雖然你可以調(diào)用System.gc()或者Runtime.gc(),但是沒有辦法保證GC的執(zhí)行。
23)怎么獲取Java程序使用的內(nèi)存?堆使用的百分比?
可以通過java.lang.Runtime類中與內(nèi)存相關(guān)方法來獲取剩余的內(nèi)存,總內(nèi)存及最大堆內(nèi)存。通過這些方法你也可以獲取到堆使用的百分比及堆內(nèi)存的剩余空間。Runtime.freeMemory()方法返回剩余空間的字節(jié)數(shù),Runtime.totalMemory()方法總內(nèi)存的字節(jié)數(shù),Runtime.maxMemory()返回最大內(nèi)存的字節(jié)數(shù)。
24)Java中堆和棧有什么區(qū)別?
JVM中堆和棧屬于不同的內(nèi)存區(qū)域,使用目的也不同。棧常用于保存方法幀和局部變量,而對(duì)象總是在堆上分配。棧通常都比堆小,也不會(huì)在多個(gè)線程之間共享,而堆被整個(gè)JVM的所有線程共享。

關(guān)于內(nèi)存的的面試問題和答案
Java基本概念面試題
25)“a==b”和”a.equals(b)”有什么區(qū)別?
如果a和b都是對(duì)象,則a==b是比較兩個(gè)對(duì)象的引用,只有當(dāng)a和b指向的是堆中的同一個(gè)對(duì)象才會(huì)返回true,而a.equals(b)是進(jìn)行邏輯比較,所以通常需要重寫該方法來提供邏輯一致性的比較。例如,String類重寫equals()方法,所以可以用于兩個(gè)不同對(duì)象,但是包含的字母相同的比較。
25)a.hashCode()有什么用?與a.equals(b)有什么關(guān)系?
hashCode()方法是相應(yīng)對(duì)象整型的hash值。它常用于基于hash的集合類,如Hashtable、HashMap、LinkedHashMap等等。它與equals()方法關(guān)系特別緊密。根據(jù)Java規(guī)范,兩個(gè)使用equal()方法來判斷相等的對(duì)象,必須具有相同的hashcode。
26)final、finalize和finally的不同之處?
final是一個(gè)修飾符,可以修飾變量、方法和類。如果final修飾變量,意味著該變量的值在初始化后不能被改變。finalize方法是在對(duì)象被回收之前調(diào)用的方法,給對(duì)象自己最后一個(gè)復(fù)活的機(jī)會(huì),但是什么時(shí)候調(diào)用finalize沒有保證。finally是一個(gè)關(guān)鍵字,與try和catch一起用于異常的處理。finally塊一定會(huì)被執(zhí)行,無論在try塊中是否有發(fā)生異常。
27)Java中的編譯期常量是什么?使用它又什么風(fēng)險(xiǎn)?
公共靜態(tài)不可變(publicstaticfinal)變量也就是我們所說的編譯期常量,這里的public可選的。實(shí)際上這些變量在編譯時(shí)會(huì)被替換掉,因?yàn)榫幾g器知道這些變量的值,并且知道這些變量在運(yùn)行時(shí)不能改變。這種方式存在的一個(gè)問題是你使用了一個(gè)內(nèi)部的或第三方庫中的公有編譯時(shí)常量,但是這個(gè)值后面被其他人改變了,但是你的客戶端仍然在使用老的值,甚至你已經(jīng)部署了一個(gè)新的jar。為了避免這種情況,當(dāng)你在更新依賴JAR文件時(shí),確保重新編譯你的程序。
Java集合框架的面試題
這部分也包含數(shù)據(jù)結(jié)構(gòu)、算法及數(shù)組的面試問題
28)List、Set、Map和Queue之間的區(qū)別
List是一個(gè)有序集合,允許元素重復(fù)。它的某些實(shí)現(xiàn)可以提供基于下標(biāo)值的常量訪問時(shí)間,但是這不是List接口保證的。Set是一個(gè)無序集合。
29)poll()方法和remove()方法的區(qū)別?
poll()和remove()都是從隊(duì)列中取出一個(gè)元素,但是poll()在獲取元素失敗的時(shí)候會(huì)返回空,但是remove()失敗的時(shí)候會(huì)拋出異常。
30)Java中LinkedHashMap和PriorityQueue的區(qū)別是什么?
PriorityQueue保證最高或者最低優(yōu)先級(jí)的的元素總是在隊(duì)列頭部,但是LinkedHashMap維持的順序是元素插入的順序。當(dāng)遍歷一個(gè)PriorityQueue時(shí),沒有任何順序保證,但是LinkedHashMap課保證遍歷順序是元素插入的順序。
31)ArrayList與LinkedList的不區(qū)別?
最明顯的區(qū)別是ArrrayList底層的數(shù)據(jù)結(jié)構(gòu)是數(shù)組,支持隨機(jī)訪問,而LinkedList的底層數(shù)據(jù)結(jié)構(gòu)書鏈表,不支持隨機(jī)訪問。使用下標(biāo)訪問一個(gè)元素,ArrayList的時(shí)間復(fù)雜度是O(1),而LinkedList是O(n)。更多細(xì)節(jié)的討論參見答案。
32)用哪兩種方式來實(shí)現(xiàn)集合的排序?
你可以使用有序集合,如TreeSet或TreeMap,你也可以使用有順序的的集合,如list,然后通過Collections.sort()來排序。
33)Java中怎么打印數(shù)組?
你可以使用Arrays.toString()和Arrays.deepToString()方法來打印數(shù)組。由于數(shù)組沒有實(shí)現(xiàn)toString()方法,所以如果將數(shù)組傳遞給System.out.println()方法,將無法打印出數(shù)組的內(nèi)容,但是Arrays.toString()可以打印每個(gè)元素。
34)Java中的LinkedList是單向鏈表還是雙向鏈表?
是雙向鏈表,你可以檢查JDK的源碼。在Eclipse,你可以使用快捷鍵Ctrl+T,直接在編輯器中打開該類。
35)Java中的TreeMap是采用什么樹實(shí)現(xiàn)的?
Java中的TreeMap是使用紅黑樹實(shí)現(xiàn)的。
36)Hashtable與HashMap有什么不同之處?
這兩個(gè)類有許多不同的地方,下面列出了一部分:
a)Hashtable是JDK1遺留下來的類,而HashMap是后來增加的。
b)Hashtable是同步的,比較慢,但HashMap沒有同步策略,所以會(huì)更快。
c)Hashtable不允許有個(gè)空的key,但是HashMap允許出現(xiàn)一個(gè)nullkey。
更多的不同之處參見答案。
37)Java中的HashSet,內(nèi)部是如何工作的?
HashSet的內(nèi)部采用HashMap來實(shí)現(xiàn)。由于Map需要key和value,所以所有key的都有一個(gè)默認(rèn)value。類似于HashMap,HashSet不允許重復(fù)的key,只允許有一個(gè)nullkey,意思就是HashSet中只允許存儲(chǔ)一個(gè)null對(duì)象。
38)寫一段代碼在遍歷ArrayList時(shí)移除一個(gè)元素?
該問題的關(guān)鍵在于面試者使用的是ArrayList的remove()還是Iterator的remove()方法。這有一段示例代碼,是使用正確的方式來實(shí)現(xiàn)在遍歷的過程中移除元素,而不會(huì)出現(xiàn)ConcurrentModificationException異常的示例代碼。
39)我們能自己寫一個(gè)容器類,然后使用for-each循環(huán)碼?
可以,你可以寫一個(gè)自己的容器類。如果你想使用Java中增強(qiáng)的循環(huán)來遍歷,你只需要實(shí)現(xiàn)Iterable接口。如果你實(shí)現(xiàn)Collection接口,默認(rèn)就具有該屬性。
40)ArrayList和HashMap的默認(rèn)大小是多數(shù)?
在Java7中,ArrayList的默認(rèn)大小是10個(gè)元素,HashMap的默認(rèn)大小是16個(gè)元素(必須是2的冪)。這就是Java7中ArrayList和HashMap類的代碼片段:
//fromArrayList.javaJDK1.7
privatestaticfinalintDEFAULT_CAPACITY=10;
//fromHashMap.javaJDK7
staticfinalintDEFAULT_INITIAL_CAPACITY=1<<4;//aka16
41)有沒有可能兩個(gè)不相等的對(duì)象有有相同的hashcode?
有可能,兩個(gè)不相等的對(duì)象可能會(huì)有相同的hashcode值,這就是為什么在hashmap中會(huì)有沖突。相等hashcode值的規(guī)定只是說如果兩個(gè)對(duì)象相等,必須有相同的hashcode值,但是沒有關(guān)于不相等對(duì)象的任何規(guī)定。
42)兩個(gè)相同的對(duì)象會(huì)有不同的的hashcode嗎?
不能,根據(jù)hashcode的規(guī)定,這是不可能的。
43)我們可以在hashcode()中使用隨機(jī)數(shù)字嗎?
不行,因?yàn)閷?duì)象的hashcode值必須是相同的。參見答案獲取更多關(guān)于Java中重寫hashCode()方法的知識(shí)。
44)Java中,Comparator與Comparable有什么不同?
Comparable接口用于定義對(duì)象的自然順序,而comparator通常用于定義用戶定制的順序。Comparable總是只有一個(gè),但是可以有多個(gè)comparator來定義對(duì)象的順序。
45)為什么在重寫equals方法的時(shí)候需要重寫hashCode方法?
因?yàn)橛袕?qiáng)制的規(guī)范指定需要同時(shí)重寫hashcode與equal是方法,許多容器類,如HashMap、HashSet都依賴于hashcode與equals的規(guī)定。
以上就是動(dòng)力節(jié)點(diǎn)java培訓(xùn)機(jī)構(gòu)小編分享的“開發(fā)多年中級(jí)程序員面試題經(jīng)驗(yàn)總結(jié)”的內(nèi)容,希望對(duì)大家有幫助,更多java面試題請(qǐng)繼續(xù)關(guān)注動(dòng)力節(jié)點(diǎn)java培訓(xùn)機(jī)構(gòu)官網(wǎng),每天會(huì)精彩內(nèi)容分享與你。
相關(guān)java面試題推薦
2019最新最全java面試題及答案:http://www.soulsinkind.com/tutorial_baseinterviewquestions/
Java常見面試題匯總:http://www.soulsinkind.com/javazixun/1007.html
2019最新java面試題含答案(基礎(chǔ)篇):http://www.soulsinkind.com/javazixun/1145.html
各大互聯(lián)網(wǎng)公司Java面試題匯總:http://www.soulsinkind.com/javazixun/1867.html
2019最新Java常見面試題(附帶答案):http://www.soulsinkind.com/javazixun/891.html
常被問到的Java面試題(帶全部答案):http://www.soulsinkind.com/javazixun/886.html
相關(guān)閱讀
Java實(shí)驗(yàn)班
0基礎(chǔ) 0學(xué)費(fèi) 15天面授
Java就業(yè)班
有基礎(chǔ) 直達(dá)就業(yè)
Java夜校直播班
業(yè)余時(shí)間 高薪轉(zhuǎn)行
Java在職加薪班
工作1~3年,加薪神器
Java架構(gòu)師班
工作3~5年,晉升架構(gòu)
提交申請(qǐng)后,顧問老師會(huì)電話與您溝通安排學(xué)習(xí)