概述
Java對象的生命周期包括以下6個階段:
- 建立階段(Created)
- 應用階段(In Use)
- 不可見階段(Invisible)
- 不可達階段(Unreachable)
- 收集階段(Collected)
- 終結階段(Finalized)
建立階段
即對象的聲明和構造階段,主要過程如下:
- 在記憶體中配置設定空間
- 開始構造對象
- 從超類到子類進行static成員初始化(加載靜态變量)
- 從超類開始調用構造方法(雙親委派機制)
- 子類成員變量初始化,子類構造方法調用
一旦對象被建立,并被分派給某些變量指派,這個對象的狀态就切換到了應用階段。
應用階段
對象至少被一個強引用持有
不可見階段
即對象超出了所在的作用域(對象在某方法中建立并引用,某方法已調用完畢,對象進入不可見階段,無法再被引用)
不可達階段
對象處于不可達階段是指該對象不再被任何強引用所持有。
與“不可見階段”相比,“不可見階段”是指程式不再持有該對象的任何強引用,這種情況下,該對象仍可能被JVM等系統下的某些已裝載的靜态變量或線程或JNI等強引用持有着,這些特殊的強引用被稱為”GC root”。存在着這些GC root會導緻對象的記憶體洩露情況,無法被回收。
收集階段
當垃圾回收器發現該對象已經處于“不可達階段”并且垃圾回收器已經對該對象的記憶體空間重新配置設定做好準備時,則對象進入了“收集階段”。如果該對象已經重寫了finalize()方法,則會去執行該方法的終端操作。
終結階段
當對象執行完finalize方法後進入不可達狀态,等待GC回收
線程的生命周期
概述
線程的生命周期包含6種狀态:
- 建立(NEW)
- 可運作(RUNNABLE)
- 阻塞(BLOCKED)
- 等待(WAITING)
- 計時等待(TIMED_WAITING)
- 死亡(TERMINATED)
當線程進入運作狀态後,一般的作業系統是采用搶占式(兩種線程排程模式之一,另外一種為分時排程)的方式來讓線程獲得CPU。是以CPU需要在多條線程之間切換,于是線程狀态也會多次在運作、阻塞、就緒之間切換。
建立(NEW)
使用new方法,new出來線程,此時僅僅由JAVA虛拟機為其配置設定記憶體,并初始化成員變量的值。此時未調用start方法,程式未運作,程式進入RUNNABLE狀态。
可運作(RUNNABLE)
Java 中的 Runable 狀态對應作業系統線程狀态中的兩種狀态,分别是 Running(運作中) 和 Ready(等待CPU配置設定資源),也就是說,Java 中處于 Runnable 狀态的線程有可能正在執行,也有可能沒有正在執行,正在等待被配置設定 CPU 資源。
是以,如果一個正在運作的線程是 Runnable 狀态,當它運作到任務的一半時,執行該線程的 CPU 被排程去做其他事情,導緻該線程暫時不運作,它的狀态依然不變,還是 Runnable,因為它有可能随時被排程回來繼續執行任務。
阻塞狀态(BLOCKING)
差別于可運作的RUNNABLE狀态,另外有三種情況導緻線程無法運作,分别為:BLOCKED(被阻塞)、WAITING(等待)、TIMED_WAITING(計時等待),可統稱阻塞狀态(BLOCKING)
被阻塞(BLOCKED)
當處于RUNNABLE狀态的線程,因為某些原因(沒有拿到同步鎖或者IO請求被阻塞),放棄了CPU的使用,此時進入BLOCKED狀态,暫停運作,JVM也不會再配置設定CPU給線程,直到線程重新回到RUNNABLE狀态。
等待(WAITING)
運作中的程式由于某些條件未滿足,主動調用Object.wait()/Thread.join()/LockSupport.park()等方法,程式進入WAITING狀态(放入對象等待池中),等待其他線程的喚醒。
計時等待(TIMED_WAITING)
調用wait方法時加入了等待時長參數,或者調用了sleep方法,進入計時等待,逾時後自動被系統喚醒,也可以被notify提前喚醒
死亡狀态(TERMINATED)
- run方法執行完畢,線程正常退出
- 出現未捕獲的異常,線程意外停止
以上兩種情況将導緻線程終止
線程間切換
- BLOCKED進入RUNNABLE 線程擷取鎖後即可從BLOCKED進入RUNNABLE狀态,BLOCKED無逾時機制,如沒拿到鎖将一直阻塞
- WAITING/TIMED_WAITING進入RUNNABLE 等待中的線程首先被notify/notifyALl喚醒,進入BLOCKED阻塞狀态,擷取鎖後重新進入RUNNABLE狀态
Spring Bean的生命周期
概述
Spring Bean的主要生命周期為以下四個階段:
- 執行個體化(配置設定空間) 2. 前置/後置處理器
- 屬性指派(get/set/依賴注入)
- 初始化(init方法) 5. 前置後置處理器
- 銷毀(destroy方法)
Servlet生命周期
Servlet生命周期主要為以下四個階段:
- 加載階段(Loading)
- 初始化階段(Initialization)
- 處理請求階段(Request Handling)
- 銷毀階段(Destruction)
加載階段(Loading)
伺服器啟動時(第一次通路時,如果在注解中設定loadOnStartup為一個非-1的值,則設定為伺服器啟動時加載并建立執行個體),會加載 Servlet 類并建立對應的 Servlet 執行個體。這個過程隻會執行一次(懶加載機制)。
- 優點:節約記憶體開銷
- 缺點:第一個使用者的體驗感不好
- 把注解加上啟動參數loadOnStartup 非負數的時候容器加載的時候就啟動了
java
複制代碼
@WebServlet(value = "/myServlet",loadOnStartup = 0)
初始化階段(Initialization)
在 Servlet 執行個體被建立後,容器會調用其 init() 方法來完成初始化操作。在初始化期間,Servlet 可以讀取配置參數和其他上下文資訊,并準備好處理用戶端請求。
處理請求階段(Request Handling)
在 Servlet 初始化完成後,容器會将用戶端的請求轉發給 Servlet 執行個體,并調用其 service() 方法來處理請求。service() 方法會根據請求的類型(GET、POST 等)來調用對應的 doGet()、doPost() 等方法進行處理。可以通路多次
銷毀階段(Destruction)
當 Servlet 執行個體不再需要時,容器會調用其 destroy() 方法來釋放資源。這個過程隻會執行一次。(也可以手動調用destroy方法)
注意
Servlet 生命周期中的各個階段并非一成不變的。在某些情況下,例如 Servlet 初始化失敗或容器需要重新加載 Servlet 類時,Servlet 生命周期可能會被打斷或重新開始。