首先直接給出答案:不是執行緒安全的
一、分析問題
證明不是執行緒安全的案例如下:
public class Student {
private String stuName;
public String report(String uname){
stuName = "大家好,我叫:"+uname;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
return stuName;
}
}
-----------------------------------------------------------------------------------------------------------------
public class Run {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
Student bean1 = context.getBean(Student.class);
new Thread(() -> {
System.out.println(bean1.report("張三"));
}).start();
Student bean2 = context.getBean(Student.class);
new Thread(() -> {
System.out.println(bean2.report("李四"));
}).start();
}
}

分析原因:執行緒一執行完stuName的賦值后進入休眠,執行緒二這時候也進入該方法對stuName進行賦值,由于物件是單例的,執行緒二的賦值操作也就影響了執行緒一的列印結果,導致最后列印的結果都是執行緒二傳入的值,
二、解決方法
既然單例bean不是執行緒安全的,那么該怎么解決上面的問題呢?下面博主給出四種解決方法僅供讀者參考:
1.方法一:將成員變數放入方法中
修改后的Student類如下:
public class Student {
// private String stuName;
public String report(String uname){
String stuName = "大家好,我叫:"+uname;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
return stuName;
}
}
2.方法二:加鎖使方法串行執行
比如下面的方法中我加入了synchronized鎖:
public class Student {
private String stuName;
public synchronized String report(String uname){
stuName = "大家好,我叫:"+uname;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
return stuName;
}
}
3.方法三:將bean變成原型模式
比如加上Scope注解宣告為多例模式:
@Bean
@Scope("prototype")
public Student student(){
return new Student();
}
4.方法四:使用ThreadLocal
改造后的代碼如下:
public class Student {
private ThreadLocal<String> stuName = new ThreadLocal<>();
public String report(String uname){
stuName.set("大家好,我叫:"+uname);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
return stuName.get();
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/345633.html
標籤:其他
