Spring中單例和多例的深入理解
Spring單例和多例的理解
1、什么是單例和多例
單例:所有請(qǐng)求用同一個(gè)對(duì)象來處理。通過單例模式,可以保證系統(tǒng)中一個(gè)類只有一個(gè)實(shí)例。
多例:每個(gè)請(qǐng)求用一個(gè)新的對(duì)象來處理。
2、Spring中的單例與多例
spring ioc容器的bean都是默認(rèn)單例的,即spring依賴注入Bean實(shí)例默認(rèn)是單例的。
spring提供了5中scope,分別是singleton,prototype,request,session,global session,常用是前兩種。點(diǎn)此查看官網(wǎng)介紹。
單例bean與多例(原型)bean的區(qū)別:
如果一個(gè)bean被聲明為單例的時(shí)候,在處理多次請(qǐng)求的時(shí)候,在spring容器里只實(shí)例化出一個(gè)bean,后續(xù)的請(qǐng)求都公用這個(gè)對(duì)象,這個(gè)對(duì)象會(huì)保存在一個(gè)map里面。
當(dāng)有請(qǐng)求來的時(shí)候,會(huì)先從緩存(map)里查看有沒有,有的話直接使用這個(gè)對(duì)象,沒有的話才實(shí)例化一個(gè)新的對(duì)象,所以這是個(gè)單例的。
但是對(duì)于原型(prototype)bean來說,當(dāng)每次請(qǐng)求來的時(shí)候,會(huì)直接實(shí)例化新的bean,沒有緩存以及緩存查詢的過程。
3、單例的優(yōu)勢(shì)與劣勢(shì)
優(yōu)勢(shì):
由于不會(huì)創(chuàng)建新的對(duì)象,所以有以下幾個(gè)性能上的優(yōu)勢(shì):
- 減少新生成實(shí)例的消耗。新生成實(shí)例包括兩個(gè)方面,第一,spring會(huì)通過反射或者cglib來生成bean實(shí)例,這都是耗性能的操作。第二,給對(duì)象分配內(nèi)存也會(huì)涉及負(fù)責(zé)算法。
- 減少jvm垃圾回收。由于不會(huì)給每個(gè)請(qǐng)求都生成bean實(shí)例,所以回收的對(duì)象就少了。
- 可以快速獲取到bean。因?yàn)閱卫@取bean操作,除了第一次生成之外,其余都是從緩存里獲取的,所以很快。
劣勢(shì):
一個(gè)很大的劣勢(shì)是它不能做到線程安全。由于所有請(qǐng)求都共享一個(gè)bean實(shí)例,那么如果這個(gè)bean是一個(gè)有狀態(tài)的bean的話,在并發(fā)場(chǎng)景下就有可能出現(xiàn)問題。
4、spring單例模式與線程安全:
當(dāng)多用戶同時(shí)請(qǐng)求一個(gè)服務(wù)時(shí),容器會(huì)給每一個(gè)請(qǐng)求分配一個(gè)線程,這時(shí)多個(gè)線程會(huì)并發(fā)執(zhí)行該請(qǐng)求所對(duì)應(yīng)的業(yè)務(wù)邏輯(成員方法),此時(shí)就要注意了,如果該處理邏輯中有對(duì)該單例狀態(tài)的修改(體現(xiàn)為該單例的成員屬性),則必須考慮線程同步問題(此時(shí)該狀態(tài)就是一個(gè)臨界資源(共享數(shù)據(jù)),如果多個(gè)線程同時(shí)操作(修改)這個(gè)臨界資源就會(huì)誘發(fā)線程安全問題)。
線程安全:如果你的代碼所在的進(jìn)程中有多個(gè)線程在同時(shí)運(yùn)行,而這些線程可能會(huì)同時(shí)運(yùn)行這段代碼。如果每次運(yùn)行的結(jié)果和單線程運(yùn)行的結(jié)果是一樣的,而且其他的變量的值也和預(yù)期的是一樣的,就是線程安全的。或者說:一個(gè)類或者程序所提供的接口對(duì)于線程來說是原子操作,或者多線程之間的切換不會(huì)導(dǎo)致該接口的執(zhí)行結(jié)果存在二義性,就是線程安全的。
線程安全問題都是由全局變量及靜態(tài)變量引起的。
若每個(gè)線程中對(duì)全局變量,靜態(tài)變量只有讀操作,而無寫操作,一般來說,這個(gè)全局變量是線程安全的;若多個(gè)線程同時(shí)執(zhí)行寫操作,一般都需要考慮線程同步,否則就可能影響線程安全。
- 常量始終是線程安全的,因?yàn)橹淮嬖谧x操作;
- 每次調(diào)用方法前都新建一個(gè)實(shí)例是線程安全的,因?yàn)椴粫?huì)訪問共享的資源;
- 局部變量是線程安全的。因?yàn)槊繄?zhí)行一個(gè)方法,都會(huì)在獨(dú)立的空間創(chuàng)建局部變量,它不是共享資源。局部變量包括方法的參數(shù)變量和方法內(nèi)的變量。
在關(guān)于spring單例與線程安全的很多文章中,會(huì)提到一個(gè)概念,即有狀態(tài)bean和無狀態(tài)bean。
無狀態(tài)bean:無狀態(tài),就是一次操作,不能保存數(shù)據(jù)。無狀態(tài)bean,就是沒有實(shí)例變量的對(duì)象,不能保存數(shù)據(jù),是不變類,在線程安全的。
有狀態(tài)bean:有狀態(tài),就是有數(shù)據(jù)存儲(chǔ)功能。有狀態(tài)bean,就是有實(shí)例變量的對(duì)象,可以保存數(shù)據(jù),是非線程安全的。
如何解決線程安全問題?
(1)使用線程同步機(jī)制:通過對(duì)象的鎖機(jī)制保證同一時(shí)間只有一個(gè)線程訪問變量。這時(shí)該變量是多個(gè)線程共享的,使用同步機(jī)制要求程序縝密地分析什么時(shí)候?qū)ψ兞窟M(jìn)行讀寫,什么時(shí)候需要鎖定某個(gè)對(duì)象,什么時(shí)候釋放對(duì)象鎖等繁雜問題,程序設(shè)計(jì)和編寫難度相對(duì)較大。
(2)使用ThreadLocal:為每一個(gè)線程提供一個(gè)獨(dú)立的變量副本,從而隔離了多個(gè)線程對(duì)數(shù)據(jù)的訪問沖突。因?yàn)槊恳粋€(gè)線程都擁有自己的變量副本,從而也就沒有必要對(duì)該變量進(jìn)行同步了。
概括起來就是:對(duì)于多線程資源共享的問題,同步機(jī)制采用了“以時(shí)間換空間”的方式,而ThreadLocal采用了“以空間換時(shí)間”的方式。前者僅提供一份變量,讓不同的線程排隊(duì)訪問,而后者為每一個(gè)線程都提供了一份變量,因此可以同時(shí)訪問而互不影響。
5、單例如何變多例
Scope聲明為prototype,即
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
SpringMVC單例和多例的優(yōu)缺點(diǎn)
默認(rèn)是單例模式可設(shè)置為多例模式,兩種模式的優(yōu)缺點(diǎn):
1、單例模式(單例多線程的)
- 優(yōu)點(diǎn):共享一個(gè)實(shí)例,內(nèi)存占用少,GC開銷小
- 缺點(diǎn):共享資源存在線程安全問題
2、多例模式(單線程的)
- 優(yōu)點(diǎn):不存在線程安全問題(靜態(tài)共享資源除外)
- 缺點(diǎn):多個(gè)實(shí)例,內(nèi)存占用多,GC開銷大
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot使用Apache?POI實(shí)現(xiàn)導(dǎo)入導(dǎo)出Excel文件
Apache?POI?是一個(gè)強(qiáng)大的?Java?庫,用于處理?Microsoft?Office?文檔,下面我們來看看SpringBoot如何使用Apache?POI導(dǎo)入導(dǎo)出Excel文件功能吧2025-01-01
Spring基于常用AspectJ切點(diǎn)表達(dá)式使用介紹
AspectJ是一個(gè)基于Java語言的AOP框架,使用AspectJ需要導(dǎo)入Spring?AOP和AspectJ相關(guān)jar包,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-12-12
Java技巧分享之利用RxJava打造可觀測(cè)數(shù)據(jù)RxLiveData
這篇文章主要來和大家分享一個(gè)Java技巧,那就是利用RxJava打造可觀測(cè)數(shù)據(jù)RxLiveData,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2023-06-06
Java后臺(tái)實(shí)現(xiàn)瀏覽器一鍵導(dǎo)出下載zip壓縮包
這篇文章主要為大家詳細(xì)介紹了Java后臺(tái)實(shí)現(xiàn)瀏覽器一鍵導(dǎo)出下載zip壓縮包,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-07-07
Apache Commons fileUpload實(shí)現(xiàn)文件上傳之一
這篇文章主要介紹了Apache Commons fileUpload實(shí)現(xiàn)文件上傳之一的相關(guān)資料,需要的朋友可以參考下2016-03-03
Java多線程中wait?notify等待喚醒機(jī)制詳解
這篇文章主要介紹了Java多線程中wait?notify等待喚醒機(jī)制,由于線程之間是搶占式執(zhí)行的,因此線程的執(zhí)行順序難以預(yù)知,但是實(shí)際開發(fā)中有時(shí)候我們希望合理的協(xié)調(diào)多個(gè)線程之間的執(zhí)行先后順序,所以這里我們來介紹下等待喚醒機(jī)制,需要的朋友可以參考下2024-10-10

