jav面試(十五)--(1)請談一談ClassLoader(類加載器), 以及對雙親委派模型理解(2)JVM內存(3)JAVA鎖(4)ThreadLocal

1.請談一談ClassLoader(類加載器), 以及對雙親委派模型理解

從java虛擬機的角度講,只有兩種不同的類加載器:一種是啓動類加載器(Bootstrap ClassLoader),這個類加載器使用的是c++實現的,是虛擬機的一部分,另一類就是所有其他類加載器,這些類加載器都由java語言實現,獨立於虛擬機外部,並且全都繼承自抽象類。
從開發人員的角度看,類加載器還可以劃分爲3種系統類加載器:
啓動類加載器(Bootstrap ClassLoader),負責加載存放在<JAVA_HOME>/lib目錄中的,或者被-Xbootclasspath參數所指定的路徑中的,並且是虛擬機識別的(僅按照文件名識別,如rt.jar,名字不符的類庫即使放在lib目錄中也不會被加載)類庫加載到虛擬機中內存中。啓動類加載器無法被java程序直接引用,用戶在編寫自定義類加載器是,如果需要把加載請求委派給引導類加載器,那直接使用null代替即可。

擴展類加載器(Extension ClassLoader):這個類加載器有sun.misc.Launcher$ExtClassLoader實現,負責加載<JAVA_HOME>/lib/ext目錄中的,或者被java.ext.dirs系統變量所指定的路徑中的所有類庫,開發者可以直接使用擴展類加載器。

應用類加載器(Application ClassLoader):這個類加載器由sun.misc.Launcher$AppClassLoader實現。由於這個類加載器是ClassLoader中的getSystemClassLoader()方法的返回值,所以也稱它爲系統類加載器(System ClassLoader)。他負責加載用戶類路徑(ClassPath)上所指定的類庫,開發者可以直接使用這個類加載器,如果應用程序中沒有自定義過自己的類加載器,一般情況下這個就是程序中默認的類加載器。對此,如果有必要開發者可以加入自己定義的類加載器。

雙親委派模型簡單理解:
一般對於我們java程序員來說,類的加載使用的是雙親委派模型,即當一個類需要加載時,會將類傳給Application ClassLoader,但是Application ClassLoader並不會加載,不管它是否能加載,而是傳給它的"父類" Extension ClassLoader,Extension ClassLoader同樣不會加載,同樣傳給 Bootstrap ClassLoader(注意不是我們常說的那種父類,但是可以這樣理解),這時Bootstrap ClassLoader會判斷它是否能加載,能加載就直接加載了,不能加載就傳給Extension ClassLoader,Extension ClassLoader同樣的判斷是否能加載,能加載就直接加載,不能加載就傳給Application ClassLoader,然後Application ClassLoader也判斷能否加載,如果還是不能加載應該就是報ClassNotFoundException了。這就是雙親委託模型的簡單理解了。

2.請簡單的談談JVM內存

運行時數據區包括:虛擬機棧區,堆區,方法區,本地方法棧,程序計數器
虛擬機棧區 :也就是我們常說的棧區,線程私有,存放基本類型,對象的引用和 returnAddress ,在編譯期間完成分配。
堆區 , JAVA 堆,也稱 GC 堆,所有線程共享,存放對象的實例和數組, JAVA 堆是垃圾收集器管理的主要區域。
方法區 :所有線程共享,存儲已被虛擬機加載的類信息,常量,靜態變量,即時編譯器編譯後的代碼等數據。這個區域的內存回收目標主要是針對常量池的對象的回收和對類型的卸載。
程序計數器線程私有,每個線程都有自己獨立的程序計數器,用來指示下一條指令的地址。

3.JAVA鎖的種類

1、自旋鎖 ,自旋,jvm默認是10次吧,由jvm自己控制。for去爭取鎖
2、阻塞鎖 被阻塞的線程,不會爭奪鎖。
3、可重入鎖 多次進入改鎖的域
4、讀寫鎖
5、互斥鎖 鎖本身就是互斥的
6、悲觀鎖 不相信,這裏會是安全的,必須全部上鎖
7、樂觀鎖 相信,這裏是安全的。
8、公平鎖 有優先級的鎖
9、非公平鎖 無優先級的鎖
10、偏向鎖 無競爭不鎖,有競爭掛起,轉爲輕量鎖
11、對象鎖 鎖住對象
12、線程鎖
13、鎖粗化 多鎖變成一個,自己處理
14、輕量級鎖 CAS 實現
15、鎖消除 偏向鎖就是鎖消除的一種
16、鎖膨脹 jvm實現,鎖粗化
17、信號量 使用阻塞鎖 實現的一種策略
18、排它鎖:X鎖,若事務T對數據對象A加上X鎖,則只允許T讀取和修改A,其他任何事務都不能再對A加任何類型的鎖,直到T釋放A上的鎖。這就保證了其他事務在T釋放A上的鎖之前不能再讀取和修改A。

4.ThreadLocal

ThreadLocal類用來提供線程內部的局部變量。
這種變量在多線程環境下訪問(通過get或set方法訪問)時能保證各個線程裏的變量相對獨立於其他線程內的變量。ThreadLocal實例通常來說都是private static類型的,用於關聯線程和線程的上下文。
可以總結爲一句話:ThreadLocal的作用是提供線程內的局部變量,這種變量在線程的生命週期內起作用,減少同一個線程內多個函數或者組件之間一些公共變量的傳遞的複雜度。
舉個例子,我出門需要先坐公交再做地鐵,這裏的坐公交和坐地鐵就好比是同一個線程內的兩個函數,我就是一個線程,我要完成這兩個函數都需要同一個東西:公交卡(北京公交和地鐵都使用公交卡),那麼我爲了不向這兩個函數都傳遞公交卡這個變量(相當於不是一直帶着公交卡上路),我可以這麼做:將公交卡事先交給一個機構,當我需要刷卡的時候再向這個機構要公交卡(當然每次拿的都是同一張公交卡)。這樣就能達到只要是我(同一個線程)需要公交卡,何時何地都能向這個機構要的目的。 有人要說了:你可以將公交卡設置爲全局變量啊,這樣不是也能何時何地都能取公交卡嗎?但是如果有很多個人(很多個線程)呢?大家可不能都使用同一張公交卡吧(我們假設公交卡是實名認證的),這樣不就亂套了嘛。現在明白了吧?
這就是ThreadLocal設計的初衷:提供線程內部的局部變量,在本線程內隨時隨地可取,隔離其他線程。
補充:
1.ThreadLocal存放的值是線程封閉,線程間互斥的,主要用於線程內共享一些數據,避免通過參數來傳遞
2.線程的角度看,每個線程都保持一個對其線程局部變量副本的隱式引用,只要線程是活動的並且 ThreadLocal 實例是可訪問的;在線程消失之後,其線程局部實例的所有副本都會被垃圾回收
3.在Thread類中有一個Map,用於存儲每一個線程的變量的副本。
4.對於多線程資源共享的問題,同步機制採用了“以時間換空間”的方式,而ThreadLocal採用了“以空間換時間”的方式

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