任何程序都需要加載到內(nèi)存才能與CPU進(jìn)行交流
同理, 字節(jié)碼.class文件同樣需要加載到內(nèi)存中,才可以實(shí)例化類
ClassLoader的使命就是提前加載.class 類文件到內(nèi)存中
在加載類時(shí),使用的是Parents Delegation Model(溯源委派加載模型)
Java的類加載器是一個(gè)運(yùn)行時(shí)核心基礎(chǔ)設(shè)施模塊,主要是在啟動(dòng)之初進(jìn)行類的加載、鏈接、初始化
第一步,Load階段讀取類文件產(chǎn)生二進(jìn)制流,并轉(zhuǎn)為特定數(shù)據(jù)結(jié)構(gòu),初步校驗(yàn)cafe babe魔法數(shù)、常量池、文件長(zhǎng)度、是否有父類等,然后創(chuàng)建對(duì)應(yīng)類的java.lang.Class實(shí)例
第二步,Link階段包括驗(yàn)證、準(zhǔn)備、解析三個(gè)步驟
驗(yàn)證是更詳細(xì)的校驗(yàn),比如final是否合規(guī)、類型是否正確、靜態(tài)變量是否合理等
準(zhǔn)備階段是為靜態(tài)變量分配內(nèi)存,并設(shè)定默認(rèn)值,解析類和方法確保類與類之間的相互引用正確性,完成內(nèi)存結(jié)構(gòu)布局第三步,Init 階段執(zhí)行類構(gòu)造器 類加載是一個(gè)將.class字節(jié)碼文件實(shí)例化成Class對(duì)象并進(jìn)行相關(guān)初始化的過(guò)程。
在這個(gè)過(guò)程中,JVM會(huì)初始化繼承樹上還沒有被初始化過(guò)的所有父類,并且會(huì)執(zhí)行這個(gè)鏈路上所有未執(zhí)行過(guò)的靜態(tài)代碼塊、靜態(tài)變量賦值語(yǔ)句等。
某些類在使用時(shí),也可以按需由類加載器進(jìn)行加載。
全小寫的class是關(guān)鍵字,用來(lái)定義類
而首字母大寫的Class,它是所有class的類
這句話理解起來(lái)有難度,類已經(jīng)是現(xiàn)實(shí)世界中某種事物的抽象,為什么這個(gè)抽象還是另外一個(gè)類Class的對(duì)象?
示例代碼如下:
● 第1處說(shuō)明:
Class類下的newInstance()在JDK9中已經(jīng)置為過(guò)時(shí),使用getDeclaredConstructor().newInstance()的方式
著重說(shuō)明一下new與newInstance的區(qū)別
new是強(qiáng)類型校驗(yàn),可以調(diào)用任何構(gòu)造方法,在使用new操作的時(shí)候,這個(gè)類可以沒有被加載過(guò)
而Class類下的newInstance是弱類型,只能調(diào)用無(wú)參構(gòu)造方法
如果沒有默認(rèn)構(gòu)造方法,就拋出InstantiationException異常;
如果此構(gòu)造方法沒有權(quán)限訪問(wèn),則拋 IllegalAccessException異常
Java 通過(guò)類加載器把類的實(shí)現(xiàn)與類的定義進(jìn)行解耦,所以是實(shí)現(xiàn)面向接口編程、依賴倒置的必然選擇。
● 第2處說(shuō)明:
可以使用類似的方式獲取其他聲明,如注解、方法等
● 第3處說(shuō)明: private 成員在類外是否可以修改?
通過(guò)setccessible(true),即可使用Class類的set方法修改其值
如果沒有這一步,則拋出如下異常:
類加載器類加載器是如何定位具體的類文件并讀取的呢?
在類加載器家族中存在著類似人類社會(huì)的權(quán)力等級(jí)制度
最高層的Bootstrap
在JVM啟動(dòng)時(shí)創(chuàng)建的,通常由與操作系統(tǒng)相關(guān)的本地代碼實(shí)現(xiàn),是最根基的類加載器,負(fù)責(zé)裝載最核心的Java類,比如Object、System、 String ,Java運(yùn)行時(shí)的rt.jar等jar包
JDK9的Platform ClassLoader
負(fù)責(zé)加載
加載一些擴(kuò)展的系統(tǒng)類,比如XML、加密、壓縮相關(guān)的功能類等;
JDK9之前是Extension ClassLoader.
第三層 Application ClassLoader
應(yīng)用類加載器,主要是加載用戶定義的CLASSPATH路徑下的類
第二、三層類加載器為Java語(yǔ)言實(shí)現(xiàn),用戶也可以自定義類加載器
查看本地類加載器的方式如下:
在JDK8環(huán)境中,執(zhí)行結(jié)果如下
AppClassLoader的Parent為Bootstrap,它是通過(guò)C/C++實(shí)現(xiàn)的,并不存在于JVM體系內(nèi),所以輸出為 null
低層次的當(dāng)前類加載器,不能覆蓋更高層次類加載器已經(jīng)加載的類
如果低層次的類加載器想加載一個(gè)未知類,要非常禮貌地向上逐級(jí)詢問(wèn):“請(qǐng)問(wèn),這個(gè)類已經(jīng)加載了嗎?”
被詢問(wèn)的高層次類加載器會(huì)自問(wèn)兩個(gè)問(wèn)題
我是否已加載過(guò)此類
如果沒有,是否可以加載此類
只有當(dāng)所有高層次類加載器在兩個(gè)問(wèn)題的答案均為“否”時(shí),才可以讓當(dāng)前類加載器加載這個(gè)未知類
左側(cè)綠色箭頭向上逐級(jí)詢問(wèn)是否已加載此類,直至Bootstrap ClassLoader,然后向下逐級(jí)嘗試是否能夠加載此類,如果都加載不了,則通知發(fā)起加載請(qǐng)求的當(dāng)前類加載器,準(zhǔn)予加載
在右側(cè)的三個(gè)小標(biāo)簽里,列舉了此層類加載器主要加載的代表性類庫(kù),事實(shí)上不止于此
通過(guò)如下代碼可以查看Bootstrap 所有已加載類庫(kù)
執(zhí)行結(jié)果
Bootstrap加載的路徑可以追加,不建議修改或刪除原有加載路徑
在JVM中增加如下啟動(dòng)參數(shù),則能通過(guò)Class.forName正常讀取到指定類,說(shuō)明此參數(shù)可以增加Bootstrap的類加載路徑:
-Xbootclasspath/a:/Users/sss/book/ easyCoding/byJdk11/src
如果想在啟動(dòng)時(shí)觀察加載了哪個(gè)jar包中的哪個(gè)類,可以增加
-XX:+TraceClassLoading
此參數(shù)在解決類沖突時(shí)非常實(shí)用,畢竟不同的JVM環(huán)境對(duì)于加載類的順序并非是一致的
有時(shí)想觀察特定類的加載上下文,由于加載的類數(shù)量眾多,調(diào)試時(shí)很難捕捉到指定類的加載過(guò)程,這時(shí)可以使用條件斷點(diǎn)功能
比如,想查看HashMap的加載過(guò)程,在loadClass處打個(gè)斷點(diǎn),并且在condition框內(nèi)輸入如圖
JVM如何確立每個(gè)類在JVM的唯一性類的全限定名和加載這個(gè)類的類加載器的ID
在學(xué)習(xí)了類加載器的實(shí)現(xiàn)機(jī)制后,知道雙親委派模型并非強(qiáng)制模型,用戶可以自定義類加載器,在什么情況下需要自定義類加載器呢?
隔離加載類
在某些框架內(nèi)進(jìn)行中間件與應(yīng)用的模塊隔離,把類加載到不同的環(huán)境
比如,阿里內(nèi)某容器框架通過(guò)自定義類加載器確保應(yīng)用中依賴的jar包不會(huì)影響到中間件運(yùn)行時(shí)使用的jar包
修改類加載方式
類的加載模型并非強(qiáng)制,除Bootstrap外,其他的加載并非一定要引入,或者根據(jù)實(shí)際情況在某個(gè)時(shí)間點(diǎn)進(jìn)行按需進(jìn)行動(dòng)態(tài)加載
擴(kuò)展加載源
比如從數(shù)據(jù)庫(kù)、網(wǎng)絡(luò),甚至是電視機(jī)機(jī)頂盒進(jìn)行加載
防止源碼泄露
Java代碼容易被編譯和篡改,可以進(jìn)行編譯加密。那么類加載器也需要自定義,還原加密的字節(jié)碼。
實(shí)現(xiàn)自定義類加載器的步驟
繼承ClassLoader
重寫findClass()方法
調(diào)用defineClass()方法
一個(gè)簡(jiǎn)單的類加載器實(shí)現(xiàn)的示例代碼如下
由于中間件一般都有自己的依賴jar包,在同一個(gè)工程內(nèi)引用多個(gè)框架時(shí),往往被迫進(jìn)行類的仲裁
按某種規(guī)則jar包的版本被統(tǒng)一指定, 導(dǎo)致某些類存在包路徑、類名相同的情況,就會(huì)引起類沖突,導(dǎo)致應(yīng)用程序出現(xiàn)異常
主流的容器類框架都會(huì)自定義類加載器,實(shí)現(xiàn)不同中間件之間的類隔離,有效避免了類沖突。
1 加載的定位“加載”是“類加載”(Class Loading)過(guò)程的第一步1.1 加載的過(guò)程
在加載的過(guò)程中,JVM主要做3件事情
通過(guò)一個(gè)類的全限定名來(lái)獲取定義此類的二進(jìn)制字節(jié)流(class文件)
在程序運(yùn)行過(guò)程中,當(dāng)要訪問(wèn)一個(gè)類時(shí),若發(fā)現(xiàn)這個(gè)類尚未被加載,并滿足類初始化的條件時(shí),就根據(jù)要被初始化的這個(gè)類的全限定名找到該類的二進(jìn)制字節(jié)流,開始加載過(guò)程
將這個(gè)字節(jié)流的靜態(tài)存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)
在內(nèi)存中創(chuàng)建一個(gè)該類的java.lang.Class對(duì)象,作為方法區(qū)該類的各種數(shù)據(jù)的訪問(wèn)入口
程序在運(yùn)行中所有對(duì)該類的訪問(wèn)都通過(guò)這個(gè)類對(duì)象,也就是這個(gè)Class對(duì)象是提供給外界訪問(wèn)該類的接口
1.2 加載源JVM規(guī)范對(duì)于加載過(guò)程給予了較大的寬松度.一般二進(jìn)制字節(jié)流都從已經(jīng)編譯好的本地class文件中讀取,此外還可以從以下地方讀取
zip包
Jar、War、Ear等String[] str = new String[10];這個(gè)數(shù)組的數(shù)組類型是Ljava.lang.String,而String只是這個(gè)數(shù)組的元素類型
其它文件生成
由JSP文件中生成對(duì)應(yīng)的Class類.
數(shù)據(jù)庫(kù)中
將二進(jìn)制字節(jié)流存儲(chǔ)至數(shù)據(jù)庫(kù)中,然后在加載時(shí)從數(shù)據(jù)庫(kù)中讀取.有些中間件會(huì)這么做,用來(lái)實(shí)現(xiàn)代碼在集群間分發(fā)
網(wǎng)絡(luò)
從網(wǎng)絡(luò)中獲取二進(jìn)制字節(jié)流.典型就是Applet.
運(yùn)行時(shí)計(jì)算生成
動(dòng)態(tài)代理技術(shù),用PRoxyGenerator.generateProxyClass為特定接口生成形式為"*$Proxy"的代理類的二進(jìn)制字節(jié)流.1.3 類和數(shù)組加載過(guò)程的區(qū)別數(shù)組也有類型,稱為“數(shù)組類型”.如:
當(dāng)程序在運(yùn)行過(guò)程中遇到new關(guān)鍵字創(chuàng)建一個(gè)數(shù)組時(shí),由JVM直接創(chuàng)建數(shù)組類,再由類加載器創(chuàng)建數(shù)組中的元素類型.
而普通類的加載由類加載器創(chuàng)建.既可以使用系統(tǒng)提供的引導(dǎo)類加載器,也可以由用戶自定義的類加載器完成(即重寫一個(gè)類加載器的loadClass()方法)
1.4 加載過(guò)程的注意點(diǎn)JVM規(guī)范并未給出類在方法區(qū)中存放的數(shù)據(jù)結(jié)構(gòu)
類完成加載后,二進(jìn)制字節(jié)流就以特定的數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)在方法區(qū)中,但存儲(chǔ)的數(shù)據(jù)結(jié)構(gòu)是由虛擬機(jī)自己定義的,虛擬機(jī)規(guī)范并沒有指定
JVM規(guī)范并沒有指定Class對(duì)象存放的位置
在二進(jìn)制字節(jié)流以特定格式存儲(chǔ)在方法區(qū)后,JVM會(huì)創(chuàng)建一個(gè)java.lang.Class類的對(duì)象,作為本類的外部訪問(wèn)接口
既然是對(duì)象就應(yīng)該存放在Java堆中,不過(guò)JVM規(guī)范并沒有給出限制,不同的虛擬機(jī)根據(jù)自己的需求存放這個(gè)對(duì)象
HotSpot將Class對(duì)象存放在方法區(qū).
加載階段和鏈接階段是交叉的
類加載的過(guò)程中每個(gè)步驟的開始順序都有嚴(yán)格限制,但每個(gè)步驟的結(jié)束順序沒有限制.也就是說(shuō),類加載過(guò)程中,必須按照如下順序開始: 加載 -> 鏈接 -> 初始化
但結(jié)束順序無(wú)所謂,因此由于每個(gè)步驟處理時(shí)間的長(zhǎng)短不一就會(huì)導(dǎo)致有些步驟會(huì)出現(xiàn)交叉
2 驗(yàn)證驗(yàn)證階段比較耗時(shí),它非常重要但不一定必要(因?yàn)閷?duì)程序運(yùn)行期沒有影響),如果所運(yùn)行的代碼已經(jīng)被反復(fù)使用和驗(yàn)證過(guò),那么可以使用-Xverify:none參數(shù)關(guān)閉,以縮短類加載時(shí)間
2.1 驗(yàn)證的目的保證二進(jìn)制字節(jié)流中的信息符合虛擬機(jī)規(guī)范,并沒有安全問(wèn)題
2.2 驗(yàn)證的必要性雖然Java語(yǔ)言是一門安全的語(yǔ)言,它能確保程序猿無(wú)法訪問(wèn)數(shù)組邊界以外的內(nèi)存、避免讓一個(gè)對(duì)象轉(zhuǎn)換成任意類型、避免跳轉(zhuǎn)到不存在的代碼行.也就是說(shuō),Java語(yǔ)言的安全性是通過(guò)編譯器來(lái)保證的.
但是我們知道,編譯器和虛擬機(jī)是兩個(gè)獨(dú)立的東西,虛擬機(jī)只認(rèn)二進(jìn)制字節(jié)流,它不會(huì)管所獲得的二進(jìn)制字節(jié)流是哪來(lái)的,當(dāng)然,如果是編譯器給它的,那么就相對(duì)安全,但如果是從其它途徑獲得的,那么無(wú)法確保該二進(jìn)制字節(jié)流是安全的。
通過(guò)上文可知,虛擬機(jī)規(guī)范中沒有限制二進(jìn)制字節(jié)流的來(lái)源,在字節(jié)碼層面上,上述Java代碼無(wú)法做到的都是可以實(shí)現(xiàn)的,至少語(yǔ)義上是可以表達(dá)出來(lái)的,為了防止字節(jié)流中有安全問(wèn)題,需要驗(yàn)證!
2.3 驗(yàn)證的過(guò)程文件格式驗(yàn)證
驗(yàn)證字節(jié)流是否符合Class文件格式的規(guī)范,并且能被當(dāng)前的虛擬機(jī)處理.
本驗(yàn)證階段是基于二進(jìn)制字節(jié)流進(jìn)行的,只有通過(guò)本階段驗(yàn)證,才被允許存到方法區(qū)
后面的三個(gè)驗(yàn)證階段都是基于方法區(qū)的存儲(chǔ)結(jié)構(gòu)進(jìn)行,不會(huì)再直接操作字節(jié)流.
通過(guò)上文可知,加載開始前,二進(jìn)制字節(jié)流還沒進(jìn)方法區(qū),而加載完成后,二進(jìn)制字節(jié)流已經(jīng)存入方法區(qū)
而在文件格式驗(yàn)證前,二進(jìn)制字節(jié)流尚未進(jìn)入方法區(qū),文件格式驗(yàn)證通過(guò)之后才進(jìn)入方法區(qū)
也就是說(shuō),加載開始后,立即啟動(dòng)了文件格式驗(yàn)證,本階段驗(yàn)證通過(guò)后,二進(jìn)制字節(jié)流被轉(zhuǎn)換成特定數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)至方法區(qū)中,繼而開始下階段的驗(yàn)證和創(chuàng)建Class對(duì)象等操作
這個(gè)過(guò)程印證了:加載和驗(yàn)證是交叉進(jìn)行的
元數(shù)據(jù)驗(yàn)證
對(duì)字節(jié)碼描述信息進(jìn)行語(yǔ)義分析,確保符合Java語(yǔ)法規(guī)范.public static final int value = 123;準(zhǔn)備階段后 a 的值為 0,而不是 123,要在初始化之后才變?yōu)?123,但若被final修飾的常量如果有初始值,那么在編譯階段就會(huì)將初始值存入constantValue屬性中,在準(zhǔn)備階段就將constantValue的值賦給該字段(此處將value賦為123).4 解析解析階段是虛擬機(jī)將常量池中的符號(hào)引用替換為直接引用的過(guò)程.5 初始化真正開始執(zhí)行類中定義的Java程序代碼(或者說(shuō)是字節(jié)碼)
初始化階段就是執(zhí)行類構(gòu)造器clinit()的過(guò)程.
字節(jié)碼驗(yàn)證
本階段是驗(yàn)證過(guò)程的最復(fù)雜的一個(gè)階段.
本階段對(duì)方法體進(jìn)行語(yǔ)義分析,保證方法在運(yùn)行時(shí)不會(huì)出現(xiàn)危害虛擬機(jī)的事件.
字節(jié)碼驗(yàn)證將對(duì)類的方法進(jìn)行校驗(yàn)分析,保證被校驗(yàn)的方法在運(yùn)行時(shí)不會(huì)做出危害虛擬機(jī)的事,一個(gè)類方法體的字節(jié)碼沒有通過(guò)字節(jié)碼驗(yàn)證,那一定有問(wèn)題,但若一個(gè)方法通過(guò)了驗(yàn)證,也不能說(shuō)明它一定安全
符號(hào)引用驗(yàn)證
發(fā)生在JVM將符號(hào)引用轉(zhuǎn)化為直接引用的時(shí)候,這個(gè)轉(zhuǎn)化動(dòng)作發(fā)生在解析階段,對(duì)類自身以外的信息進(jìn)行匹配校驗(yàn),確保解析能正常執(zhí)行.3 準(zhǔn)備完成兩件事情
為已在方法區(qū)中的類的靜態(tài)成員變量分配內(nèi)存
為靜態(tài)成員變量設(shè)置初始值
初始值為0、false、null等
clinit()方法由編譯器自動(dòng)產(chǎn)生,收集類中static{}代碼塊中的類變量賦值語(yǔ)句和類中靜態(tài)成員變量的賦值語(yǔ)句。在準(zhǔn)備階段,類中靜態(tài)成員變量已經(jīng)完成了默認(rèn)初始化,而在初始化階段,clinit()方法對(duì)靜態(tài)成員變量進(jìn)行顯示初始化。
5.1 初始化過(guò)程的注意點(diǎn)
clinit()方法是IDE自動(dòng)收集類中所有類變量的賦值動(dòng)作和靜態(tài)語(yǔ)句塊中的語(yǔ)句合并產(chǎn)生的,IDE收集的順序是由語(yǔ)句在源文件中出現(xiàn)的順序所決定的.public class Test {
static {
i=0; System.out.println(i);//編譯失敗:"非法向前引用"
}
static int i = 1;
}
靜態(tài)代碼塊只能訪問(wèn)到出現(xiàn)在靜態(tài)代碼塊之前的變量,定義在它之后的變量,在前面的靜態(tài)語(yǔ)句塊可以賦值,但是不能訪問(wèn).
實(shí)例構(gòu)造器init()需要顯示調(diào)用父類構(gòu)造函數(shù),而類的clinit()不需要調(diào)用父類的類構(gòu)造函數(shù),虛擬機(jī)會(huì)確保子類的clinit()方法執(zhí)行前已經(jīng)執(zhí)行完畢父類的clinit()方法.因此在JVM中第一個(gè)被執(zhí)行的clinit()方法的類肯定是java.lang.Object.
如果一個(gè)類/接口中沒有靜態(tài)代碼塊,也沒有靜態(tài)成員變量的賦值操作,那么編譯器就不會(huì)為此類生成clinit()方法.
接口也需要通過(guò)clinit()方法為接口中定義的靜態(tài)成員變量顯示初始化。
接口中不能使用靜態(tài)代碼塊,但仍然有變量初始化的賦值操作,因此接口與類一樣都會(huì)生成clinit()方法.不同的是,執(zhí)行接口的clinit()方法不需要先執(zhí)行父接口的clinit()方法.只有當(dāng)父接口中的靜態(tài)成員變量被使用到時(shí)才會(huì)執(zhí)行父接口的clinit()方法.
虛擬機(jī)會(huì)保證在多線程環(huán)境中一個(gè)類的clinit()方法別正確地加鎖,同步.當(dāng)多條線程同時(shí)去初始化一個(gè)類時(shí),只會(huì)有一個(gè)線程去執(zhí)行該類的clinit()方法,其它線程都被阻塞等待,直到活動(dòng)線程執(zhí)行clinit()方法完畢.
其他線程雖會(huì)被阻塞,只要有一個(gè)clinit()方法執(zhí)行完,其它線程喚醒后不會(huì)再進(jìn)入clinit()方法.同一個(gè)類加載器下,一個(gè)類型只會(huì)初始化一次.參考
《碼到成功》
《深入理解Java虛擬機(jī)第二版》
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/75970.html
學(xué)習(xí)JVM的相關(guān)資料 《深入理解Java虛擬機(jī)——JVM高級(jí)特性與最佳實(shí)踐(第2版)》 showImg(https://segmentfault.com/img/bVbsqF5?w=200&h=200); 基于最新JDK1.7,圍繞內(nèi)存管理、執(zhí)行子系統(tǒng)、程序編譯與優(yōu)化、高效并發(fā)等核心主題對(duì)JVM進(jìn)行全面而深入的分析,深刻揭示JVM的工作原理。以實(shí)踐為導(dǎo)向,通過(guò)大量與實(shí)際生產(chǎn)環(huán)境相結(jié)合的案例展示了解...
摘要:如問(wèn)到是否使用某框架,實(shí)際是是問(wèn)該框架的使用場(chǎng)景,有什么特點(diǎn),和同類可框架對(duì)比一系列的問(wèn)題。這兩個(gè)方向的區(qū)分點(diǎn)在于工作方向的側(cè)重點(diǎn)不同。 [TOC] 這是一份來(lái)自嗶哩嗶哩的Java面試Java面試 32個(gè)核心必考點(diǎn)完全解析(完) 課程預(yù)習(xí) 1.1 課程內(nèi)容分為三個(gè)模塊 基礎(chǔ)模塊: 技術(shù)崗位與面試 計(jì)算機(jī)基礎(chǔ) JVM原理 多線程 設(shè)計(jì)模式 數(shù)據(jù)結(jié)構(gòu)與算法 應(yīng)用模塊: 常用工具集 ...
摘要:大多數(shù)待遇豐厚的開發(fā)職位都要求開發(fā)者精通多線程技術(shù)并且有豐富的程序開發(fā)調(diào)試優(yōu)化經(jīng)驗(yàn),所以線程相關(guān)的問(wèn)題在面試中經(jīng)常會(huì)被提到。將對(duì)象編碼為字節(jié)流稱之為序列化,反之將字節(jié)流重建成對(duì)象稱之為反序列化。 JVM 內(nèi)存溢出實(shí)例 - 實(shí)戰(zhàn) JVM(二) 介紹 JVM 內(nèi)存溢出產(chǎn)生情況分析 Java - 注解詳解 詳細(xì)介紹 Java 注解的使用,有利于學(xué)習(xí)編譯時(shí)注解 Java 程序員快速上手 Kot...
摘要:不可變?nèi)缃^對(duì)線程安全就是滿足并發(fā)編程實(shí)戰(zhàn)中對(duì)線程安全的定義在中標(biāo)注自己是線程安全的類,大都不是絕對(duì)的線程安全。如的和二實(shí)現(xiàn)線程安全的方法互斥同步互斥是因同步是果互斥是方法同步是目的。 一.到底什么叫線程安全:java并發(fā)編程實(shí)戰(zhàn)中對(duì)線程安全的定義是:當(dāng)多個(gè)線程訪問(wèn)一個(gè)對(duì)象時(shí),如果不用考慮這些線程在運(yùn)行時(shí)環(huán)境下的調(diào)度和交替執(zhí)行,也不需要進(jìn)行額外的同步,或者在調(diào)用方進(jìn)行任何其他的協(xié)調(diào)操作,...
閱讀 2919·2019-08-30 15:55
閱讀 2033·2019-08-30 14:02
閱讀 1311·2019-08-29 15:23
閱讀 1033·2019-08-29 11:27
閱讀 494·2019-08-26 11:43
閱讀 3221·2019-08-26 10:32
閱讀 1277·2019-08-23 14:41
閱讀 3323·2019-08-23 14:41