日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

Spring并发访问的线程安全性问题

發布時間:2023/11/28 生活经验 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring并发访问的线程安全性问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

下面的記錄對spring中并發的總結。理論分析參考Spring中Singleton模式的線程安全,建議先看

spring中的并發訪問題:

我們知道在一般情況下,只有無狀態的Bean才可以在多線程環境下共享,在Spring中,絕大部分Bean都可以聲明為singleton作用域。
那么對于有狀態的bean呢?Spring對一些(如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等)中非線程安全狀態的bean采用ThreadLocal進行處理,讓它們也成為線程安全的狀態,因此有狀態的Bean就可以在多線程中共享了。

如果用有狀態的bean,也可以使用用prototype模式,每次在注入的時候就重新創建一個bean,在多線程中互不影響。

有狀態就是有數據存儲功能。有狀態對象(Stateful Bean),就是有實例變量的對象 ,可以保存數據,是非線程安全的。在不同方法調用間不保留任何狀態。

無狀態就是一次操作,不能保存數據。無狀態對象(Stateless Bean),就是沒有實例變量的對象 .不能保存數據,是不變類,是線程安全的。

無狀態的Bean適合用不變模式,技術就是單例模式,這樣可以共享實例,提高性能。

有狀態的Bean,多線程環境下不安全,那么適合用Prototype原型模式。Prototype: 每次對bean的請求都會創建一個新的bean實例。

Servlet體系結構是建立在Java多線程機制之上的,它的生命周期是由Web 容器負責的。一個Servlet類在Application中只有一個實例存在,也就是有多個線程在使用這個實例。這是單例模式的應用。如Service層、Dao層用默認singleton就行,雖然Service類也有dao這樣的屬性,但dao這些類都是沒有狀態信息的,也就是相當于不變(immutable)類,所以不影響。Struts2中的Action因為會有User、BizEntity這樣的實例對象,是有狀態信息的,在多線程環境下是不安全的,所以Struts2默認的實現是Prototype模式。在Spring中,Struts2的Action中,scope要配成prototype作用域。 (單例模式-單例注冊表實現和threadLocal-可以處理有狀態的bean之間的關系)

還有我們的實體bean,從客戶端傳遞到后臺的controller–>service–>Dao,這一個流程中,他們這些對象都是單例的,那么這些單例的對象在處理我們的傳遞到后臺的實體bean不會出問題嗎?
答:[實體bean不是單例的],并沒有交給spring來管理,每次我們都手動的New出來的【如EMakeType et = new EMakeType();】,所以即使是那些處理我們提交數據的業務處理類是被多線程共享的,但是他們處理的數據并不是共享的,數據時每一個線程都有自己的一份,所以在數據這個方面是不會出現線程同步方面的問題的。

(在這里補充下自己在項目開發中對于實體bean在多線程中的處理:1。對于實體bean一般通過方法參數的的形式傳遞(參數是局部變量),所以多線程之間不會有影響。2.有的地方對于有狀態的bean直接使用prototype原型模式來進行解決。3.對于使用bean的地方可以通過new的方式來創建)

但是那些的在Dao中的xxxDao,或controller中的xxxService,這些對象都是單例那么就會出現線程同步的問題。但是話又說回來了,這些對象雖然會被多個進程并發訪問,可我們訪問的是他們里面的方法,這些類里面通常不會含有成員變量,那個Dao里面的ibatisDao是框架里面封裝好的,已經被測試,不會出現線程同步問題了。所以出問題的地方就是我們自己系統里面的業務對象,所以我們一定要注意這些業務對象里面千萬不能要獨立成員變量,否則會出錯。

spring對那些個有狀態bean使用ThreadLocal維護變量[僅僅是變量,因為線程同步的問題就是成員變量的互斥訪問出問題]時,ThreadLocal為每個使用該變量的線程提供獨立的變量副本,所以每一個線程都可以獨立地改變自己的副本,而不會影響其它線程所對應的副本。

對spring并發訪問線程安全的兩篇博客匯總,可以得出上述結論…………..

由于Spring MVC默認是Singleton的,所以會產生一個潛在的安全隱患。根本核心是instance**的變量保持狀態**的問題。這意味著每個request過來,系統都會用原有的instance去處理,這樣導致了兩個結果(單例的好處):

一是我們不用每次創建Controller,
二是減少了對象創建和垃圾收集的時間;
由于只有一個Controller的instance,當多個線程同時調用它的時候,它里面的instance**變量**(可以理解為私有變量)就不是線程安全的了,會發生竄數據的問題。
當然大多數情況下,我們根本不需要考慮線程安全的問題,比如dao,service等,除非在bean中聲明了實例變量。因此,我們在使用spring mvc 的contrller時,應避免在controller中定義實例變量(singleton唯一的不好是單例的變量容易出現問題,下面有解決的方案)
如:

public  class  Controller  extends  AbstractCommandController  {
......
protected  ModelAndView handle(HttpServletRequest request,HttpServletResponse response,Object command,BindException errors)  throws  Exception  {
company =  ................;
}
protected  Company company;
}

在這里有聲明一個變量company,這里就存在并發線程安全的問題。
如果控制器是使用單例形式,且controller中有一個私有的變量a,所有請求到同一個controller時,使用的a變量是共用的,即若是某個請求中修改了這個變量a,則,在別的請求中能夠讀到這個修改的內容。。

有幾種解決方法:
1、在控制器中不使用實例變量(可以使用方法參數的形式解決,參考博文 Spring Bean Scope 有狀態的Bean 無狀態的Bean)
2、將控制器的作用域從單例改為原型,即在spring配置文件Controller中聲明 scope=”prototype”,每次都創建新的controller
3、在Controller中使用ThreadLocal變量

這幾種做法有好有壞,第一種,需要開發人員擁有較高的編程水平與思想意識,在編碼過程中力求避免出現這種BUG,

而第二種則是容器自動的對每個請求產生一個實例,由JVM進行垃圾回收,因此做到了線程安全。

使用第一種方式的好處是實例對象只有一個,所有的請求都調用該實例對象,速度和性能上要優于第二種,不好的地方,就是需要程序員自己去控制實例變量的狀態保持問題。第二種由于每次請求都創建一個實例,所以會消耗較多的內存空間。

所以在使用spring開發web 時要注意,默認Controller、Dao、Service都是單例的。

SpringMVC多線程環境中如何保證對象的安全性?

代碼如下:

@RequestMapping("/user")
@Controller
public class UserController {@ResourceUserService userService;@RequestMapping("/add")public void testA(User user) {userService.add(user);}@RequestMapping("/get")public void testA(int id) {userService.get(id);}
}@Service("userService")
class UserService {public static Map<Integer, User> usersCache = new HashMap<String, User>();public void add(User user) {usersCache.put(user.getId(), user);}public void get(int id) {usersCache.get(id);}
}

此段代碼,usersCache對象就是線程不安全的。因為它是靜態的全局共享對象。如果有多個線程同時調用add方法,可能會發生用戶對象被覆蓋的情況,也就是id對應對象不一致,這是多線程編程中最常發生的事情。

所以,可以使用 Collections 工具同步Map。

static Map<Integer, Users> usersCache = Collections.synchronizedMap(new HashMap<Integer, Users>());

研究一下,Spring中的源碼,它對常用的開源框架做了大量封裝,如,Hibernate中的sessionFactory,就使用的是 org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean,而在 AnnotationSessionFactoryBean的父類LocalSessionFactoryBean中,定義了大量的ThreadLocal來保證多線程的安全性。

public class LocalSessionFactoryBean extends AbstractSessionFactoryBean implements BeanClassLoaderAware {private static final ThreadLocal<DataSource> configTimeDataSourceHolder = new ThreadLocal<DataSource>();private static final ThreadLocal<TransactionManager> configTimeTransactionManagerHolder = new ThreadLocal<TransactionManager>();private static final ThreadLocal<Object> configTimeRegionFactoryHolder = new ThreadLocal<Object>();private static final ThreadLocal<CacheProvider> configTimeCacheProviderHolder = new ThreadLocal<CacheProvider>();private static final ThreadLocal<LobHandler> configTimeLobHandlerHolder = new ThreadLocal<LobHandler>();
}

總結

以上是生活随笔為你收集整理的Spring并发访问的线程安全性问题的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。