JavaWeb中Servlet的生命周期及線程安全問題詳解
一、Servlet的生命周期
Servlet 生命周期可被定義為從創(chuàng)建直到毀滅的整個(gè)過程。
它分為四個(gè)階段:
- Servlet容器創(chuàng)建Servlet的實(shí)例。
- 該容器調(diào)用init ( ServletConfig )方法。
- Servlet 調(diào)用service()方法來處理客戶端的請(qǐng)求。
- Servlet 銷毀前調(diào)用destroy()方法。
1、加載Servlet
Servlet生命周期的第一個(gè)階段是通過Servlet容器來實(shí)現(xiàn)加載以及初始化。
Servlet容器加載所執(zhí)行的操作:
(1)加載Servlet類
(2)創(chuàng)建Servlet并實(shí)例化
2、init() 方法
init 方法被設(shè)計(jì)成只調(diào)用一次。它在第一次創(chuàng)建 Servlet 時(shí)被調(diào)用,在后續(xù)每次用戶請(qǐng)求時(shí)不再調(diào)用。因此,它是用于一次性初始化。
當(dāng)用戶調(diào)用一個(gè) Servlet 時(shí),就會(huì)創(chuàng)建一個(gè) Servlet 實(shí)例,每一個(gè)用戶請(qǐng)求都會(huì)產(chǎn)生一個(gè)新的線程,適當(dāng)?shù)臅r(shí)候移交給 doGet 或 doPost 方法。init() 方法簡(jiǎn)單地創(chuàng)建或加載一些數(shù)據(jù),這些數(shù)據(jù)將被用于 Servlet 的整個(gè)生命周期。
init 方法的定義如下:
public void init() throws ServletException { // 初始化代碼... }
3、service() 方法
service() 方法是執(zhí)行實(shí)際任務(wù)的主要方法。Servlet 容器(即 Web 服務(wù)器)調(diào)用 service() 方法來處理來自客戶端(瀏覽器)的請(qǐng)求,并把格式化的響應(yīng)寫回給客戶端。
每次服務(wù)器接收到一個(gè) Servlet 請(qǐng)求時(shí),服務(wù)器會(huì)產(chǎn)生一個(gè)新的線程并調(diào)用服務(wù)。service() 方法檢查 HTTP 請(qǐng)求類型(GET、POST、PUT、DELETE 等),并在適當(dāng)?shù)臅r(shí)候調(diào)用 doGet、doPost、doPut,doDelete 等方法。
下面是該方法的特征:
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException{ }
4、destroy() 方法
destroy() 方法只會(huì)被調(diào)用一次,在 Servlet 生命周期結(jié)束時(shí)被調(diào)用。destroy() 方法可以讓您的 Servlet 關(guān)閉數(shù)據(jù)庫連接、停止后臺(tái)線程、把 Cookie 列表或點(diǎn)擊計(jì)數(shù)器寫入到磁盤,并執(zhí)行其他類似的清理活動(dòng)。
destroy 方法定義如下所示:
public void destroy() { // 終止化代碼... }
5、下圖顯示了一個(gè)典型的 Servlet 生命周期方案:
二、Servlet的線程安全問題
要了解Servlet的線程安全問題,我們首先要了解Servlet的多線程機(jī)制。
1、Servlet的多線程機(jī)制
Servlet體系結(jié)構(gòu)是建立在Java多線程機(jī)制之上的,它的生命周期是由Web容器負(fù)責(zé)的。當(dāng)客戶端第一次請(qǐng)求某個(gè)Servlet時(shí),Servlet容器將會(huì)根據(jù)web.xml配置文件實(shí)例化這個(gè)Servlet類。當(dāng)有新的客戶端請(qǐng)求該 Servlet時(shí),一般不會(huì)再實(shí)例化該Servlet類,也就是有多個(gè)線程在使用這個(gè)實(shí)例。Servlet容器會(huì)自動(dòng)使用線程池等技術(shù)來支持系統(tǒng)的運(yùn)行。
這樣,當(dāng)兩個(gè)或多個(gè)線程同時(shí)訪問同一個(gè)Servlet時(shí),可能會(huì)發(fā)生多個(gè)線程同時(shí)訪問同一資源的情況,數(shù)據(jù)可能會(huì)變得不一致。
所以在用Servlet構(gòu)建的Web應(yīng)用時(shí)如果不注意線程安全的問題,會(huì)使所寫的Servlet程序有難以發(fā)現(xiàn)的錯(cuò)誤。
2、Servlet的線程安全問題
Servlet是線程不安全的。
Servlet的線程安全問題主要是由于實(shí)例變量使用不當(dāng)而引起的。因?yàn)樗J(rèn)是單例模式,如果提供成員變量,多個(gè)線程對(duì)成員變量進(jìn)行操作,將發(fā)生并發(fā)問題。
3、如何解決Servlet的線程安全問題
- 如果某個(gè)Servlet實(shí)現(xiàn)了SingleThreadModel接口,那么Servlet引擎將以單線程模式來調(diào)用其service方法。但是本質(zhì)上面并沒有解決線程安全問題,因?yàn)槠洳捎玫姆绞绞歉鶕?jù)并發(fā)請(qǐng)求去產(chǎn)生多個(gè)Servlet實(shí)例對(duì)象,并發(fā)的每個(gè)線程分別調(diào)用一個(gè)獨(dú)立的Servlet實(shí)例對(duì)象,而真正意義上解決多線程安全問題是指一個(gè)Servlet實(shí)例對(duì)象被多個(gè)線程同時(shí)調(diào)用的問題。而不是多個(gè)線程調(diào)用多個(gè)Servlet實(shí)例。
- 利用synchronized同步代碼,將我們有并發(fā)問題的代碼轉(zhuǎn)化為同步代碼,但是這樣做的一個(gè)壞處就是,如果遇到高并發(fā)的情況下,我們的用戶可能會(huì)因?yàn)橥酱a的問題而造成等待的時(shí)間比較久這樣的問題,所以,要慎用。
- 減少引起并發(fā)問題的資源代碼,從根本上解決Servlet線程安全問題,其實(shí),造成Servlet線程的問題好多都是因?yàn)樽兞吭O(shè)置不正確造成的,我們應(yīng)該盡可能去避免這樣的問題。
4、總結(jié)
- servlet是線程不安全的,而造成這種原因主要是以為實(shí)例變量不正確的使用。
- 盡量不使用synchronized來解決Servlet線程安全問題
- Servlet的線程安全問題只有在大量的并發(fā)訪問時(shí)才會(huì)顯現(xiàn)出來,并且很難發(fā)現(xiàn),因此在編寫Servlet程序時(shí)要特別注意。線程安全問題主要是由實(shí)例變量造成的,因此在Servlet中應(yīng)避免使用實(shí)例變量。如果應(yīng)用程序設(shè)計(jì)無法避免使用實(shí)例變量,那么使用同步來保護(hù)要使用的實(shí)例變量,但為保證系統(tǒng)的最佳性能,應(yīng)該同步可用性最小的代碼路徑。
到此這篇關(guān)于JavaWeb中Servlet的生命周期及線程安全問題詳解的文章就介紹到這了,更多相關(guān)Servlet的生命周期及線程安全內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java實(shí)現(xiàn)搶紅包算法(公平版和手速版)
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)搶紅包算法,分為公平版和手速版,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-09-09Mac?Maven環(huán)境搭建安裝和配置超詳細(xì)步驟
這篇文章主要給大家介紹了關(guān)于Mac?Maven環(huán)境搭建安裝和配置的超詳細(xì)步驟,Maven是一種常用的Java構(gòu)建工具,它可以自動(dòng)化構(gòu)建、測(cè)試和打包Java項(xiàng)目,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-10-10idea創(chuàng)建properties文件,解決亂碼問題
這篇文章主要介紹了idea創(chuàng)建properties文件,解決亂碼問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07