一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

javaweb回顧第六篇談一談Servlet線程安全問題

 一本正經(jīng)地胡鬧 2019-07-01

前言:前面說了很多關(guān)于Servlet的一些基礎(chǔ)知識,這一篇主要說一下關(guān)于Servlet的線程安全問題。

1:多線程的Servlet模型

要想弄清Servlet線程安全我們必須先要明白Servlet實例是如何創(chuàng)建,它的模式是什么樣的。

在默認(rèn)的情況下Servlet容器對聲明的Servlet,只創(chuàng)建一個Servlet實例,那么如果要是多個客戶同時請求訪問這個Servlet,Servlet容器就采取多線程。下面我們來看一幅圖

從圖中可以看出當(dāng)客戶發(fā)送請求的時候,Servlet容器通過調(diào)度者線程從線程池中選擇一個線程,然后將請求傳遞給這個線程,然后在由這個線程去執(zhí)行Servlet的Service方法。

如果多個客戶端同時請求執(zhí)行一個Servlet實例,那么這個Servlet容器的Service方法將在多個線程中并發(fā)執(zhí)行(比喻圖中客戶1,客戶2,客戶3同時調(diào)用Servlet1實例,那么調(diào)度者線程就會在線程池中調(diào)用3個線程分別用于客戶1,2,3的請求,然后3個線程同時并發(fā)執(zhí)行Servlet1實例的Service方法)因為Servlet容器采取的單實例多線程的方法,那么就大大的減小了Servlet實例創(chuàng)建的開銷,提升了對請求的響應(yīng)時間,也是這樣引起了Servlet線程安全問題。所以我們下面說線程安全問題。

2:Servlet的線程安全

2.1:變量的線程安全

2.1.1:變量為啥會存在線程安全

我們先看一段代碼

復(fù)制代碼
 1 public class HelloWorldServlet extends HttpServlet{ 2     private String userName;    
 3     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException 4     { 5         userName=request.getParameter("userName"); 6         PrintWriter out=response.getWriter(); 7         if(userName!=null&&userName!="") 8         { 9             out.print(userName);10         }11         else {12             out.println("用戶名不存在");13         }14     }15 }
復(fù)制代碼

我們來分析這段代碼,現(xiàn)在有A,B2個客戶端同時請求HelloWorldServlet 這個實例,Servlet容器分配線程T1來服務(wù)A客戶端的請求,T2來服務(wù)B客戶端的請求,操作系統(tǒng)首先調(diào)用T1來運行,T1運行到第6行的時候得到了用戶名為張三并保存,此時時間片段到了,操作系統(tǒng)開始調(diào)用T2運行也運行到第6行但是這個用戶名是李四,此時時間片段又到了,操作系統(tǒng)又開始運行T1,從第7行開始運行,但是此時的用戶名卻成了李四,輸出的時候確實李四(很明顯是錯誤的),那么這個時候就出現(xiàn)了線程安全問題。

2.1.2:如何防止變量的線程安全

  1. 把全局變量改為局部變量

    1. 復(fù)制代碼
      protected  void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException
          {
              String userName=request.getParameter("userName");
              PrintWriter out=response.getWriter();if(userName!=null&&userName!="")
              {out.print(userName);
              }else {out.println("用戶名不存在");
              }
          }
      復(fù)制代碼

      因為每次調(diào)用這個方法的時候就會重寫對userName實例化這樣一來就不會存在線程安全問題了。

  2. 使用synchronized對doGet進行同步

       protected synchronized  void doGet(HttpServletRequest request, HttpServletResponse response) 

      采用這種方式明顯不合適,因為這樣T2必須要等T1執(zhí)行完畢以后才可以執(zhí)行,大大的影響了效率。

     3.如果是靜態(tài)資源則加上final表示這個資源不可以改變

      比喻 final static String url="jdbc:mysql://localhost:3306/blog";

2.2:屬性的線程安全

在Servlet中可以訪問保存在ServletContext,HttpSession,ServletRequest對象中的屬性,這三種對象都提供了getAttribute(),setAttribute() 方法用來對取和設(shè)置屬性,那么這三個不同范圍對象的屬性訪問是否線程安全呢,下面我們來一起看一下

2.2.1:ServletContext

首先明確一點是ServletContext是被應(yīng)用程序下所有的Servlet所共享的,那么ServletContext對象就可以被web應(yīng)用程序所有的Servlet訪問,那么這樣一來多個Servlet就可以同時對ServletContext的屬性進行設(shè)置和訪問,所以這個時候就會出現(xiàn)線程安全問題。我們來看一段代碼

復(fù)制代碼
 1 protected void service(HttpServletRequest request, HttpServletResponse response) 2     { 3         String userName=request.getParameter("userName"); 4         if ("login") { 5             List list=(List)getServletContext().getAttribute("userList"); 6             list.add(userName); 7         } 8         else { 9             List list=(List)getServletContext().getAttribute("userList");10             list.remove(userName);11         }12     }
復(fù)制代碼
復(fù)制代碼
 1 protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException 2     { 3         List list=(List)getServletContext().getAttribute("userList"); 4         int count=list.size(); 5         for(int i=0;i<count;i++) 6         { 7             PrintWriter out=response.getWriter(); 8             out.println(list.get(i)); 9         }10     }
復(fù)制代碼

第一段代碼是當(dāng)用戶登錄以后把用戶名保存在ServletContext屬性中,如果不是登錄就刪除這個用戶

第二段代碼就是查看應(yīng)用程序所有的用戶登錄情況,那么我們看如何出現(xiàn)線程安全問題的

當(dāng)2個請求并發(fā)執(zhí)行的時候,可能第二段代碼剛剛執(zhí)行第五行的時候獲取的count=5;但是呢另一個請求恰好執(zhí)行第一段代碼第十行,把其中的某個用戶刪除了,當(dāng)?shù)诙未a在循環(huán)遍歷的時候運行到count=5的時候就會數(shù)組超過索性界限異常。那么此時就出現(xiàn)了線程安全問題。那么遇到這樣的問題怎么解決呢,第一就是把ServletContext屬性值進行拷貝保存起來,第二就是采用synchronized 進行同步(這個效率低)

2.2.2:HttpSession

httpSession對象在用戶會話期間存活的,不像ServletContext一樣被所有的用戶共享,所以說一個HttpSession在同一個時刻只用一個用戶進行請求的,因此理論看來Session是線程安全的,其實并不是如此,這個和瀏覽器有關(guān),在上一篇Session我們說過,同一個瀏覽器只能具有一個Session,那么這樣一來就會出現(xiàn)Session線程安全問題,看如下代碼

復(fù)制代碼
 1     protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException 2     { 3         String commandType=request.getParameter("commandType"); 4         HttpSession session=request.getSession(); 5         List list=(List)session.getAttribute("items"); 6         if ("add".equals(commandType)) { 7             //添加 8         } 9         else if("delete".equals(commandType)){10             //刪除11         }12         else {13             int count=list.size();14             for (int i = 0; i < count; i++) {15                 //遍歷16             }17         }18     }
復(fù)制代碼

上面是一個添加物品信息的一個簡單偽代碼,如果用戶現(xiàn)在在一個瀏覽器窗口刪除一件物品的同時又在另一個窗口去獲取所有的物品這個時候就會出現(xiàn)線程安全,從上面的介紹得知Servlet容器是多線程單實例的,這個時候Servlet容器就會分配2個線程來分別為刪除物品和獲取所有物品進行服務(wù),如果其中一個線程剛好運行到14行時間片段結(jié)束,另一個線程這個時候又運行第10行刪除一條物品信息,然后第一個線程又開始運行第15開始遍歷,此時同樣出現(xiàn)了上面數(shù)組索性超出范圍的錯誤。

2.2.3:HttpRequest

httprequest是線程安全的,因為每個請求都會調(diào)用Service,都會創(chuàng)建一個新的HttpRequest和局部變量一樣。

3:SingleThreadModel

從名字很好理解,就是單線程模式,也就是說如果Servlet實現(xiàn)了SingleThreadModel接口,Servlet容器就保證一個時刻只有一個線程在Servlet實例的Service方法運行(其實和同步差不多)這樣一來就很影響效率了,現(xiàn)在SingleThreadModel已經(jīng)被廢棄了,值得注意的是就算Servlet實現(xiàn)了SingleThreadModel接口并不一定保證線程安全,比喻上面說的ServletContext,HttpSession,因為ServletContext是應(yīng)用程序共享的,可能2個Servlet實例同時運行造成線程安全,HttpSession因為是在同一瀏覽器共享的所以也會出現(xiàn)(雖然可能性很?。?/p>

4:總結(jié)

1:只要我們了解Servlet容器工作的模式,可能就能夠理解為什么Servlet會出現(xiàn)線程安全問題,所以一定牢記Servlet容器是多線程單實例的模型

2:避免使用全局變量,最好是使用局部變量,其實這本身也是一個好的編程習(xí)慣

3:應(yīng)該使用只讀的實例變量和靜態(tài)變量(就是前面加上final意為不可改變)

4:不要在Servlet上自己創(chuàng)建線程,因為Servlet容器已經(jīng)幫我們做好了。

5:如果要修改共享對象的時候記得要同步,盡量縮小同步的范圍(比喻修改Session時候直接使用synchronized(Session)即可),避免影響性能

轉(zhuǎn)自 https://www.cnblogs.com/LipeiNet/p/5699944.html

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    99热在线精品视频观看| 成人免费在线视频大香蕉| 麻豆一区二区三区精品视频| 国产精品欧美一区两区| 丝袜人妻夜夜爽一区二区三区| 欧美国产日韩在线综合| 成人免费在线视频大香蕉| 亚洲精品福利入口在线| 人妻久久一区二区三区精品99| 好吊妞视频只有这里有精品| 欧美黑人巨大一区二区三区| 精品国产亚洲区久久露脸| 粉嫩国产一区二区三区在线| 老熟妇2久久国内精品| 日本人妻丰满熟妇久久| 午夜福利黄片免费观看| 日韩和欧美的一区二区三区 | 美女极度色诱视频在线观看| 亚洲天堂精品一区二区| 久热青青草视频在线观看| 亚洲男人天堂网在线视频| 又大又紧又硬又湿又爽又猛| 91超频在线视频中文字幕| 人妻少妇久久中文字幕久久| 在线一区二区免费的视频| 开心久久综合激情五月天| 日本精品啪啪一区二区三区| 色偷偷亚洲女人天堂观看| 精品亚洲av一区二区三区| 欧美一区二区三区性视频| 中文字幕日产乱码一区二区| 亚洲欧美日韩网友自拍| 国产成人午夜av一区二区| 91精品视频免费播放| 99视频精品免费视频| 欧美自拍系列精品在线| 日韩人妻免费视频一专区| 日韩国产欧美中文字幕| 色婷婷在线视频免费播放| 亚洲最大的中文字幕在线视频| 午夜国产精品福利在线观看|