spring mvc controller 高並發問題


springMVC一個Controller處理所有用戶請求的並發問題

有狀態和無狀態的對象基本概念
有狀態對象(Stateful Bean),就是有實例變量的對象 ,可以保存數據,是非線程安全的。一般是prototype scope。
無狀態對象(Stateless Bean),就是沒有實例變量的對象,不能保存數據,是不變類,是線程安全的。一般是singleton scope。

如Struts2中的Action,假如內部有實例變量User,當調用新增用戶方法時,user是用來保存數據,那么此action是有狀態對象。多個線程同時訪問此action時 會造成user變量的不一致。所以action的scope要設計成prototype,或者,User類放到threadLocal里來保持多個線程不會造成User變量的亂串(此種場景沒必要放到threadLocal內)。

而Service內部一般只有dao實例變量 如userDao, 因為userDao是無狀態的對象(內部無實例變量且不能保存數據),所以service也是無狀態的對象。

對於那些會以多線程運行的單例類

局部變量不會受多線程影響,
成員變量會受到多線程影響。

多個線程調用同一個對象的同一個方法: 
如果方法里無成員變量,那么不受任何影響;
如果方法里有成員變量,只有讀操作,不受影響;存在寫操作,考慮多線程影響值;

例如Web應用中的Servlet,每個方法中對局部變量的操作都是在線程自己獨立的內存區域內完成的,所以是線程安全的。 
對於成員變量的操作,可以使用ThreadLocal來保證線程安全。 

springMVC中,一般Controller、service、DAO層的scope均是singleton;

每個請求都是單獨的線程,即使同時訪問同一個Controller對象,因為並沒有修改Controller對象,相當於針對Controller對象而言,只是讀操作,沒有寫操作,不需要做同步處理。

Service層、Dao層用默認singleton就行,雖然Service類也有dao這樣的屬性,但dao這些類都是沒有狀態信息的,也就是 相當於不變(immutable)類,所以不影響。

Struts2中的Action因為會有User、BizEntity這樣的實例對象,是有狀態信息 的,在多線程環境下是不安全的,所以Struts2默認的實現是Prototype模式。在Spring中,Struts2的Action中scope 要配成prototype作用域。

Spring並發訪問的線程安全性問題  

由於Spring MVC默認是Singleton的,所以會產生一個潛在的安全隱患。根本核心是instance變量保持狀態的問題。這意味着每個request過來,系統都會用原有的instance去處理,這樣導致了兩個結果:
一是我們不用每次創建Controller,
二是減少了對象創建和垃圾收集的時間;
由於只有一個Controller的instance,當多個線程同時調用它的時候,它里面的instance變量就不是線程安全的了,會發生竄數據的問題。
當然大多數情況下,我們根本不需要考慮線程安全的問題,比如dao,service等,除非在bean中聲明了實例變量。因此,我們在使用spring mvc 的contrller時,應避免在controller中定義實例變量。


有幾種解決方法:
1、在控制器中不使用實例變量
2、將控制器的作用域從單例改為原型,即在spring配置文件Controller中聲明 scope="prototype",每次都創建新的controller
3、在Controller中使用ThreadLocal變量

這幾種做法有好有壞,第一種,需要開發人員擁有較高的編程水平與思想意識,在編碼過程中力求避免出現這種BUG,而第二種則是容器自動的對每個請求產生一個實例,由JVM進行垃圾回收,因此做到了線程安全。
使用第一種方式的好處是實例對象只有一個,所有的請求都調用該實例對象,速度和性能上要優於第二種,不好的地方,就是需要程序員自己去控制實例變量的狀態保持問題。第二種由於每次請求都創建一個實例,所以會消耗較多的內存空間。
所以在使用spring開發web 時要注意,默認Controller、Dao、Service都是單例的

 ThreadLocal和線程同步

ThreadLocal和線程同步機制都是為了解決多線程中相同變量的訪問沖突問題。

在同步機制中,通過對象的鎖機制保證同一時間只有一個線程訪問變量。這時該變量是多個線程共享的,使用同步機制要求程序慎密地分析什么時候對變量進行讀寫,什么時候需要鎖定某個對象,什么時候釋放對象鎖等繁雜的問題,程序設計和編寫難度相對較大。

而ThreadLocal則從另一個角度來解決多線程的並發訪問。ThreadLocal會為每一個線程提供一個獨立的變量副本,從而隔離了多個線程對數據的訪問沖突。因為每一個線程都擁有自己的變量副本,從而也就沒有必要對該變量進行同步了。ThreadLocal提供了線程安全的共享對象,在編寫多線程代碼時,可以把不安全的變量封裝進ThreadLocal。

缺點:threadlocal變量會一直存在於controller對象中,但是controller對象是多線程復用的,如果這一次請求完成之后忘記把threadlocal中的信息清空,則在處理下一個請求時則會出現信息串用。

概括起來說,對於多線程資源共享的問題,同步機制采用了“以時間換空間”的方式,而ThreadLocal采用了“以空間換時間”的方式。前者僅提供一份變量,讓不同的線程排隊訪問,而后者為每一個線程都提供了一份變量,因此可以同時訪問而互不影響。

 

https://blog.csdn.net/config441002/article/details/52084156


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM