Servlet是web體系里面最重要的部分,下面羅列幾道常見的面試題,小伙伴們一定要好好記住哈。
1.Servlet是單例的嗎,如何證明?
Servlet一般都是單例的,并且是多線程的。如何證明Servlet是單例模式呢?很簡單,重寫Servlet的init方法,或者添加一個(gè)構(gòu)造方法。然后,在web.xml中配置。如:
<?xml?version="1.0"?encoding="UTF-8"?>
<web-app?xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"?xmlns="http://xmlns.jcp.org/xml/ns/javaee"?xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee?http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"?id="WebApp_ID"?version="3.1">
??
??<servlet>
????<servlet-name>MyServlet</servlet-name>
????<servlet-class>web.MyServlet</servlet-class>
??</servlet>
??<servlet-mapping>
????<servlet-name>MyServlet</servlet-name>
????<url-pattern>/hello</url-pattern>
??</servlet-mapping>
</web-app>
然后是MyServlet
public?class?MyServlet?extends?HttpServlet{
?
?public?MyServlet(){
??System.out.println("MyServlet構(gòu)造函數(shù)調(diào)用了");
?}
?@Override
?public?void?init()?throws?ServletException?{
??System.out.println("MyServlet初始化");
?}
?
?
}
啟動(dòng)Tomcat,不管你訪問多少次這個(gè)Servlet,init方法和構(gòu)造器都只會(huì)執(zhí)行1次。
2.如何讓Servlet變成多例
方法1.實(shí)現(xiàn) SingleThreadModel 接口(不推薦,官方已經(jīng)將這個(gè)接口廢棄)
public?class?MyServlet?extends?HttpServlet?implements?SingleThreadModel{
?
?public?MyServlet(){
??System.out.println("MyServlet構(gòu)造函數(shù)調(diào)用了");
?}
?@Override
?public?void?init()?throws?ServletException?{
??System.out.println("MyServlet初始化");
?}
}
SingleThreadModel
的意思是“單線程模式”,如果servlet實(shí)現(xiàn)了該接口,會(huì)確保不會(huì)有兩個(gè)線程同時(shí)執(zhí)行servlet的service方法。
servlet容器通過同步化訪問servlet的單實(shí)例來保證,也可以通過維持servlet的實(shí)例池,對于新的請求會(huì)分配給一個(gè)空閑的servlet。源碼中,最多會(huì)生成20個(gè)實(shí)例。
方法2. 在web.xml中多配置一個(gè)Servlet
哪怕是同一個(gè)Servlet,你在web.xml中配置幾個(gè),就會(huì)有幾個(gè)實(shí)例。
3.你能證明Servlet線程不安全嗎?
Servlet默認(rèn)是線程不安全的!
Servlet體系結(jié)構(gòu)是建立在Java多線程機(jī)制之上的,它的生命周期是由Web容器負(fù)責(zé)的。
當(dāng)客戶端第一次請求某個(gè)Servlet時(shí),Servlet容器將會(huì)根據(jù)web.xml配置文件實(shí)例化這個(gè)Servlet類。
當(dā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ò)誤。
下面舉一個(gè)例子來說明,為什么Servlet是線程不安全的。
public?class?MyServlet?extends?HttpServlet{
?
?String?message;
?@Override
?protected?void?doGet(HttpServletRequest?req,?HttpServletResponse?resp)?throws?ServletException,?IOException?{
??message?=?req.getParameter("message");
??PrintWriter?out?=?resp.getWriter();
??//故意延時(shí)5秒鐘,使得下一次請求過來的時(shí)候,message的值還沒有返回就被覆蓋了
??try?{
???Thread.sleep(5000);
??}?catch?(InterruptedException?e)?{
???e.printStackTrace();
??}
??out.write(message);
??out.flush();
??out.close();
??
?}
}
打開兩個(gè)瀏覽器,分別訪問:
http://localhost:8080/web/hello?message=jack
http://localhost:8080/web/hello?message=rose
因?yàn)橛?秒的延時(shí),所以可能就會(huì)出現(xiàn)第一個(gè)Servlet還沒返回呢,第二個(gè)Servlet就進(jìn)來了。于是,把message的值給沖掉了。如下圖
石錘了,Servlet是線程不安全的。
4.你怎么設(shè)計(jì)一個(gè)線程安全的Servlet?
1.最直接的辦法,就是用上面的SingleThreadModel接口
既然單例會(huì)有共享實(shí)例變量導(dǎo)致線程不安全的問題,那就改成多例的唄。
但是,這個(gè)接口都已經(jīng)被官方廢棄了,這就說明官方也不推薦這么做。原因很簡單,那就是這樣一來會(huì)有很多個(gè)實(shí)例,性能的代價(jià)太大了。
-
用同步鎖
這也是非常容易想到的辦法,把當(dāng)前對象鎖起來,不返回不給其他用戶插入(怎么有點(diǎn)怪怪的?)文章來源:http://www.zghlxwxcb.cn/news/detail-458701.html
@Override
protected?void?doGet(HttpServletRequest?req,?HttpServletResponse?resp)?throws?ServletException,?IOException?{
?
?synchronized(this){
??message?=?req.getParameter("message");
??PrintWriter?out?=?resp.getWriter();
??//故意延時(shí)5秒鐘,使得下一次請求過來的時(shí)候,message的值還沒有釋放
??try?{
???Thread.sleep(5000);
??}?catch?(InterruptedException?e)?{
???e.printStackTrace();
??}
??out.write(message);
??out.flush();
??out.close();
?
?}
?
}
這樣的代價(jià)就是等待時(shí)間更長了,參考火車上的的衛(wèi)生間,這就是同步鎖。文章來源地址http://www.zghlxwxcb.cn/news/detail-458701.html
-
盡量別用實(shí)例變量,用局部變量代替
到了這里,關(guān)于如何證明Servlet是單例的?的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!