<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ā)安全?

          共 3108字,需瀏覽 7分鐘

           ·

          2022-05-11 02:51

          點(diǎn)擊上方“碼農(nóng)突圍”,馬上關(guān)注
          這里是碼農(nóng)充電第一站,回復(fù)“666”,獲取一份專屬大禮包
          真愛,請(qǐng)?jiān)O(shè)置“星標(biāo)”或點(diǎn)個(gè)“在看”
          來源:toutiao.com/article/6927297421139706376
          單例模式(Singleton)是程序設(shè)計(jì)中一種非常重要的設(shè)計(jì)模式,設(shè)計(jì)模式也是Java面試重點(diǎn)考察的一個(gè)方面。面試經(jīng)常會(huì)問到的一個(gè)問題是:SpringMVC中的Controller是單例還是多例,很多同學(xué)可能會(huì)想當(dāng)然認(rèn)為Controller是多例,其實(shí)不然。
          Tomcat官網(wǎng)截圖
          根據(jù)Tomcat官網(wǎng)中的介紹,對(duì)于一個(gè)瀏覽器請(qǐng)求,tomcat會(huì)指定一個(gè)處理線程,或是在線程池中選取空閑的,或者新建一個(gè)線程。
          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容器中,每個(gè)servlet是單例的。在SpringMVC中,Controller 默認(rèn)也是單例。 采用單例模式的最大好處,就是可以在高并發(fā)場(chǎng)景下極大地節(jié)省內(nèi)存資源,提高服務(wù)抗壓能力。
          單例模式容易出現(xiàn)的問題是:在Controller中定義的實(shí)例變量,在多個(gè)請(qǐng)求并發(fā)時(shí)會(huì)出現(xiàn)競爭訪問,Controller中的實(shí)例變量不是線程安全的。

          Controller不是線程安全的

          正因?yàn)镃ontroller默認(rèn)是單例,所以不是線程安全的。如果用SpringMVC 的 Controller時(shí),盡量不在 Controller中使用實(shí)例變量,否則會(huì)出現(xiàn)線程不安全性的情況,導(dǎo)致數(shù)據(jù)邏輯混亂。
          舉一個(gè)簡單的例子,在一個(gè)Controller中定義一個(gè)非靜態(tài)成員變量 num 。通過Controller成員方法來對(duì) num 增加。
          @Controller
          public?class?TestController?{
          ????private?int?num?=?0;

          ????@RequestMapping("/addNum")
          ????public?void?addNum()?{
          ????????System.out.println(++num);
          ????}
          }
          在本地運(yùn)行后:
          • 首先訪問 http:// localhost:8080 / addNum,得到的答案是1;
          • 再次訪問 http:// localhost:8080 / addNum,得到的答案是 2。
          兩次訪問得到的結(jié)果不同,num已經(jīng)被修改,并不是我們希望的結(jié)果,接口的冪等性被破壞。
          從這個(gè)例子可以看出,所有的請(qǐng)求訪問同一個(gè)Controller實(shí)例,Controller的私有成員變量就是線程共用的。某個(gè)請(qǐng)求對(duì)應(yīng)的線程如果修改了這個(gè)變量,那么在別的請(qǐng)求中也可以讀到這個(gè)變量修改后的的值。

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

          如果要保證Controller的線程安全,有以下解決辦法:
          • 盡量不要在 Controller 中定義成員變量 ;
          如果必須要定義一個(gè)非靜態(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容器中的對(duì)象(Bean )允許存在的限定場(chǎng)景,或者說是對(duì)象的存活空間。在對(duì)象進(jìn)入相應(yīng)的使用場(chǎng)景之前,IOC容器會(huì)生成并裝配這些對(duì)象;當(dāng)該對(duì)象不再處于這些使用場(chǎng)景的限定時(shí),容器通常會(huì)銷毀這些對(duì)象。
          Controller也是一個(gè)Bean,默認(rèn)的 Scope 屬性為Singleton ,也就是單例模式。如果Bean的 Scope 屬性設(shè)置為 prototype 的話,容器在接受到該類型對(duì)象的請(qǐng)求時(shí),每次都會(huì)重新生成一個(gè)新的對(duì)象給請(qǐng)求方。
          • Controller 中使用 ThreadLocal 變量。每一個(gè)線程都有一個(gè)變量的副本。
          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());
          ????}
          }
          以上代碼運(yùn)行以后,每次請(qǐng)求 http:// localhost:8080 / addNum , 得到的結(jié)果都是1。
          更嚴(yán)格的做法是用AtomicInteger類型定義成員變量,對(duì)于成員變量的操作使用AtomicInteger的自增方法完成。
          總的來說,還是盡量不要在 Controller 中定義成員變量為好。

          (完)

          碼農(nóng)突圍資料鏈接

          1、臥槽!字節(jié)跳動(dòng)《算法中文手冊(cè)》火了,完整版 PDF 開放下載!
          2、計(jì)算機(jī)基礎(chǔ)知識(shí)總結(jié)與操作系統(tǒng) PDF 下載
          3、艾瑪,終于來了!《LeetCode Java版題解》.PDF
          4、Github 10K+,《LeetCode刷題C/C++版答案》出爐.PDF

          歡迎添加魚哥個(gè)人微信:smartfish2020,進(jìn)粉絲群或圍觀朋友圈

          瀏覽 33
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  亚洲色图欧美视频 | 午夜乱伦福利 | 欧美三级片一区二区 | 乱码黄在线 | 国产一级黄色免费看 |