java虛擬機jvm啟動后java代碼層面發(fā)生了什么?

0000 我想驗證的事情

java代碼在被編譯后可以被jdk提供的java命令進行加載和運行, 在我們的程序被運行起來的時候,都發(fā)生了什么事情, 下面就來探究下這個問題, 這個問題被拆成了兩個問題, 第一個問題用來確定發(fā)生了哪些事情, 第二個問題用來確定這些事情是如何進行的.

  1. java進程里面都發(fā)生了哪些活動?
  2. 這些活動在java代碼(反編譯或者是源碼)級別有所體現(xiàn)嗎?

0001 尋找驗證的方式

當(dāng)我在探究上面兩個問題時, 我想了很多方式去探究這兩個問題,下面是我想到的方法

  1. java官方文檔? 沒有找到
  2. 搜索引擎? 沒有找到
  3. idea中debug? 有點線索

在idea中打上斷點然后debug時, 我發(fā)現(xiàn)了一個東西,以下是idea中的debug截圖

image.png

看到了這個關(guān)于線程和調(diào)用堆棧的線索, 那么java代碼層面中發(fā)生了哪些事情就好確定了
通過線程名字可以看出這個線程主要負責(zé)的事情.

image.png

0002 確認驗證的入口

idea中的debug窗口的線程選擇下拉框顯示了一些可以進行debug操作的線程, 那么可以斷定這幾個線程都有對應(yīng)java代碼入口, 我們可以根據(jù)這些堆棧的入口來進行代碼閱讀, 感興趣的可以看看里面究竟發(fā)生了哪些事情
idea中的可debug的線程沒有通過jstack命令顯示的線程多, 下面是通過jstack命令dump出來的數(shù)據(jù):

"RMI TCP Connection(2)-192.168.191.1" #18 daemon prio=5 os_prio=0 tid=0x000000001b409800 nid=0x80a4 runnable [0x000000001c93d000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:171)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
at java.io.BufferedInputStream.read(BufferedInputStream.java:265)
- locked <0x00000000d7520cb0> (a java.io.BufferedInputStream)
at java.io.FilterInputStream.read(FilterInputStream.java:83)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:555)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:834)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:688)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$Lambda$3/1223273742.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:687)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

Locked ownable synchronizers:
- <0x00000000d6c99530> (a java.util.concurrent.ThreadPoolExecutor$Worker)

"JMX server connection timeout 17" #17 daemon prio=5 os_prio=0 tid=0x000000001ae9e000 nid=0x8088 in Object.wait() [0x000000001c63f000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000d715f378> (a [I)
at com.sun.jmx.remote.internal.ServerCommunicatorAdmin$Timeout.run(ServerCommunicatorAdmin.java:168)
- locked <0x00000000d715f378> (a [I)
at java.lang.Thread.run(Thread.java:748)

Locked ownable synchronizers:
- None

"RMI Scheduler(0)" #16 daemon prio=5 os_prio=0 tid=0x000000001b1c6800 nid=0x8084 waiting on condition [0x000000001c53e000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000000d69fbee0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1093)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

Locked ownable synchronizers:
- None

"RMI TCP Connection(1)-192.168.191.1" #15 daemon prio=5 os_prio=0 tid=0x000000001ae1a800 nid=0x8080 runnable [0x000000001c43d000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:171)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
at java.io.BufferedInputStream.read(BufferedInputStream.java:265)
- locked <0x00000000d6ddc2e0> (a java.io.BufferedInputStream)
at java.io.FilterInputStream.read(FilterInputStream.java:83)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:555)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:834)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:688)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$$Lambda$3/1223273742.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:687)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

Locked ownable synchronizers:
- <0x00000000d6c93ac0> (a java.util.concurrent.ThreadPoolExecutor$Worker)

"RMI TCP Accept-0" #14 daemon prio=5 os_prio=0 tid=0x000000001a833800 nid=0x8074 runnable [0x000000001c23e000]
java.lang.Thread.State: RUNNABLE
at java.net.DualStackPlainSocketImpl.accept0(Native Method)
at java.net.DualStackPlainSocketImpl.socketAccept(DualStackPlainSocketImpl.java:131)
at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:409)
at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:199)
- locked <0x00000000d6be9bb0> (a java.net.SocksSocketImpl)
at java.net.ServerSocket.implAccept(ServerSocket.java:545)
at java.net.ServerSocket.accept(ServerSocket.java:513)
at sun.management.jmxremote.LocalRMIServerSocketFactory$1.accept(LocalRMIServerSocketFactory.java:52)
at sun.rmi.transport.tcp.TCPTransport$AcceptLoop.executeAcceptLoop(TCPTransport.java:405)
at sun.rmi.transport.tcp.TCPTransport$AcceptLoop.run(TCPTransport.java:377)
at java.lang.Thread.run(Thread.java:748)

Locked ownable synchronizers:
- None

"Service Thread" #12 daemon prio=9 os_prio=0 tid=0x000000001a653800 nid=0x3be8 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

Locked ownable synchronizers:
- None

"C1 CompilerThread2" #11 daemon prio=9 os_prio=2 tid=0x000000001a63f000 nid=0x70b8 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

Locked ownable synchronizers:
- None

"C2 CompilerThread1" #10 daemon prio=9 os_prio=2 tid=0x000000001a5ed800 nid=0x7898 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

Locked ownable synchronizers:
- None

"C2 CompilerThread0" #9 daemon prio=9 os_prio=2 tid=0x000000001a5ec800 nid=0x79a4 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

Locked ownable synchronizers:
- None

"JDWP Command Reader" #8 daemon prio=10 os_prio=0 tid=0x0000000018458800 nid=0x7520 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

Locked ownable synchronizers:
- None

"JDWP Event Helper Thread" #7 daemon prio=10 os_prio=0 tid=0x0000000018455000 nid=0x7c44 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

Locked ownable synchronizers:
- None

"JDWP Transport Listener: dt_socket" #6 daemon prio=10 os_prio=0 tid=0x0000000018449000 nid=0x7a50 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

Locked ownable synchronizers:
- None

"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x00000000197b3000 nid=0x3250 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

Locked ownable synchronizers:
- None

"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x000000001842a800 nid=0x4c8c runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

Locked ownable synchronizers:
- None

"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x00000000037bd800 nid=0x764c in Object.wait() [0x000000001976f000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000d5d88ed0> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
- locked <0x00000000d5d88ed0> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216)

Locked ownable synchronizers:
- None

"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x00000000037bc000 nid=0x3c8c in Object.wait() [0x000000001966e000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000d5d86bf8> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:502)
at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
- locked <0x00000000d5d86bf8> (a java.lang.ref.Reference$Lock)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

Locked ownable synchronizers:
- None

"main" #1 prio=5 os_prio=0 tid=0x00000000036c4000 nid=0x1cb0 runnable [0x00000000035bf000]
java.lang.Thread.State: RUNNABLE
at java.io.FileInputStream.readBytes(Native Method)
at java.io.FileInputStream.read(FileInputStream.java:255)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
at java.io.BufferedInputStream.read(BufferedInputStream.java:265)
- locked <0x00000000d5de89a8> (a java.io.BufferedInputStream)
at com.TaskTest.main(Test.java:179)

Locked ownable synchronizers:
- None

"VM Thread" os_prio=2 tid=0x00000000183d8000 nid=0x6d38 runnable

"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00000000036e2800 nid=0x7e88 runnable

"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00000000036e4000 nid=0x35e4 runnable

"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00000000036e5800 nid=0x4ed4 runnable

"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00000000036e7000 nid=0x702c runnable

"VM Periodic Task Thread" os_prio=2 tid=0x000000001a69f000 nid=0x2af8 waiting on condition

JNI global references: 5253

可以看出來jstack導(dǎo)出的線程有些有調(diào)用堆棧, 有些沒有, 是這樣的, 沒有堆棧的線程應(yīng)該是jvm的一些核心線程, 這些核心線程提供了jvm的核心功能, 比如垃圾回收, 即時編譯等. 帶有堆棧的這些線程都是由java代碼作為入口構(gòu)建出來的, 所以我們能根據(jù)這些入口去查看里面的具體邏輯, 這些線程中有一個線程main, 這個線程就是為帶有main方法入口的java應(yīng)用構(gòu)建出來的, 這個線程主要執(zhí)行動作就是java應(yīng)用由入口方法所觸發(fā)的程序邏輯.
帶有堆棧信息的這些線程, 在執(zhí)行其自身代碼的邏輯之外, 還會被jvm用于執(zhí)行類加載這個動作. 如何驗證這個類加載的動作呢, 如果你用的idea, 在設(shè)置中開啟debug時進入類加載器斷點, idea默認不開啟這個動作, 然后把斷點打點到類加載器的loadClass這個方法中, 給出以下具體位置:sun.misc.Launcher.AppClassLoader#loadClass, 如何確定是這個類呢, 大家可以在自己的main方法中獲取自己定義的類的類對象, 根據(jù)類對象的方法getClassLoader就可以確認類加載器了, 對于AppClassLoader這個類加載器大家肯定不會陌生, 比較有名雙親委派模型就是由這個類實現(xiàn)的, 大家有興趣的可以去扒下代碼, 驗證下自己讀過的文章是不是和代碼一致. 最后以debug模式啟動你的main代碼, 你就可以命中類加載器中的代碼了. 好了, 好好琢磨琢磨這些代碼邏輯吧.

下次再見

0003 網(wǎng)絡(luò)資源

下面是一些本文的相關(guān)資源

JVM 內(nèi)部運行線程介紹
https://www.cnblogs.com/williamjie/p/9389349.html
各個工具如何查找加載類
https://docs.oracle.com/javase/8/docs/technotes/tools/findingclasses.html
java虛擬機如何查找加載類
https://docs.oracle.com/javase/8/docs/technotes/tools/windows/java.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末垢乙,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子语卤,更是在濱河造成了極大的恐慌追逮,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件粹舵,死亡現(xiàn)場離奇詭異钮孵,居然都是意外死亡,警方通過查閱死者的電腦和手機眼滤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進店門巴席,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人诅需,你說我怎么就攤上這事漾唉∮猓” “怎么了?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵赵刑,是天一觀的道長分衫。 經(jīng)常有香客問我,道長料睛,這世上最難降的妖魔是什么丐箩? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任摇邦,我火速辦了婚禮恤煞,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘施籍。我一直安慰自己居扒,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布丑慎。 她就那樣靜靜地躺著喜喂,像睡著了一般。 火紅的嫁衣襯著肌膚如雪竿裂。 梳的紋絲不亂的頭發(fā)上玉吁,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天,我揣著相機與錄音腻异,去河邊找鬼进副。 笑死,一個胖子當(dāng)著我的面吹牛悔常,可吹牛的內(nèi)容都是我干的影斑。 我是一名探鬼主播,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼机打,長吁一口氣:“原來是場噩夢啊……” “哼矫户!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起残邀,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤皆辽,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后芥挣,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體驱闷,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年九秀,在試婚紗的時候發(fā)現(xiàn)自己被綠了遗嗽。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡鼓蜒,死狀恐怖痹换,靈堂內(nèi)的尸體忽然破棺而出征字,到底是詐尸還是另有隱情,我是刑警寧澤娇豫,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布匙姜,位于F島的核電站,受9級特大地震影響冯痢,放射性物質(zhì)發(fā)生泄漏氮昧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一浦楣、第九天 我趴在偏房一處隱蔽的房頂上張望袖肥。 院中可真熱鬧,春花似錦振劳、人聲如沸椎组。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽寸癌。三九已至,卻和暖如春弱贼,著一層夾襖步出監(jiān)牢的瞬間蒸苇,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工吮旅, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留溪烤,地道東北人。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓鸟辅,卻偏偏與公主長得像氛什,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子匪凉,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,500評論 2 359

推薦閱讀更多精彩內(nèi)容