有狀態和無狀態的區別
基本概念:
有狀態就是有資料儲存功能。有狀態物件(Stateful Bean),就是有例項變數的物件 ,可以儲存資料,是非執行緒安全的。在不同方法呼叫間不保留任何狀態。
無狀態就是一次操作,不能儲存資料。無狀態物件(Stateless Bean),就是沒有例項變數的物件 .不能儲存資料,是不變類,是執行緒安全的。
程式碼更好理解:
- public class StatefulBean {
- public int state;
- // 由於多執行緒環境下,user是引用物件,是非執行緒安全的
- public User user;
- public int getState() {
- return state;
- }
- public void setState( int state) {
- this .state = state;
- }
- public User getUser() {
- return user;
- }
- public void setUser(User user) {
- this .user = user;
- }
- }
- public class StatelessBeanService {
- // 雖然有billDao屬性,但billDao是沒有狀態資訊的,是Stateless Bean.
- BillDao billDao;
- public BillDao getBillDao() {
- return billDao;
- }
- public void setBillDao(BillDao billDao) {
- this .billDao = billDao;
- }
- public List<User> findUser(String Id) {
- return null ;
- }
- }
單例模式中的有狀態和無狀態:
單例類可以是有狀態的(stateful),一個有狀態的單例物件一般也是可變(mutable)單例物件 。 有狀態的可變的單例物件常常當做狀態庫(repositary)使用。比如一個單例物件TaskCache(Spring中配為singleton)可以 持有一個AtomicLong型別的屬性,用來給一個系統提供一個數值惟一的序列號碼,作為任務通迅管理的ID生成器。同時,一個單例類也可以持有一個聚 集,從而允許儲存多個狀態,如示例中的ExpiringMap快取任務列表。
程式碼示例:
- import java.util.concurrent.atomic.AtomicLong;
- import org.apache.mina.util.ExpiringMap;
- public class TaskCache {
- // 請求超時
- private short requestTimeout;
- // 這個快取Map是執行緒安全,並且有定時超時功能
- private ExpiringMap<String, Object> tasksMap = new ExpiringMap<String, Object>();
- // 執行緒安全的原子類,示例有狀態的單例類
- private static AtomicLong seqNo = new AtomicLong( 1 );
- // 示例有狀態的單例類
- public Long nextSeqNo() {
- return seqNo.getAndIncrement();
- }
- public void setRequestTimeout( short requestTimeout) {
- this .requestTimeout = requestTimeout;
- }
- // 啟動過期檢測
- public void startExpiring() {
- tasksMap.getExpirer().setTimeToLive(requestTimeout);
- tasksMap.getExpirer().startExpiringIfNotStarted();
- }
- // 停止過期檢測
- public void stopExpiring() {
- tasksMap.getExpirer().stopExpiring();
- }
- // 取任務列表.
- public Object getTasks(String key) {
- return tasksMap.get(key);
- }
- // 去除任務列表.
- public Object removeTasks(String key) {
- return tasksMap.remove(key);
- }
- // 新增任務列表.
- public void addTasks(String key, Object value) {
- tasksMap.put(key, value);
- }
- }
單例類也可以是沒有狀態的(stateless) ,僅用做提供工具性函式的物件。既然是為了提供工具性函式,也就沒有必要建立多個例項,因此使用單例模式很合適。平常的單例類都是沒有狀態的,這裡就不示例了。一個沒有狀態的單例類也就是不變(Immutable)單例類。關於不變模式,請參考 http://www.javaeye.com/topic/959751
EJB中的有狀態與無狀態:
1.Stateful session bean的每個使用者都有自己的一個例項,所以兩者對stateful session bean的操作不會影響對方。另外注意:如果後面需要操作某個使用者的例項,你必須在客戶端快取Bean的Stub物件(JSP通常的做法是用Session快取),這樣在後面每次呼叫中,容器才知道要提供相同的bean例項。
2.Stateless Session Bean不負責記錄使用者狀態,Stateless Session Bean一旦例項化就被加進會話池中,各個使用者都可以共用。如果它有自己的屬性(變數),那麼這些變數就會受到所有呼叫它的使用者的影響。
3.從記憶體方面來看,Stateful Session Bean與Stateless Session Bean比較,Stateful Session Bean會消耗J2EE Server 較多的記憶體,然而Stateful Session Bean的優勢卻在於他可以維持使用者的狀態。
Spring中的有狀態(Stateful)和無狀態(Stateless)
1.通過上面的分析,相信大家已經對有狀態和無狀態有了一定的理解。無狀態的Bean適合用不變模式,技術就是單例模式,這樣可以共享例項,提高效能。有狀態的Bean,多執行緒環境下不安全,那麼適合用Prototype原型模式。Prototype: 每次對bean的請求都會建立一個新的bean例項。
2.預設情況下,從Spring bean工廠所取得的例項為singleton(scope屬性為singleton),容器只存在一個共享的bean例項。
3.理解了兩者的關係,那麼scope選擇的原則就很容易了:有狀態的bean都使用prototype作用域,而對無狀態的bean則應該使用singleton作用域。
4.如Service層、Dao層用預設singleton就行,雖然Service類也有dao這樣的屬性,但dao這些類都是沒有狀態資訊的,也就是 相當於不變(immutable)類,所以不影響。Struts2中的Action因為會有User、BizEntity這樣的例項物件,是有狀態資訊 的,在多執行緒環境下是不安全的,所以Struts2預設的實現是Prototype模式。在Spring中,Struts2的Action中,scope 要配成prototype作用域。
Servlet、Struts中的有狀態和無狀態:
1.Servlet體系結構是建立在Java多執行緒機制之上的,它的生命週期是由Web 容器負責的。一個Servlet類在Application中只有一個例項存在,也就是有多個執行緒在使用這個例項。這是單例模式的應用。無狀態的單例是線 程安全的,但我們如果在Servlet裡用了例項變數,那麼就變成有狀態了,是非執行緒安全的。如下面的用法就是不安全的,因為user,out都是有狀態 資訊的。
- public class UnSafeServlet HttpServlet{
- User user;
- PrintWriter out;
- public void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
- //do something...
- }
- }
Out,Request,Response,Session,Config,Page,PageContext是執行緒安全的,Application在整個系統內被使用,所以不是執行緒安全的.
2.Struts1也是基於單例模式實現,也就是隻有一個Action例項供多執行緒使用。預設的模式是前臺頁面資料通過actionForm傳入,在 action中的excute方法接收,這樣action是無狀態的,所以一般情況下Strunts1是執行緒安全的。如果Action中用了例項變數,那 麼就變成有狀態了,同樣是非執行緒安全的。像下面這樣就是執行緒不安全的。
- public class UnSafeAction1 extends Action {
- // 因為Struts1是單例實現,有狀態情況下,物件引用是非執行緒安全的
- User user;
- public void execute() {
- // do something...
- }
- public User getUser() {
- return user;
- }
- public void setUser(User user) {
- this .user = user;
- }
- }
3.Struts2預設的實現是Prototype模式。也就是每個請求都新生成一個Action例項,所以不存線上程安全問題。需要注意的是,如果由Spring管理action的生命週期, scope要配成prototype作用域。
4.如何解決Servlet和Struts1的執行緒安全問題,當我們能比較好的理解有狀態和無狀態的原理,自然很容易得出結論:不要使用有狀態的bean,也就是不要用例項變數 。如果用,就要用prototype模式。Struts1 user guide裡有: Only Use Local Variables - The most important principle that aids in thread-safe coding is to use
only local variables, not instance variables , in your Action class.
總結:
Stateless無狀態用單例Singleton模式,Stateful有狀態就用原型Prototype模式。
Stateful 有狀態是多執行緒編碼的天敵,所以在開發中儘量用Stateless無狀態,無狀態是不變(immutable)模式的應用,有很多優點:不用管執行緒和同步的問題 ,如果值是不可變的,程式不用擔心多個執行緒改變共享狀態,所以可以避免執行緒競爭的bugs. 因為沒有競爭,就不用用locks等機制,所以無狀態的不變機制,也可以避免產生死鎖現象。
國外一些哥們的觀點:
Immutable objects may not be altered after their creation. So: Yes, they are some kind of stateless.As immutable objects can not be changed, there is no need for locking - reading access to objects is always threadsafe (when not modifying variables). Therefore,
real immutable objects are always threadsafe.
Rod Johnson大叔的觀點:
Stateless or Stateful?
Service objects will usually be stateless. Stateless service layers are highly scalable: They pose no replication issues and there is no need to allocate additional resources for every client. (Remember that one of
the key motivations of a middle tier is to share resources between multiple clients.) It is also much easier for stateless service layers to support remote clients, if necessary. A stateless service layer is one concession of object orientation that I find
not too painful.
此處省去N個字。
If possible, design applications to use a stateless service layer. Hold state in the web tier, rather than in the business logic tier, if possible.
相關文章
- Spring Bean Scope 有狀態的Bean和無狀態的BeanSpringBean
- 關於有狀態和無狀態會話bean的解釋 (轉)會話Bean
- ssdbgrid中,設了斷點的除錯狀態和執行狀態有區別斷點除錯
- SAP Fiori和WebClient UI的有狀態和無狀態行為設計原理WebclientUI
- 架構設計(五):有狀態服務和無狀態服務架構
- 系統設計架構:有狀態與無狀態架構
- SAP BSP應用有狀態和無狀態行為差異比較
- 工作流從無狀態切換到有狀態的好處
- 執行緒狀態&&Wait和sleep的區別?執行緒AI
- 非同步API中事件、命令和狀態區別非同步API事件
- 無狀態協議協議
- Blazor中的無狀態元件Blazor元件
- 物件和函式的區別就是物件可以儲存狀態物件函式
- RAC中lsnrctl和srvctl的區別(監聽狀態異常)
- React 4 種狀態型別及 N 種狀態管理React型別
- Oracle資料庫的靜默狀態和掛起狀態Oracle資料庫
- steam雲狀態無法同步怎麼辦 steam雲狀態無法同步會有什麼影響
- 【架構設計】無狀態狀態機在程式碼中的實踐架構
- 什麼時候用有狀態session bean,什麼時候用無狀態session bean (轉)SessionBean
- 前端狀態管理與有限狀態機前端
- 狀態模式的理解和示例模式
- 更新TableView和CollectionView的狀態View
- 最全的HTTP響應狀態碼列表:除了404,HTTP狀態碼還有啥?HTTP
- 無狀態會話bean的疑問會話Bean
- 初次使用無狀態sessionbean的問題SessionBean
- [React]屬性和狀態React
- React 狀態管理:狀態與生命週期React
- 程式的建立和程式的狀態
- 順序控制和狀態機之間的差別
- flink 有狀態(stateful)的計算
- 狀態模式模式
- 狀態機
- 狀態碼
- 狀態管理
- 行為和狀態的關係
- mysql 鎖狀態的一些狀態資訊記錄MySql
- Vuex 單狀態庫 與 多模組狀態庫Vue
- 淺談前端的狀態管理,以及anguar的狀態管理庫前端