2020-06-11 設計模式之spring中的bean默認是單例模式

一、Spring單例模式及線程安全

  Spring框架中的Bean,或者說組件屁魏,獲取實例的時候都是默認單例模式右蹦,這是在多線程開發(fā)的時候需要尤其注意的地方诊杆。

  單例模式的意思是只有一個實例,例如在Spring容器中某一個類只有一個實例何陆,而且自行實例化后并項整個系統(tǒng)提供這個實例刽辙,這個類稱為單例類。

  當多個用戶同時請求一個服務時甲献,容器會給每一個請求分配一個線程宰缤,這時多個線程會并發(fā)執(zhí)行該請求對應的業(yè)務邏輯(成員方法),此時就要注意了晃洒,如果該處理邏輯中有對單例狀態(tài)的修改(體現(xiàn)為該單例的成員屬性)慨灭,則必須考慮線程同步問題。

同步機制的比較:

  ThreadLocal和線程同步機制相比有什么優(yōu)勢呢球及?他們都是為了解決多線程中相同變量的訪問沖突問題氧骤。

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


  而ThreadLocal則從另一個角度來解決多線程的并發(fā)訪問庐氮。ThreadLocal會為每一個線程提供一個獨立的變量副本语稠,從而隔離了多個線程對數(shù)據(jù)的訪問沖突。因為每一個線程都擁有自己的變量副本,從而也就沒有必要對該變量進行同步了仙畦。ThreadLocal提供了線程安全的共享對象输涕,在編寫多線程代碼時,可以把不安全的變量封裝進ThreadLocal慨畸。?


  由于ThreadLocal中可以持有任何類型的對象莱坎,低版本JDK所提供的get()返回的是Object對象,需要強制類型轉(zhuǎn)換寸士。但JDK 5.0通過泛型很好的解決了這個問題型奥,在一定程度地簡化ThreadLocal的使用

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


  Spring使用ThreadLocal解決線程安全問題?


  我們知道在一般情況下搭综,只有無狀態(tài)的Bean才可以在多線程環(huán)境下共享,在Spring中划栓,絕大部分Bean都可以聲明為singleton作用域兑巾。就是因為Spring對一些Bean(如RequestContextHolder、TransactionSynchronizationManager忠荞、LocaleContextHolder等)中非線程安全狀態(tài)采用ThreadLocal進行處理蒋歌,讓它們也成為線程安全的狀態(tài),因為有狀態(tài)的Bean就可以在多線程中共享了委煤。


  一般的Web應用劃分為展現(xiàn)層堂油、服務層和持久層三個層次,在不同的層中編寫對應的邏輯碧绞,下層通過接口向上層開放功能調(diào)用府框。在一般情況下,從接收請求到返回響應所經(jīng)過的所有程序調(diào)用都同屬于一個線程

ThreadLocal是解決線程安全問題一個很好的思路讥邻,它通過為每個線程提供一個獨立的變量副本解決了變量并發(fā)訪問的沖突問題迫靖。在很多情況下,ThreadLocal比直接使用synchronized同步機制解決線程安全問題更簡單兴使,更方便系宜,且結(jié)果程序擁有更高的并發(fā)性。

如果你的代碼所在的進程中有多個線程在同時運行鲫惶,而這些線程可能會同時運行這段代碼蜈首。如果每次運行結(jié)果和單線程運行的結(jié)果是一樣的实抡,而且其他的變量的值也和預期的是一樣的欠母,就是線程安全的欢策。 或者說:一個類或者程序所提供的接口對于線程來說是原子操作或者多個線程之間的切換不會導致該接口的執(zhí)行結(jié)果存在二義性,也就是說我們不用考慮同步的問題。  線程安全問題都是由全局變量及靜態(tài)變量引起的赏淌。

若每個線程中對全局變量踩寇、靜態(tài)變量只有讀操作,而無寫操作六水,一般來說俺孙,這個全局變量是線程安全的;若有多個線程同時執(zhí)行寫操作掷贾,一般都需要考慮線程同步睛榄,否則就可能影響線程安全。

1) 常量始終是線程安全的想帅,因為只存在讀操作场靴。

2)每次調(diào)用方法前都新建一個實例是線程安全的,因為不會訪問共享的資源港准。

3)局部變量是線程安全的旨剥。因為每執(zhí)行一個方法,都會在獨立的空間創(chuàng)建局部變量浅缸,它不是共享的資源轨帜。局部變量包括方法的參數(shù)變量和方法內(nèi)變量。

有狀態(tài)就是有數(shù)據(jù)存儲功能衩椒。有狀態(tài)對象(Stateful Bean)蚌父,就是有實例變量的對象? ,可以保存數(shù)據(jù)毛萌,是非線程安全的梢什。在不同方法調(diào)用間不保留任何狀態(tài)。

無狀態(tài)就是一次操作朝聋,不能保存數(shù)據(jù)嗡午。無狀態(tài)對象(Stateless Bean),就是沒有實例變量的對象? .不能保存數(shù)據(jù)冀痕,是不變類荔睹,是線程安全的。

有狀態(tài)對象:

無狀態(tài)的Bean適合用不變模式言蛇,技術就是單例模式僻他,這樣可以共享實例,提高性能腊尚。有狀態(tài)的Bean吨拗,多線程環(huán)境下不安全,那么適合用Prototype原型模式。Prototype: 每次對bean的請求都會創(chuàng)建一個新的bean實例劝篷。

Struts2默認的實現(xiàn)是Prototype模式哨鸭。也就是每個請求都新生成一個Action實例,所以不存在線程安全問題娇妓。需要注意的是像鸡,如果由Spring管理action的生命周期, scope要配成prototype作用域

二哈恰、線程安全案例

  SimpleDateFormat(下面簡稱sdf)類內(nèi)部有一個Calendar對象引用,它用來儲存和這個sdf相關的日期信息,例如sdf.parse(dateStr), sdf.format(date) 諸如此類的方法參數(shù)傳入的日期相關String, Date等等, 都是交友Calendar引用來儲存的.這樣就會導致一個問題,如果你的sdf是個static的, 那么多個thread 之間就會共享這個sdf, 同時也是共享這個Calendar引用只估,非線程安全的。

這個問題背后隱藏著一個更為重要的問題--無狀態(tài):無狀態(tài)方法的好處之一着绷,就是它在各種環(huán)境下蛔钙,都可以安全的調(diào)用。衡量一個方法是否是有狀態(tài)的荠医,就看它是否改動了其它的東西夸楣,比如全局變量,比如實例的字段子漩。format方法在運行過程中改動了SimpleDateFormat的calendar字段豫喧,所以,它是有狀態(tài)的幢泼。

這也同時提醒我們在開發(fā)和設計系統(tǒng)的時候注意下一下三點:

1.自己寫公用類的時候紧显,要對多線程調(diào)用情況下的后果在注釋里進行明確說明

2.對線程環(huán)境下,對每一個共享的可變變量都要注意其線程安全性

3.我們的類和方法在做設計的時候缕棵,要盡量設計成無狀態(tài)的

解決方法:

  1.使用synchronized關鍵字進行數(shù)據(jù)同步孵班,或者使用ThreadLocal保證線程安全

  2.不適用JDK自帶的時間格式化類,使用其他類庫的

  使用Apache commons里的FastDateFormat招驴,宣城是既快有線程安全的SimpleDateFormat翰灾,可惜他只能對日期進行format黎做,不能對日期串進行解析

使用Joda-Time類庫來處理時間相關問題巩步,該種對時間的處理方式比較完美哩俭,建議使用

------------------------------------------------------------------------------------------------------------------------------------------------------------------------


一触趴、單例模式:在spring中其實是scope(作用范圍)參數(shù)的缺省設定值

每個bean定義只生成一個對象實例,每次getBean請求獲得的都是此實例

單例模式分為餓漢模式和懶漢模式氮发,

餓漢模式spring singleton的缺省是餓漢模式:啟動容器時(即實例化容器時),為所有spring配置文件中定義的bean都生成一個實例

懶漢模式在第一個請求時才生成一個實例,以后的請求都調(diào)用這個實例

----------------------------------------------

spring singleton設置為懶漢模式:

default-lazy-init="true">

------------------------------------------------

二、另一種和singleton對應的scope值---prototype多實例模式

調(diào)用getBean時,就new一個新實例

--------------------------------------------------------

singleton和prototype的比較

singleton:

xml配置文件:

測試代碼:

ctx = new ClassPathXmlApplicationContext("spring-hibernate-mysql.xml");

DvdTypeDAO tDao1 = (DvdTypeDAO)ctx.getBean("dvdTypeDAO");

DvdTypeDAO tDao2 = (DvdTypeDAO)ctx.getBean("dvdTypeDAO");

運行:

-----------------------------------------

true

com.terana.hibernate.impl.DvdTypeDAOImpl@15b0333

com.terana.hibernate.impl.DvdTypeDAOImpl@15b0333

--------------------------------------

說明前后兩次getBean()獲得的是同一實例,說明spring缺省是單例

prototype:

<bean id="dvdTypeDAO" class="com.terana.hibernate.impl.DvdTypeDAOImpl"?scope="prototype"?/>

執(zhí)行同樣的測試代碼

----------------------------------------------------

運行:

false

com.terana.hibernate.impl.DvdTypeDAOImpl@afae4a

com.terana.hibernate.impl.DvdTypeDAOImpl@1db9852

說明scope="prototype"后,每次getBean()的都是不同的新實例

---------------------------------------------------------


轉(zhuǎn)自https://blog.csdn.net/qq_35661171/article/details/83180546

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末冗懦,一起剝皮案震驚了整個濱河市爽冕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌披蕉,老刑警劉巖颈畸,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件乌奇,死亡現(xiàn)場離奇詭異,居然都是意外死亡眯娱,警方通過查閱死者的電腦和手機礁苗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來困乒,“玉大人寂屏,你說我怎么就攤上這事贰谣∧嚷В” “怎么了?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵吱抚,是天一觀的道長百宇。 經(jīng)常有香客問我,道長秘豹,這世上最難降的妖魔是什么携御? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮既绕,結(jié)果婚禮上啄刹,老公的妹妹穿的比我還像新娘。我一直安慰自己凄贩,他們只是感情好誓军,可當我...
    茶點故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著疲扎,像睡著了一般昵时。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上椒丧,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天壹甥,我揣著相機與錄音,去河邊找鬼壶熏。 笑死句柠,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的棒假。 我是一名探鬼主播俄占,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼淆衷!你這毒婦竟也來了缸榄?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤祝拯,失蹤者是張志新(化名)和其女友劉穎甚带,沒想到半個月后她肯,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡鹰贵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年晴氨,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片碉输。...
    茶點故事閱讀 40,615評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡籽前,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出敷钾,到底是詐尸還是另有隱情枝哄,我是刑警寧澤,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布阻荒,位于F島的核電站挠锥,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏侨赡。R本人自食惡果不足惜蓖租,卻給世界環(huán)境...
    茶點故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望羊壹。 院中可真熱鬧蓖宦,春花似錦、人聲如沸油猫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽眨攘。三九已至主慰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鲫售,已是汗流浹背共螺。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留情竹,地道東北人藐不。 一個月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓,卻偏偏與公主長得像秦效,于是被迫代替她去往敵國和親雏蛮。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,630評論 2 359