Spring如何解決單例bean線程不安全的問題
首先我們應(yīng)該知道線程安全問題一般發(fā)生在成員變量上,這是為什么啦?
因?yàn)槌蓡T變量是存放在堆內(nèi)存中,而堆內(nèi)存又是線程共享的,這就造成了線程安全問題
因?yàn)镾pring中的Bean默認(rèn)是單例的,所以在定義成員變量時(shí)也有可能會(huì)發(fā)生線程安全問題。下面我們就來研究下如何解決Spring中單例Bean的線程安全問題
@RestController
//@Scope("prototype")
public class BeanController {
private int content=0; //基本類型 線程不安全
private String test=null;//引用類型 線程不安全
@RequestMapping("testBean")
public Object getSercurity(){
System.out.println(content);
System.out.println(test);
content=20;
test="單例模式是不安全的";
return test;
}
問題來了,我們?cè)撊绾螠y試線程不安全問題啦?我們需要在程序中用debug模式去啟動(dòng),打斷點(diǎn)。不需要執(zhí)行完程序,然后再次調(diào)用該接口?;蛘叨啻握{(diào)用該接口,便會(huì)出現(xiàn)以下控制臺(tái)所示的結(jié)果。

下面我們就來討論下解決這個(gè)線程不安全的問題的辦法
解決方式一:
在對(duì)應(yīng)的類名上加上該注解@Scope("prototype"),表示每次調(diào)用該接口都會(huì)生成一個(gè)新的Bean。下圖示例

解決方案二 ThreadLocal解決問題
@RestController
//@Scope("prototype")
public class BeanController {
private static ThreadLocal<Integer> content = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return (int)(Math.random()*10+100);
}
};
private static ThreadLocal<String> test = new ThreadLocal<String>() {
@Override
protected String initialValue() {
return "單例模式是不安全的"+(int)(Math.random()*10+100);
}
};
@RequestMapping("testBean")
public Object getSercurity(){
System.out.println(content.get());
System.out.println(test.get()); System.out.println();
return test.get();
}
}
第三種解決方案:
盡量不要使用成員變量
第四種解決方案:
前提:
該程序是web應(yīng)用,可以使用Spring Bean的作用域中的request,就是說在類前面加上@Scope("request"),表明每次請(qǐng)求都會(huì)生成一個(gè)新的Bean對(duì)象。
作用于@Scope("prototype")類似。
補(bǔ)充知識(shí):SpringMVC是單例的,高并發(fā)情況下,如何保證性能的?
首先在大家的思考中,肯定有影響的,你想想,單例顧名思義:一個(gè)個(gè)排隊(duì)過... 高訪問量的時(shí)候,你能想象服務(wù)器的壓力了... 而且用戶體驗(yàn)也不怎么好,等待太久~
實(shí)質(zhì)上這種理解是錯(cuò)誤的,Java里有個(gè)API叫做ThreadLocal,spring單例模式下用它來切換不同線程之間的參數(shù)。用ThreadLocal是為了保證線程安全,實(shí)際上ThreadLoacal的key就是當(dāng)前線程的Thread實(shí)例。單例模式下,spring把每個(gè)線程可能存在線程安全問題的參數(shù)值放進(jìn)了ThreadLocal。這樣雖然是一個(gè)實(shí)例在操作,但是不同線程下的數(shù)據(jù)互相之間都是隔離的,因?yàn)檫\(yùn)行時(shí)創(chuàng)建和銷毀的bean大大減少了,所以大多數(shù)場景下這種方式對(duì)內(nèi)存資源的消耗較少,而且并發(fā)越高優(yōu)勢越明顯。
總的來說就是,單利模式因?yàn)榇蟠蠊?jié)省了實(shí)例的創(chuàng)建和銷毀,有利于提高性能,而ThreadLocal用來保證線程安全性。
另外補(bǔ)充說一句,單例模式是spring推薦的配置,它在高并發(fā)下能極大的節(jié)省資源,提高服務(wù)抗壓能力。spring IOC的bean管理器是“絕對(duì)的線程安全”。
以上這篇Spring如何解決單例bean線程不安全的問題就是小編分享給大家的全部內(nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
java實(shí)現(xiàn)文本框和文本區(qū)的輸入輸出
這篇文章主要介紹了java實(shí)現(xiàn)文本框和文本區(qū)的輸入輸出的方法和具體示例,有需要的小伙伴可以參考下。2015-06-06
SpringBoot使用validation做參數(shù)校驗(yàn)的實(shí)現(xiàn)步驟
這篇文章主要介紹了SpringBoot使用validation做參數(shù)校驗(yàn)的實(shí)現(xiàn)步驟,幫助大家更好的理解和學(xué)習(xí)使用SpringBoot,感興趣的朋友可以了解下2021-05-05
SpringIOC DI循環(huán)依賴實(shí)例詳解
這篇文章主要介紹了SpringIOC——DI循環(huán)依賴,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03
gRPC實(shí)踐之proto及Maven插件概念及使用詳解
這篇文章主要為大家介紹了gRPC實(shí)踐之proto及Maven插件概念及使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04
Java實(shí)現(xiàn)兩人五子棋游戲(三) 畫出棋子
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)兩人五子棋游戲,畫出五子棋的棋子,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-03-03
spring boot集成shiro詳細(xì)教程(小結(jié))
這篇文章主要介紹了spring boot 集成shiro詳細(xì)教程,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-01-01

