大家好,我是被編程耽誤的文藝Tom。
金三銀四的招聘季到了,Spring 作為最熱門的框架,在很多大廠面試中都會(huì)問到相關(guān)的問題。
前幾天,就有好幾個(gè)同學(xué)就問我,在面試中被問到這樣一個(gè)問題。Spring中的Bean是不是線程安全的。大家總覺得在面試過(guò)程差了一點(diǎn)意思。但是又說(shuō)不上來(lái)是什么原因。這是因?yàn)?,大家可能?duì)Spring 的本質(zhì)還欠缺一些深度的思考。
今天,咱們不兜圈子不繞彎,上來(lái)直接說(shuō)答案,大家關(guān)注點(diǎn)個(gè)贊,本視頻跟大家徹底講明白。
其實(shí),Spring中的Bean是否線程安全,其實(shí)跟Spring容器本身無(wú)關(guān)。Spring框架中沒有提供線程安全的策略,因此,Spring容器中在的Bean本身也不具備線程安全的特性。咱們要透徹理解這個(gè)結(jié)論,我們首先要知道Spring中的Bean是從哪里來(lái)的。
1、Spring中Bean從哪里來(lái)的?
在Spring容器中,除了很多Spring內(nèi)置的Bean以外,其他的Bean都是我們自己通過(guò)Spring配置來(lái)聲明的,然后,由Spring容器統(tǒng)一加載。我們?cè)赟pring聲明配置中通常會(huì)配置以下內(nèi)容,如:class(全類名)、id(也就是Bean的唯一標(biāo)識(shí))、 scope(作用域)以及l(fā)azy-init(是否延時(shí)加載)等。之后,Spring容器根據(jù)配置內(nèi)容使用對(duì)應(yīng)的策略來(lái)創(chuàng)建Bean的實(shí)例。因此,Spring容器中的Bean其實(shí)都是根據(jù)我們自己寫的類來(lái)創(chuàng)建的實(shí)例。因此,Spring中的Bean是否線程安全,跟Spring容器無(wú)關(guān),只是交由Spring容器托管而已。
那么,在Spring容器中,什么樣的Bean會(huì)存在線程安全問題呢?回答,這個(gè)問題之前我們得先回顧一下Spring Bean的作用域。在Spring定義的作用域中,其中有 prototype( 多例Bean )和 singleton ( 單例Bean)。那么,定義為 prototype 的Bean,是在每次 getBean 的時(shí)候都會(huì)創(chuàng)建一個(gè)新的對(duì)象。定義為 singleton 的Bean,在Spring容器中只會(huì)存在一個(gè)全局共享的實(shí)例?;趯?duì)以上Spring Bean作用域的理解,下面,我們來(lái)分析一下在Spring容器中,什么樣的Bean會(huì)存在線程安全問題。
2、Spring中什么樣的Bean存在線程安全問題?
我們已經(jīng)知道,多例Bean每次都會(huì)新創(chuàng)建新實(shí)例,也就是說(shuō)線程之間不存在Bean共享的問題。因此,多例Bean是不存在線程安全問題的。
而單例Bean是所有線程共享一個(gè)實(shí)例,因此,就可能會(huì)存在線程安全問題。但是單例Bean又分為無(wú)狀態(tài)Bean和有狀態(tài)Bean。在多線程操作中只會(huì)對(duì)Bean的成員變量進(jìn)行查詢操作,不會(huì)修改成員變量的值,這樣的Bean稱之為無(wú)狀態(tài)Bean。所以,可想而知,無(wú)狀態(tài)的單例Bean是不存在線程安全問題的。但是,在多線程操作中如果需要對(duì)Bean中的成員變量進(jìn)行數(shù)據(jù)更新操作,這樣的Bean稱之為有狀態(tài)Bean,所以,有狀態(tài)的單例Bean就可能存在線程安全問題。
所以,最終我們得出結(jié)論,在Spring中,只有有狀態(tài)的單例Bean才會(huì)存在線程安全問題。我們?cè)谑褂肧pring的過(guò)程中,經(jīng)常會(huì)使用到有狀態(tài)的單例Bean,如果真正遇到了線程安全問題,我們又該如何處理呢?
3、如何處理Spring Bean的線程安全問題?
處理有狀態(tài)單例Bean的線程安全問題有以下三種方法:
1、將Bean的作用域由 “singleton” 單例 改為 “prototype” 多例。
2、在Bean對(duì)象中避免定義可變的成員變量,當(dāng)然,這樣做不太現(xiàn)實(shí),就當(dāng)我沒說(shuō)。
3、在類中定義 ThreadLocal 的成員變量,并將需要的可變成員變量保存在 ThreadLocal 中,ThreadLocal 本身就具備線程隔離的特性,這就相當(dāng)于為每個(gè)線程提供了一個(gè)獨(dú)立的變量副本,每個(gè)線程只需要操作自己的線程副本變量,從而解決線程安全問題。
都已經(jīng)看到這里了, 相信大家應(yīng)該已經(jīng)知道了 Spring中的Bean是否線程安全以及如何處理Bean的線程安全問題。
下次再遇到這個(gè)面試題,你會(huì)回答了嗎?
我是被編程耽誤的文藝Tom,如果大家還有其他疑問,可以在評(píng)論區(qū)留言。如果我的解析對(duì)你有幫助,請(qǐng)動(dòng)動(dòng)手指一鍵三連分享給更多的人。
今天的面試題解析就到這里,我們下期再見。關(guān)注我,面試不再難!
關(guān)注『 Tom彈架構(gòu) 』回復(fù)“簡(jiǎn)歷”可獲取配套資料。
本文為“Tom彈架構(gòu)”原創(chuàng),轉(zhuǎn)載請(qǐng)注明出處。技術(shù)在于分享,我分享我快樂!如果您有任何建議也可留言評(píng)論或私信,您的支持是我堅(jiān)持創(chuàng)作的動(dòng)力。關(guān)注『 Tom彈架構(gòu) 』可獲取更多技術(shù)干貨!
原創(chuàng)不易,堅(jiān)持很酷,都看到這里了,小伙伴記得點(diǎn)贊、收藏、在看,一鍵三連加關(guān)注!如果你覺得內(nèi)容太干,可以分享轉(zhuǎn)發(fā)給朋友滋潤(rùn)滋潤(rùn)!