我們知道在Servlet第一次被調(diào)用的時(shí)候橄登,Servlet容器會(huì)根據(jù)web.xml中配置的信息去實(shí)例化Servlet栈虚,而且這個(gè)Servlet只會(huì)被實(shí)例化一次心傀。當(dāng)多個(gè)請(qǐng)求同時(shí)到來(lái)時(shí)猾警,可能會(huì)使用同一個(gè)Servlet進(jìn)行處理炬太,這時(shí)候就會(huì)涉及到線程安全的問(wèn)題灸蟆。
糾結(jié)!G鬃濉炒考!
Servlet的線程安全性可缚?不確定
Servlet是單實(shí)例多線程的方式來(lái)處理請(qǐng)求,這應(yīng)該就是造成線程安全的主要原因了斋枢。我們知道Servlet本身是無(wú)狀態(tài)的帘靡,也就是說(shuō)Servlet本身是線程安全的,但是為什么網(wǎng)上都說(shuō)Servlet是線程不安全的呢瓤帚?可能就是根據(jù)一句多個(gè)線程會(huì)同時(shí)訪問(wèn)一個(gè)Servlet實(shí)例來(lái)判斷的把描姚。
而Servlet是不是線程安全的,主要是由實(shí)現(xiàn)來(lái)決定的戈次,如果一個(gè)Servlet實(shí)現(xiàn)有實(shí)例變量轩勘,并且會(huì)被多線程更改,這時(shí)候就不是線程安全的怯邪;而如果有實(shí)例變量绊寻,但是變量又是只讀的,這時(shí)候不涉及變量的更改悬秉,就是線程安全的榛斯;而如果一個(gè)Servlet實(shí)現(xiàn)沒(méi)有實(shí)例變量,都是局部變量搂捧,這時(shí)候也是線程安全的驮俗。
HttpServlet
HttpServlet是Servlet的一個(gè)實(shí)現(xiàn),繼承自GenericServlet允跑,并且也是我們自定義Servlet所要繼承的一個(gè)類(lèi)王凑,HttpServlet是不是線程安全的,也不好說(shuō)聋丝,也得根據(jù)在使用過(guò)程中不同情況來(lái)確定索烹。另外對(duì)于Servlet中的屬性的使用也會(huì)對(duì)線程安全產(chǎn)生影響,見(jiàn)下面弱睦。
自定義的Servlet
通常我們開(kāi)發(fā)自己的Servlet都是繼承HttpServlet百姓,然后重寫(xiě)相關(guān)方法,這時(shí)候線程安全和不安全都是靠我們自己來(lái)決定了况木,沒(méi)有實(shí)例變量的時(shí)候垒拢,就是線程安全的;而有實(shí)例變量的時(shí)候火惊,并且會(huì)被改變求类,這時(shí)候就不是線程安全的了,需要使用其他手段保證線程安全屹耐。另外對(duì)于Servlet中的屬性的使用也會(huì)對(duì)線程安全產(chǎn)生影響尸疆,見(jiàn)下面。
如何控制Servlet的線程安全性
變量的線程安全
我們知道當(dāng)沒(méi)有實(shí)例變量的時(shí)候,就基本不存在線程不安全的問(wèn)題了寿弱,所以不使用實(shí)例變量是一種方法犯眠。
屬性的線程安全
- ServletContext,不是線程安全的症革,多線程可以同時(shí)讀寫(xiě)阔逼。使用時(shí)要注意。
- HttpSession地沮,不是線程安全的嗜浮,比如用戶打開(kāi)多個(gè)瀏覽器窗口時(shí)候就會(huì)產(chǎn)生多個(gè)請(qǐng)求針對(duì)同一個(gè)session的操作。使用時(shí)要注意摩疑。
- ServletRequest危融,線程安全的,它對(duì)應(yīng)著一個(gè)request請(qǐng)求雷袋,所以說(shuō)是線程安全的吉殃。
SingleThreadModel
我們還可以使用這個(gè)接口來(lái)創(chuàng)建自己的實(shí)現(xiàn)楷怒,可以保證線程安全蛋勺,同一時(shí)刻只有一個(gè)線程可以執(zhí)行Servlet實(shí)例的service方法,這就成了單線程了鸠删,該方式已經(jīng)被廢棄抱完。
常用框架的線程安全性
SpringMVC,我們知道Spring的IOC容器默認(rèn)管理的bean是單實(shí)例的刃泡,對(duì)于SpringMVC的Controller來(lái)說(shuō)也是單實(shí)例的巧娱,所以開(kāi)發(fā)的時(shí)候需要保證線程安全。
Struts1中的action也是單實(shí)例的烘贴,使用的時(shí)候會(huì)有線程安全問(wèn)題禁添。
Struts2中Action會(huì)為每一個(gè)請(qǐng)求產(chǎn)生一個(gè)實(shí)例,所以不存在線程安全問(wèn)題桨踪。
注意:當(dāng)使用Spring管理Struts2的Action時(shí)老翘,需要將Action的scope設(shè)置為prototype,因?yàn)镾pring IOC容器中bean默認(rèn)是單例的锻离。
DispatcherServlet的線程安全性
在應(yīng)用啟動(dòng)的時(shí)候铺峭,就會(huì)根據(jù)web.xml中配置的有關(guān)Spring和SpringMVC的配置啟動(dòng)初始化,對(duì)于SpringMVC初始化的是DispatcherServlet纳账,對(duì)于Servlet初始化只會(huì)進(jìn)行一次逛薇,并且只有一個(gè)實(shí)例,所以DispatcherServlet只會(huì)存在一個(gè)疏虫。
但是當(dāng)多線程同時(shí)訪問(wèn)DispatcherServlet的時(shí)候是線程安全的,因?yàn)镈ispatcherServlet中的內(nèi)部屬性都不會(huì)影響線程安全,所以DispatcherServlet可以忽略線程安全的問(wèn)題卧秘。
雖然DispatcherServlet可以認(rèn)為是線程安全的呢袱,但是SpringMVC中的Controller不是。Controller也是單例的翅敌,每個(gè)請(qǐng)求對(duì)應(yīng)一個(gè)Controller中的方法羞福,方法如果沒(méi)有使用實(shí)例變量,可以認(rèn)為是線程安全的蚯涮,但是如果有實(shí)例變量就要考慮線程安全的問(wèn)題了治专。