<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          如何保證 Controller 的并發(fā)安全?

          共 3184字,需瀏覽 7分鐘

           ·

          2022-05-11 02:39

          點擊關(guān)注公眾號,Java干貨及時送達??

          單例模式(Singleton)是程序設(shè)計中一種非常重要的設(shè)計模式,設(shè)計模式也是Java面試重點考察的一個方面。面試經(jīng)常會問到的一個問題是:SpringMVC中的Controller是單例還是多例,很多同學可能會想當然認為Controller是多例,其實不然。

          Tomcat官網(wǎng)截圖

          根據(jù)Tomcat官網(wǎng)中的介紹,對于一個瀏覽器請求,tomcat會指定一個處理線程,或是在線程池中選取空閑的,或者新建一個線程。

          Each incoming request requires a thread for the duration of that request. If more simultaneous requests are received than can be handled by the currently available request processing threads, additional threads will be created up to the configured maximum (the value of the maxThreads attribute). If still more simultaneous requests are received, they are stacked up inside the server socket created by the Connector, up to the configured maximum (the value of the acceptCountattribute). Any further simultaneous requests will receive "connection refused" errors, until resources are available to process them.

          —— https://tomcat.apache.org/tomcat-7.0-doc/config/http.html

          在Tomcat容器中,每個servlet是單例的。在SpringMVC中,Controller 默認也是單例。 采用單例模式的最大好處,就是可以在高并發(fā)場景下極大地節(jié)省內(nèi)存資源,提高服務(wù)抗壓能力。

          單例模式容易出現(xiàn)的問題是:在Controller中定義的實例變量,在多個請求并發(fā)時會出現(xiàn)競爭訪問,Controller中的實例變量不是線程安全的。

          Controller不是線程安全的

          正因為Controller默認是單例,所以不是線程安全的。如果用SpringMVC 的 Controller時,盡量不在 Controller中使用實例變量,否則會出現(xiàn)線程不安全性的情況,導致數(shù)據(jù)邏輯混亂。

          舉一個簡單的例子,在一個Controller中定義一個非靜態(tài)成員變量 num 。通過Controller成員方法來對 num 增加。

          @Controller
          public?class?TestController?{
          ????private?int?num?=?0;

          ????@RequestMapping("/addNum")
          ????public?void?addNum()?{
          ????????System.out.println(++num);
          ????}
          }

          在本地運行后:

          • 首先訪問 http:// localhost:8080 / addNum,得到的答案是1;
          • 再次訪問 http:// localhost:8080 / addNum,得到的答案是 2。

          兩次訪問得到的結(jié)果不同,num已經(jīng)被修改,并不是我們希望的結(jié)果,接口的冪等性被破壞。

          從這個例子可以看出,所有的請求訪問同一個Controller實例,Controller的私有成員變量就是線程共用的。某個請求對應的線程如果修改了這個變量,那么在別的請求中也可以讀到這個變量修改后的的值。

          Controller并發(fā)安全的解決辦法

          如果要保證Controller的線程安全,有以下解決辦法:

          • 盡量不要在 Controller 中定義成員變量 ;

          如果必須要定義一個非靜態(tài)成員變量,那么可以通過注解 @Scope(“prototype”) ,將Controller設(shè)置為多例模式。

          @Controller
          @Scope(value="prototype")
          public?class?TestController?{
          ????private?int?num?=?0;

          ????@RequestMapping("/addNum")
          ????public?void?addNum()?{
          ????????System.out.println(++num);
          ????}
          }

          Scope屬性是用來聲明IOC容器中的對象(Bean )允許存在的限定場景,或者說是對象的存活空間。在對象進入相應的使用場景之前,IOC容器會生成并裝配這些對象;當該對象不再處于這些使用場景的限定時,容器通常會銷毀這些對象。

          Controller也是一個Bean,默認的 Scope 屬性為Singleton ,也就是單例模式。如果Bean的 Scope 屬性設(shè)置為 prototype 的話,容器在接受到該類型對象的請求時,每次都會重新生成一個新的對象給請求方。

          • Controller 中使用 ThreadLocal 變量。每一個線程都有一個變量的副本。
          public?class?TestController?{
          ????private?int?num?=?0;
          ????private?final?ThreadLocal??uniqueNum?=
          ?????????????new?ThreadLocal??()?{
          ?????????????????@Override?protected?Integer?initialValue()?{
          ?????????????????????return?num;
          ?????????????????}
          ?????????????};

          ????@RequestMapping("/addNum")
          ????public?void?addNum()?{
          ????????int?unum?=?uniqueNum.get();
          ???????uniqueNum.set(++unum);
          ???????System.out.println(uniqueNum.get());
          ????}
          }

          以上代碼運行以后,每次請求 http:// localhost:8080 / addNum , 得到的結(jié)果都是1。

          更嚴格的做法是用AtomicInteger類型定義成員變量,對于成員變量的操作使用AtomicInteger的自增方法完成。

          總的來說,還是盡量不要在 Controller 中定義成員變量為好。

          來源:toutiao.com/article/6927297421139706376

          1.?實體映射最強工具類:MapStruct 真香!

          2.?同事多線程使用不當導致OOM,被我懟了一頓

          3.?你見過哪些目瞪口呆的 Java 代碼技巧?

          4.?完爆 90% 的數(shù)據(jù)庫性能毛病!

          最近面試BAT,整理一份面試資料Java面試BATJ通關(guān)手冊,覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務(wù)、數(shù)據(jù)庫、數(shù)據(jù)結(jié)構(gòu)等等。

          獲取方式:點“在看”,關(guān)注公眾號并回復?Java?領(lǐng)取,更多內(nèi)容陸續(xù)奉上。

          PS:因公眾號平臺更改了推送規(guī)則,如果不想錯過內(nèi)容,記得讀完點一下在看,加個星標,這樣每次新文章推送才會第一時間出現(xiàn)在你的訂閱列表里。

          “在看”支持小哈呀,謝謝啦??

          瀏覽 58
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  在线视频麻豆 | 中国婬乱a一级毛多女 | 老司机大香蕉 | 天堂网www在线资源网 | 日本黄色免费电影 |