https://www.cnblogs.com/prayers/p/5515245.html
https://www.cnblogs.com/eastday/p/8124580.html
https://www.cnblogs.com/IUbanana/p/7067362.html
http://www.cnblogs.com/ityouknow/p/5603287.html
http://www.importnew.com/25295.html
一窍蓝、java虛擬機的生命周期
虛擬機存在的目的是讓java程序能夠正常運行妓羊,所以它的生命周期也是伴隨著java程序的初始化與終止。服務(wù)器上有多少個java程序正在運行尚困,就有多少個java虛擬機在維護這個程序。
java虛擬機的初始化以java程序main方法作為入口讶迁,main方法必須是public static void 并以字符串數(shù)組作為參數(shù)亿鲜,可以不適用main作為方法名吻贿,但是必須在虛擬機中配置好。main方法被初始線程初始化為初始化線程呻右。
java線程分為守護線程與普通線程跪妥,守護線程是java虛擬機的線程,負責(zé)守護普通線程的正常運行声滥,例如垃圾回收線程眉撵。
普通線程為java程序內(nèi)的線程,當所有普通線程執(zhí)行完畢結(jié)束落塑,則java虛擬機生命周期結(jié)束纽疟。
通過thread.setDaemon(true)可以將普通線程設(shè)置為守護線程
public class JAVAtest {
public static void main(String[] args) {
Thread thread = new Thread(){
@Override
public void run() {
System.out.println("守護開始");
for (int i = 0 ; i < 100 ; i ++) {
try {
Thread.sleep(100) ;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(i);
}
}
};
// thread.setDaemon(true);
thread.start();
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println(12);
}
};
Thread thread1 = new Thread(runnable);
thread1.start();
}
}
二、java虛擬機的體系結(jié)構(gòu)
1.類加載器子系統(tǒng):負責(zé)加載程序中的類型(類和接口)
2.執(zhí)行引擎:負責(zé)執(zhí)行被加載類中包含的指令
3.運行時數(shù)據(jù)區(qū):負責(zé)保存字節(jié)碼憾赁、被加載類的其他額外信息
三污朽、類加載器子系統(tǒng)
1.類的唯一性:
對于任意一個類,都需要由加載它的類加載器和類的全限定名一同確定其在Java虛擬機中的唯一性龙考。(此處的類加載器由于采用雙親委派模型蟆肆,所以真正加載類的可能并不是你所使用的類加載器,例如兩個自定義類加載器繼承了ClassLoader晦款,所以加載類的為同一個頂層類加載器)每一個類被加載為Class類的實例炎功,類加載器對象與class對象都保存在堆中,類信息保存在方法區(qū)中缓溅。
2.類加載器:
2.1類加載器類別:
從java虛擬機的角度劃分:
a.啟動類加載器(Bootstrap ClassLoader):這個類加載器使用C++語言實現(xiàn)蛇损,是虛擬機自身的一部分。
b.其他的類加載器:這些類加載器由Java語言實現(xiàn)坛怪,獨立于虛擬機州藕,并且全部都繼承自抽象類java.lang.ClassLoader。
從java繼承級別劃分:
a.啟動類加載器(Bootstrap ClassLoader):虛擬機的一部分酝陈,由c++編寫。這個類加載器負責(zé)將存放在<JAVA_HOME>\lib目錄中毁涉,或者被-Xbootclasspath虛擬機參數(shù)指定的路徑中沉帮,并且是虛擬機識別的類庫加載到虛擬機內(nèi)存中。
b.擴展類加載器(Extension ClassLoader):該加載器器是用JAVA編寫,且它的父類加載器是Bootstrap穆壕,是由sun.misc.Launcher$ExtClassLoader實現(xiàn)的待牵,主要加載JAVA_HOME/lib/ext目錄中的類庫。開發(fā)者可以這幾使用擴展類加載器喇勋。
c.應(yīng)用程序類加載器(Application ClassLoader):由于這個類加載器是ClassLoader中的getSystemClassLoader()方法的返回值缨该,所以一般也稱為系統(tǒng)類加載器。它負責(zé)加載用戶類路徑(ClassPath)上所指定的類庫川背,開發(fā)者可以直接使用這個類加載器贰拿,如果應(yīng)用程序中沒有自定義過自己的類加載器,一般情況下這個就是程序中默認的類加載器熄云。
注意:類加載器的體系并不是“繼承”體系膨更,而是委派體系,大多數(shù)類加載器首先會到自己的parent中查找類或者資源缴允,如果找不到才會到自己本地查找荚守。類加載器的委托行為動機是為了避免相同的類被加載多次。
2.3雙親委派模型:
類加載器之間的層次關(guān)系练般,稱為類加載器的雙親委派模型矗漾。雙親委派模型要求除了頂層的啟動類加載器外,其余類加載器都應(yīng)該有自己的父類加載器薄料。注意敞贡,這里類加載器之間的父子關(guān)系一般不會以繼承的關(guān)系實現(xiàn),而是使用組合關(guān)系來復(fù)用父加載器的代碼都办。
2.4雙親委派模型的工作過程:
如果一個類加載器收到了類加載的請求嫡锌,它首先不會自己去嘗試加載這個類,而是把這個請求委派給父類加載器去完成琳钉,每一個層次的類加載器都是如此势木,因此所有的加載請求最終都應(yīng)該首先傳送到頂層的啟動類加載器中,只有當父加載器反饋自己無法完成這個加載請求時歌懒,子加載器才會嘗試自己去加載啦桌。
2.5雙親委派模型的實現(xiàn)
類加載器均是繼承自java.lang.ClassLoader抽象類。首先及皂,我們看一看java.lang.ClassLoader類的loadClass()方法:
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {//對加載類的過程進行同步
// 首先甫男,檢查請求的類是否已經(jīng)被加載過了
// First, check if the class has already been loaded
Class c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);//委派請求給父加載器
} else {
//父加載器為null,說明this為擴展類加載器的實例验烧,父加載器為啟動類加載器
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// 如果父加載器拋出ClassNotFoundException
// 說明父加載器無法完成加載請求
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// 如果父加載器無法加載
// 調(diào)用本身的findClass方法來進行類加載
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
通過進一步分析標準擴展類加載器(sun.misc.LauncherAppClassLoader)的代碼以及其公共父類(java.net.URLClassLoader和java.security.SecureClassLoader)的代碼可以看出板驳,都沒有重寫java.lang.ClassLoader中默認的委派加載規(guī)則——loadClass(…)方法。所以這些類加載器都沿用了ClassLoader的雙親委派規(guī)則
2.6雙親委派模型的優(yōu)點
a.安全性:通過使用雙親委派模型碍拆,同一個類由不同的類加載器加載出來仍然是同一個類若治,不會出現(xiàn)使java程序出現(xiàn)混亂慨蓝。避免類被重復(fù)加載
3.類加載機制
加載 — 驗證 — 準備 — 解析 — 初始化
加載:通過一個類的全限定名獲取其對應(yīng)的二進制流,將二進制流內(nèi)類的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)變?yōu)榉椒▍^(qū)中的運行時數(shù)據(jù)結(jié)構(gòu)端幼。在java堆中生成一個代表這個類的對象礼烈,作為方法區(qū)對應(yīng)數(shù)據(jù)的入口。(這個階段可控性是最高的婆跑,因為可以在此階段選擇加載類的類加載器)
注意此時堆中的對象為類對象此熬。
驗證:為了確保class文件字節(jié)流中包含的信息符合虛擬機的要求,不會對虛擬機造成威脅滑进。
準備:為方法區(qū)中的靜態(tài)數(shù)據(jù)初始化犀忱,此時的初始化是初始化null,0郊供,等默認值峡碉,如果數(shù)據(jù)被final static修飾,則初始化指定值驮审。
解析:把類中的符號引用轉(zhuǎn)變?yōu)橹苯右?br>
初始化:根據(jù)程序執(zhí)行類構(gòu)造器<client>鲫寄,為類變量賦值。構(gòu)造器方法是由編譯器自動收集類中的類變量的賦值操作和靜態(tài)語句塊中的語句合并而成的疯淫。
以下不會觸發(fā)初始化:
1.通過子類引用父類的靜態(tài)字段地来,只會觸發(fā)父類的初始化,而不會觸發(fā)子類的初始化熙掺。
2.定義對象數(shù)組未斑,不會觸發(fā)該類的初始化。
3.常量在編譯期間會存入調(diào)用類的常量池中币绩,本質(zhì)上并沒有直接引用定義常量的類蜡秽,不會觸發(fā)定義常量所在的類。
4.通過類名獲取Class對象缆镣,不會觸發(fā)類的初始化芽突。
5.通過Class.forName加載指定類時,如果指定參數(shù)initialize為false時董瞻,也不會觸發(fā)類初始化寞蚌,其實這個參數(shù)是告訴虛擬機,是否要對類進行初始化钠糊。
6.通過ClassLoader默認的loadClass方法挟秤,也不會觸發(fā)初始化動作。