SpringBean默認(rèn)是單例的,高并發(fā)情況下,如何保證并發(fā)安全?
1、知乎高贊:拼多多和國(guó)家電網(wǎng),選哪個(gè)? 2、Windows 11 全網(wǎng)曝光,果然一股子蘋果味... 3、小團(tuán)隊(duì)真的適合引入Spring Cloud微服務(wù)嗎? 4、卷不動(dòng)了?300 秒快速了解 Java 9 - 16 新特性,助你脫離內(nèi)卷 5、Java 程序員常犯的 10 個(gè) SQL 錯(cuò)誤!
一、拋出問題
@Controller
public class HomeController {
private int i;
@GetMapping("testsingleton1")
@ResponseBody
public int test1() {
return ++i;
}
}
二、解決方案
2.1 單例變?cè)?/span>
@Scope("prototype")或@Scope("request"),對(duì)非web項(xiàng)目,在Component類上添加注解@Scope("prototype")。2.2 線程隔離類ThreadLocal
@Controller
public class HomeController {
private ThreadLocal<Integer> i = new ThreadLocal<>();
@GetMapping("testsingleton1")
@ResponseBody
public int test1() {
if (i.get() == null) {
i.set(0);
}
i.set(i.get().intValue() + 1);
log.info("{} -> {}", Thread.currentThread().getName(), i.get());
return i.get().intValue();
}
}
[INFO ] 2019-12-03 11:49:08,226 com.cjia.ds.controller.HomeController.test1(HomeController.java:50)
http-nio-8080-exec-1 -> 1
[INFO ] 2019-12-03 11:49:16,457 com.cjia.ds.controller.HomeController.test1(HomeController.java:50)
http-nio-8080-exec-2 -> 1
[INFO ] 2019-12-03 11:49:17,858 com.cjia.ds.controller.HomeController.test1(HomeController.java:50)
http-nio-8080-exec-3 -> 1
[INFO ] 2019-12-03 11:49:18,461 com.cjia.ds.controller.HomeController.test1(HomeController.java:50)
http-nio-8080-exec-4 -> 1
[INFO ] 2019-12-03 11:49:18,974 com.cjia.ds.controller.HomeController.test1(HomeController.java:50)
http-nio-8080-exec-5 -> 1
[INFO ] 2019-12-03 11:49:19,696 com.cjia.ds.controller.HomeController.test1(HomeController.java:50)
http-nio-8080-exec-6 -> 1
[INFO ] 2019-12-03 11:49:22,138 com.cjia.ds.controller.HomeController.test1(HomeController.java:50)
http-nio-8080-exec-7 -> 1
[INFO ] 2019-12-03 11:49:22,869 com.cjia.ds.controller.HomeController.test1(HomeController.java:50)
http-nio-8080-exec-9 -> 1
[INFO ] 2019-12-03 11:49:23,617 com.cjia.ds.controller.HomeController.test1(HomeController.java:50)
http-nio-8080-exec-8 -> 1
[INFO ] 2019-12-03 11:49:24,569 com.cjia.ds.controller.HomeController.test1(HomeController.java:50)
http-nio-8080-exec-10 -> 1
[INFO ] 2019-12-03 11:49:25,218 com.cjia.ds.controller.HomeController.test1(HomeController.java:50)
http-nio-8080-exec-1 -> 2
[INFO ] 2019-12-03 11:49:25,740 com.cjia.ds.controller.HomeController.test1(HomeController.java:50)
http-nio-8080-exec-2 -> 2
[INFO ] 2019-12-03 11:49:43,308 com.cjia.ds.controller.HomeController.test1(HomeController.java:50)
http-nio-8080-exec-3 -> 2
[INFO ] 2019-12-03 11:49:44,420 com.cjia.ds.controller.HomeController.test1(HomeController.java:50)
http-nio-8080-exec-4 -> 2
[INFO ] 2019-12-03 11:49:45,271 com.cjia.ds.controller.HomeController.test1(HomeController.java:50)
http-nio-8080-exec-5 -> 2
[INFO ] 2019-12-03 11:49:45,808 com.cjia.ds.controller.HomeController.test1(HomeController.java:50)
http-nio-8080-exec-6 -> 2
[INFO ] 2019-12-03 11:49:46,272 com.cjia.ds.controller.HomeController.test1(HomeController.java:50)
http-nio-8080-exec-7 -> 2
[INFO ] 2019-12-03 11:49:46,489 com.cjia.ds.controller.HomeController.test1(HomeController.java:50)
http-nio-8080-exec-9 -> 2
[INFO ] 2019-12-03 11:49:46,660 com.cjia.ds.controller.HomeController.test1(HomeController.java:50)
http-nio-8080-exec-8 -> 2
[INFO ] 2019-12-03 11:49:46,820 com.cjia.ds.controller.HomeController.test1(HomeController.java:50)
http-nio-8080-exec-10 -> 2
[INFO ] 2019-12-03 11:49:46,990 com.cjia.ds.controller.HomeController.test1(HomeController.java:50)
http-nio-8080-exec-1 -> 3
[INFO ] 2019-12-03 11:49:47,163 com.cjia.ds.controller.HomeController.test1(HomeController.java:50)
http-nio-8080-exec-2 -> 3
......
總結(jié):ThreadLocal的方式可以達(dá)到線程隔離,但還是無法達(dá)到并發(fā)安全。
2.3 盡量避免使用成員變量
@Controller
public class HomeController {
@GetMapping("testsingleton1")
@ResponseBody
public int test1() {
int i = 0;
// TODO biz code
return ++i;
}
}
2.4 使用并發(fā)安全的類
2.5 分布式或微服務(wù)的并發(fā)安全
三、補(bǔ)充說明
singleton:?jiǎn)卫J剑?dāng)spring創(chuàng)建applicationContext容器的時(shí)候,spring會(huì)欲初始化所有的該作用域?qū)嵗由蟣azy-init就可以避免預(yù)處理;prototype:原型模式,每次通過getBean獲取該bean就會(huì)新產(chǎn)生一個(gè)實(shí)例,創(chuàng)建后spring將不再對(duì)其管理;
request:搞web的大家都應(yīng)該明白request的域了吧,就是每次請(qǐng)求都新產(chǎn)生一個(gè)實(shí)例,和prototype不同就是創(chuàng)建后,接下來的管理,spring依然在監(jiān)聽;session:每次會(huì)話,同上;global session:全局的web域,類似于servlet中的application。
最近熱文閱讀:
1、知乎高贊:拼多多和國(guó)家電網(wǎng),選哪個(gè)? 2、Windows 11 全網(wǎng)曝光,果然一股子蘋果味... 3、小團(tuán)隊(duì)真的適合引入Spring Cloud微服務(wù)嗎? 4、卷不動(dòng)了?300 秒快速了解 Java 9 - 16 新特性,助你脫離內(nèi)卷 5、Java 程序員常犯的 10 個(gè) SQL 錯(cuò)誤! 6、SpringBoot+webSocket實(shí)現(xiàn)掃碼登錄功能 7、短 URL 服務(wù)的設(shè)計(jì)以及實(shí)現(xiàn) 8、為什么阿里巴巴禁止使用存儲(chǔ)過程? 9、面試官:說一下JDK/Dubbo/Spring 三種 SPI 機(jī)制,誰更好? 10、在外包干了三年,我廢了..… 不吹不黑! 關(guān)注公眾號(hào),你想要的Java都在這里
評(píng)論
圖片
表情
