Spring 中的 bean 是線程安全的嗎?
閱讀本文大概需要 7 分鐘。
singleton:單例,默認(rèn)作用域。 prototype:原型,每次創(chuàng)建一個(gè)新對象。 request:請求,每次Http請求創(chuàng)建一個(gè)新對象,適用于WebApplicationContext環(huán)境下。 session:會(huì)話,同一個(gè)會(huì)話共享一個(gè)實(shí)例,不同會(huì)話使用不用的實(shí)例。 global-session:全局會(huì)話,所有會(huì)話共享一個(gè)實(shí)例。
spring單例,為什么controller、service和dao確能保證線程安全?
有狀態(tài)就是有數(shù)據(jù)存儲(chǔ)功能 無狀態(tài)就是不會(huì)保存數(shù)據(jù) controller、service和dao層本身并不是線程安全的,只是如果只是調(diào)用里面的方法,而且多線程調(diào)用一個(gè)實(shí)例的方法,會(huì)在內(nèi)存中復(fù)制變量,這是自己的線程的工作內(nèi)存,是安全的。
Java虛擬機(jī)棧是線程私有的,它的生命周期與線程相同。虛擬機(jī)棧描述的是Java方法執(zhí)行的內(nèi)存模型:每個(gè)方法在執(zhí)行的同時(shí)都會(huì)創(chuàng)建一個(gè)棧幀用于存儲(chǔ)局部變量表、操作數(shù)棧、動(dòng)態(tài)鏈接、方法出口等信息。
局部變量的固有屬性之一就是封閉在執(zhí)行線程中。它們位于執(zhí)行線程的棧中,其他線程無法訪問這個(gè)棧。
首先問@Controller @Service是不是線程安全的?
@RestController
public class TestController {
private int var = 0;
@GetMapping(value = "/test_var")
public String test() {
System.out.println("普通變量var:" + (++var));
return "普通變量var:" + var ;
}
}
普通變量var:1
普通變量var:2
普通變量var:3
@RestController
@Scope(value = "prototype") // 加上@Scope注解,他有2個(gè)取值:單例-singleton 多實(shí)例-prototype
public class TestController {
private int var = 0;
@GetMapping(value = "/test_var")
public String test() {
System.out.println("普通變量var:" + (++var));
return "普通變量var:" + var ;
}
}
普通變量var:1
普通變量var:1
普通變量var:1
@RestController
@Scope(value = "prototype") // 加上@Scope注解,他有2個(gè)取值:單例-singleton 多實(shí)例-prototype
public class TestController {
private int var = 0;
private static int staticVar = 0;
@GetMapping(value = "/test_var")
public String test() {
System.out.println("普通變量var:" + (++var)+ "---靜態(tài)變量staticVar:" + (++staticVar));
return "普通變量var:" + var + "靜態(tài)變量staticVar:" + staticVar;
}
}
普通變量var:1---靜態(tài)變量staticVar:1
普通變量var:1---靜態(tài)變量staticVar:2
普通變量var:1---靜態(tài)變量staticVar:3
@RestController
@Scope(value = "singleton") // prototype singleton
public class TestController {
private int var = 0; // 定義一個(gè)普通變量
private static int staticVar = 0; // 定義一個(gè)靜態(tài)變量
@Value("${test-int}")
private int testInt; // 從配置文件中讀取變量
ThreadLocal<Integer> tl = new ThreadLocal<>(); // 用ThreadLocal來封裝變量
@Autowired
private User user; // 注入一個(gè)對象來封裝變量
@GetMapping(value = "/test_var")
public String test() {
tl.set(1);
System.out.println("先取一下user對象中的值:"+user.getAge()+"===再取一下hashCode:"+user.hashCode());
user.setAge(1);
System.out.println("普通變量var:" + (++var) + "===靜態(tài)變量staticVar:" + (++staticVar) + "===配置變量testInt:" + (++testInt)
+ "===ThreadLocal變量tl:" + tl.get()+"===注入變量user:" + user.getAge());
return "普通變量var:" + var + ",靜態(tài)變量staticVar:" + staticVar + ",配置讀取變量testInt:" + testInt + ",ThreadLocal變量tl:"
+ tl.get() + "注入變量user:" + user.getAge();
}
}
@Configuration
public class MyConfig {
@Bean
public User user(){
return new User();
}
}
先取一下user對象中的值:0===再取一下hashCode:241165852
普通變量var:1===靜態(tài)變量staticVar:1===配置變量testInt:1===ThreadLocal變量tl:1===注入變量user:1
先取一下user對象中的值:1===再取一下hashCode:241165852
普通變量var:2===靜態(tài)變量staticVar:2===配置變量testInt:2===ThreadLocal變量tl:1===注入變量user:1
先取一下user對象中的值:1===再取一下hashCode:241165852
普通變量var:3===靜態(tài)變量staticVar:3===配置變量testInt:3===ThreadLocal變量tl:1===注入變量user:1
先取一下user對象中的值:0===再取一下hashCode:853315860
普通變量var:1===靜態(tài)變量staticVar:1===配置變量testInt:1===ThreadLocal變量tl:1===注入變量user:1
先取一下user對象中的值:1===再取一下hashCode:853315860
普通變量var:1===靜態(tài)變量staticVar:2===配置變量testInt:1===ThreadLocal變量tl:1===注入變量user:1
先取一下user對象中的值:1===再取一下hashCode:853315860
普通變量var:1===靜態(tài)變量staticVar:3===配置變量testInt:1===ThreadLocal變量tl:1===注入變量user:1
public class MyConfig {
@Bean
@Scope(value = "prototype")
public User user(){
return new User();
}
}
先取一下user對象中的值:0===再取一下hashCode:1612967699
普通變量var:1===靜態(tài)變量staticVar:1===配置變量testInt:1===ThreadLocal變量tl:1===注入變量user:1
先取一下user對象中的值:0===再取一下hashCode:985418837
普通變量var:1===靜態(tài)變量staticVar:2===配置變量testInt:1===ThreadLocal變量tl:1===注入變量user:1
先取一下user對象中的值:0===再取一下hashCode:1958952789
普通變量var:1===靜態(tài)變量staticVar:3===配置變量testInt:1===ThreadLocal變量tl:1===注入變量user:1
推薦閱讀:
Java身份證號碼識別系統(tǒng)(開源項(xiàng)目)
IDEA下創(chuàng)建SpringBoot+MyBatis+MySql項(xiàng)目實(shí)現(xiàn)動(dòng)態(tài)登錄與注冊功能
微信掃描二維碼,關(guān)注我的公眾號
朕已閱 

