1.private 修飾的方法可以通過反射訪問窍荧,那么private修飾的意義在哪里如庭?
因為private本職上是一種編程思想的體現(xiàn)茂附,即封裝的思想拍顷,用private修飾的變量和方法本質(zhì)上都是不對外提供的抚太,那么對于調(diào)用者來說,這些就是不可見的,所以它并不對這個事情負責尿贫;尤其是在一個大型工程里面來說电媳,各個模塊的業(yè)務(wù)范疇的定義是需要非常明確的,不歸自己管的絕對不想管庆亡,所以如果我定義了一個private匆背,那就意味著你盡量別用,如果你非得用身冀,那么好钝尸,出了問題你負責,我不管的搂根。
2.Java的類初始化順序
總的原則就是先基類后自己珍促,先靜態(tài)后普通代碼塊后構(gòu)造函數(shù):
所以,基類的靜態(tài)字段和靜態(tài)代碼塊-->>派生類的靜態(tài)代碼塊-->>基類普通代碼塊和基類普通成員變量-->>基類構(gòu)造函數(shù)-->>派生類普通代碼塊-->>派生類構(gòu)造函數(shù)
至于為什么先基類后自己剩愧,這個是很容易想明白的猪叙,因為加入我派生類依賴基類的某個變量,那肯定是要先基類準備好了仁卷,自己再去是更好的穴翩。而為什么先靜態(tài)后普通代碼塊呢?我個人理解锦积,是因為靜態(tài)變量是屬于某個類的芒帕,只要這個類被使用了,靜態(tài)的就要先加載丰介,至于后面實例化的哪個背蟆,它不管的。
3.對方法區(qū)和永久區(qū)的理解以及它們之間的關(guān)系
方法區(qū)是jvm規(guī)范里要求的哮幢,永久區(qū)是Hotspot虛擬機對方法區(qū)的具體實現(xiàn)带膀,前者是規(guī)范,后者是實現(xiàn)方式橙垢。而Java8其實又做了修改垛叨,已經(jīng)不再有永久區(qū)了,而是metaspace柜某;
4.一個java文件有3個類嗽元,編譯后有幾個class文件
這個應(yīng)該是有三個文件才是。
5.局部變量使用前需要顯式地賦值莺琳,否則編譯通過不了还棱,為什么這么設(shè)計
因為編譯器識別不出成員變量究竟會在啥時候使用和賦值,所以可以給個默認值惭等,但是局部變量是很明顯的珍手,所以這種時候編譯器給出這種約束可以極大的避免一些問題的產(chǎn)生。
6.ReadWriteLock讀寫之間互斥嗎
讀鎖和讀鎖之間不互斥,其他都是互斥的琳要。
讀寫鎖其實是有兩個鎖寡具,一個讀,一個寫稚补,他們共享同一個sync童叠,但是分別用的是共享模式和非共享模式,這個是用state的頭16位和尾16位去做的课幕。
7.Semaphore拿到執(zhí)行權(quán)的線程之間是否互斥
不是互斥的厦坛。
8.寫一個單例模式
public class Singleton{
private static class SingltonHandler{
private staticSingleton singleton=new Singleton();
?? }
publicstaticSingletongetInstance() {
return SingltonHandler.singleton;
?? }
}
最簡單的寫法就是靜態(tài)內(nèi)部類,靜態(tài)內(nèi)部類維護一個外部的變量乍惊,而不用的時候也不會去加載它杜秸。
9.B樹和B+樹是解決什么樣的問題的,怎樣演化過來润绎,之間區(qū)別
B+樹和B樹之間的核心區(qū)別就在于撬碟,mysql的每個節(jié)點是存儲在一個頁上面的,而對于B樹來說每個頁所存儲的數(shù)據(jù)包含三個部分(key莉撇,子節(jié)點指針和data)呢蛤,所以我們希望每個頁上存儲更多的子節(jié)點這樣能夠保證B樹更大的度,也就帶來了更小的樹深度棍郎,所以這就是為什么B+樹把真實的data都放在葉子節(jié)點上的原因其障;
10.寫一個生產(chǎn)者消費者模式
可以用lock和condition或者wait+notify的方式來寫;
11.寫一個死鎖
這個很簡單坝撑,兩個線程互斥的取兩份資源即可静秆;
12.cpu的100%定位
先找到top進程粮揉,然后jstack巡李,然后找這個進程中的top線程,最后轉(zhuǎn)換下16進制就好了扶认;
13.int a=1是原子操作嗎侨拦?
是的,a++不是辐宾,long 不是狱从,long被volatile修飾就是了
14.for循環(huán)可以刪除arraylist嗎?
不可以叠纹,因為刪除元素時涉及到數(shù)組元素的移動季研。
15.新的任務(wù)提交到線程池,線程池是怎樣處理
這個其實是個考察線程池原理的問題誉察,線程池包含核心線程數(shù)与涡,最大線程數(shù),和隊列,一般如果沒有到核心線程數(shù)驼卖,會擴大核心線程數(shù)氨肌,如果是超過核心線程數(shù),不到隊列數(shù)酌畜,會加到隊列里怎囚,如果是超過了隊列+核心線程數(shù),會擴容到最大線程數(shù)桥胞,最后恳守,都不行,會執(zhí)行拒絕策略贩虾;
16.AQS和CAS原理
CAS待梳理井誉;
17.synchronized底層實現(xiàn)原理
是在Java對象的頭上mark word里面存放的有:
鎖狀態(tài) 對象的hashcode 對象分代年齡 是否是偏向鎖 鎖標志位
鎖一共有四種狀態(tài),從低到高分別是:無鎖整胃、偏向鎖颗圣、輕量級鎖和重量級鎖,會隨著競爭情況逐漸升級但只能升級不能降級屁使。
偏向鎖是在棧幀中記錄擁有偏向鎖的線程id在岂,如果是同個線程則直接獲取,如果不是同個線程蛮寂,那此線程會失敗蔽午,并且通知這個偏向鎖撤銷;
重點看下鎖升級:
偏向鎖:如果有其他線程競爭鎖酬蹋,而且此時鎖的擁有者還無法釋放的時候及老,就會升級為輕量級鎖;
輕量級自選鎖:如果自旋次數(shù)超過了某個閾值范抓,或者線程1在執(zhí)行骄恶,線程2在自旋等待,線程3又過來競爭的時候匕垫,就膨脹成重量級鎖僧鲁;
18.volatile的作用
防止指令重排,可見性象泵;
提到volatile就不得不說操作系統(tǒng)的解決各個cpu的高速緩存之間的緩存一致性的問題的思路寞秃,
1.在總線上加lock,但是這種的話各個cpu都阻塞了偶惠;
2.緩存一致性協(xié)議春寿,如果發(fā)現(xiàn)操作的是共享變量,那就通知其他的cpu讓這個緩存失效忽孽,這也就是會引發(fā)所謂的一致性協(xié)議風(fēng)暴和緩存行失效的問題绑改,也就是為什么要用clh隊列做aqs的問題馋缅。
19.AOP和IOC原理
待梳理;
20.Spring怎樣解決循環(huán)依賴的問題
利用緩存绢淀,先提前把各個bean暴露出去萤悴;
22.dispatchServlet是怎樣分發(fā)任務(wù)的?
mvc待整理皆的;
23.jvm gc復(fù)制算法
24.注解的原理
25.進程間通信方式覆履;
26.Reentrantlock是可重入鎖,啥是可重入费薄?
就是可以同一個線程進入兩次硝全,這個取決于它的實現(xiàn),tryacquire的時候楞抡,發(fā)現(xiàn)如果當前線程和占領(lǐng)它的鎖的線程是同個線程伟众,就會直接獲取鎖;
27.線程如果異常會怎樣召廷?
線程的異常必須要線程自身去捕獲并處理凳厢,如果不處理,這個線程會死掉竞慢,而且先紫,這個線程的異常并不會被主線程所捕獲;
28.hashMap原理筹煮;
1.8以后版本:
1.7以前的版本就不看了遮精,因為目前核心重點在關(guān)注的就是1.8了,首先還是一個鏈表或者叫數(shù)組吧败潦,然后每個節(jié)點上下面不一定是鏈表了本冲,還有可能是紅黑樹,這個閾值是8劫扒;
先看put檬洞,如果不存在,直接插入就好粟关,然后如果存在疮胖,那就進入到里面去,先取出對應(yīng)位置的值放著闷板;
首先如果是紅黑樹,直接插進去院塞,如果是鏈表遮晚,先插進去,再轉(zhuǎn)換成紅黑樹拦止。
最后判斷這取出的node是不是空县遣,如果不空糜颠,覆蓋掉它的value;
最后萧求,如果整個的值超過了閾值其兴,就擴容;
關(guān)于擴容:
第一步:把數(shù)組擴大到兩倍夸政,把閾值擴大到兩倍
第二步:把原有的數(shù)據(jù)放到新的數(shù)組里元旬,需要重新做hash,注意守问,這里的hash用的還是很巧妙的匀归,它用的是hashcode&&table.size()-1 ,這樣其實就把這個值散列到表的每個位置上面去耗帕,所以就也要求這個表的size必須要是powerof 2穆端;說起來如何判斷一個數(shù)字是powerof2也有個巧妙的方法,就是直接n&&(n-1)==0仿便;
至于concurrentHashmap体啰,最難的地方在于擴容,擴容的過程是這樣的:先把這個擴容的過程分成多個子任務(wù)嗽仪,然后每個子任務(wù)去做各自的擴容狡赐;
29.jvm虛擬機;
30.Java類加載和雙親委派
其實整個類加載有個非常核心的關(guān)鍵之處钦幔,就在于Java把獲取class信息轉(zhuǎn)換成byte數(shù)組這一步驟外包出去了枕屉,就是它不管你從哪里獲取這個byte數(shù)組,你完全可以自行獲取鲤氢,這樣才引出了各種各樣的類加載器和雙親委派的類加載機制搀擂。
Java有兩類加載器,一類是系統(tǒng)提供的卷玉,另外一類是自定義的:
系統(tǒng)提供的有三個:
bootstrap :負責加載核心類庫的
extension:擴展庫的ext
app:classPath下的哨颂;
所謂SPI,其實就是自己定義好了interface相种,但是不實現(xiàn)威恼,讓別人來實現(xiàn),但是這里有幾個問題:
1.別人的實現(xiàn)你怎么知道在哪兒呢寝并?
那就放在固定的地方去META/INF底下箫措,讀取某個約定好的位置的信息,然后取出來看看叫啥名字
2.自己的類可能是引導(dǎo)類加載器加載的衬潦,而別人的實現(xiàn)無法用引導(dǎo)類加載器加載斤蔓?
Java 應(yīng)用運行的初始線程的上下文類加載器是系統(tǒng)類加載器。在線程中運行的代碼可以通過此類加載器來加載類和資源镀岛。