我們知道在Servlet第一次被調(diào)用的時(shí)候,Servlet容器會根據(jù)web.xml中配置的信息去實(shí)例化Servlet,而且這個(gè)Servlet只會被實(shí)例化一次。當(dāng)多個(gè)請求同時(shí)到來時(shí),可能會使用同一個(gè)Servlet進(jìn)行處理,這時(shí)候就會涉及到線程安全的問題。
糾結(jié)?。?!
Servlet的線程安全性?不確定
Servlet是單實(shí)例多線程的方式來處理請求,這應(yīng)該就是造成線程安全的主要原因了。我們知道Servlet本身是無狀態(tài)的,也就是說Servlet本身是線程安全的,但是為什么網(wǎng)上都說Servlet是線程不安全的呢?可能就是根據(jù)一句多個(gè)線程會同時(shí)訪問一個(gè)Servlet實(shí)例來判斷的把。
而Servlet是不是線程安全的,主要是由實(shí)現(xiàn)來決定的,如果一個(gè)Servlet實(shí)現(xiàn)有實(shí)例變量,并且會被多線程更改,這時(shí)候就不是線程安全的;而如果有實(shí)例變量,但是變量又是只讀的,這時(shí)候不涉及變量的更改,就是線程安全的;而如果一個(gè)Servlet實(shí)現(xiàn)沒有實(shí)例變量,都是局部變量,這時(shí)候也是線程安全的。
HttpServlet
HttpServlet是Servlet的一個(gè)實(shí)現(xiàn),繼承自GenericServlet,并且也是我們自定義Servlet所要繼承的一個(gè)類,HttpServlet是不是線程安全的,也不好說,也得根據(jù)在使用過程中不同情況來確定。另外對于Servlet中的屬性的使用也會對線程安全產(chǎn)生影響,見下面。
自定義的Servlet
通常我們開發(fā)自己的Servlet都是繼承HttpServlet,然后重寫相關(guān)方法,這時(shí)候線程安全和不安全都是靠我們自己來決定了,沒有實(shí)例變量的時(shí)候,就是線程安全的;而有實(shí)例變量的時(shí)候,并且會被改變,這時(shí)候就不是線程安全的了,需要使用其他手段保證線程安全。另外對于Servlet中的屬性的使用也會對線程安全產(chǎn)生影響,見下面。
如何控制Servlet的線程安全性
變量的線程安全
我們知道當(dāng)沒有實(shí)例變量的時(shí)候,就基本不存在線程不安全的問題了,所以不使用實(shí)例變量是一種方法。
屬性的線程安全
- ServletContext,不是線程安全的,多線程可以同時(shí)讀寫。使用時(shí)要注意。
- HttpSession,不是線程安全的,比如用戶打開多個(gè)瀏覽器窗口時(shí)候就會產(chǎn)生多個(gè)請求針對同一個(gè)session的操作。使用時(shí)要注意。
- ServletRequest,線程安全的,它對應(yīng)著一個(gè)request請求,所以說是線程安全的。
SingleThreadModel
我們還可以使用這個(gè)接口來創(chuàng)建自己的實(shí)現(xiàn),可以保證線程安全,同一時(shí)刻只有一個(gè)線程可以執(zhí)行Servlet實(shí)例的service方法,這就成了單線程了,該方式已經(jīng)被廢棄。
常用框架的線程安全性
SpringMVC,我們知道Spring的IOC容器默認(rèn)管理的bean是單實(shí)例的,對于SpringMVC的Controller來說也是單實(shí)例的,所以開發(fā)的時(shí)候需要保證線程安全。
Struts1中的action也是單實(shí)例的,使用的時(shí)候會有線程安全問題。
Struts2中Action會為每一個(gè)請求產(chǎn)生一個(gè)實(shí)例,所以不存在線程安全問題。
注意:當(dāng)使用Spring管理Struts2的Action時(shí),需要將Action的scope設(shè)置為prototype,因?yàn)镾pring IOC容器中bean默認(rèn)是單例的。
DispatcherServlet的線程安全性
在應(yīng)用啟動的時(shí)候,就會根據(jù)web.xml中配置的有關(guān)Spring和SpringMVC的配置啟動初始化,對于SpringMVC初始化的是DispatcherServlet,對于Servlet初始化只會進(jìn)行一次,并且只有一個(gè)實(shí)例,所以DispatcherServlet只會存在一個(gè)。
但是當(dāng)多線程同時(shí)訪問DispatcherServlet的時(shí)候是線程安全的,因?yàn)镈ispatcherServlet中的內(nèi)部屬性都不會影響線程安全,所以DispatcherServlet可以忽略線程安全的問題。
雖然DispatcherServlet可以認(rèn)為是線程安全的,但是SpringMVC中的Controller不是。Controller也是單例的,每個(gè)請求對應(yīng)一個(gè)Controller中的方法,方法如果沒有使用實(shí)例變量,可以認(rèn)為是線程安全的,但是如果有實(shí)例變量就要考慮線程安全的問題了。