錯誤使用ThreadLocal導致線程不安全
public class ThreadLocalFault extends Thread{
private static User user = new User(0);
ThreadLocal<User> local = new ThreadLocal<>();
@Override
public void run() {
user.setAge(user.getAge()+1);
local.set(user);
System.out.println(Thread.currentThread().getName()+":"+local.get().getAge());
}
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
new ThreadLocalFault().start();
}
}
static class User{
int age;
public User(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
}
運行後的結果爲
Thread-2:3
Thread-3:4
Thread-0:3
Thread-1:3
Thread-4:5
而預料中的正確結果應該都是1
原因分析
爲什麼ThreadLocal在這裏會產生錯誤的結果,是因爲我們Thread 的變量ThreadLocalMap存儲的是對象的一個引用,一個線程修改對象值,其他引用對象的值也會發生改變。因爲private static User user = new User(0);,使用static修飾,是靜態變量五個線程的ThreadLocal保存的是同一個對象的引用,所以結果就產生了偏差
解決方法
方法一:
去掉private static User user = new User(0);中的static
public class ThreadLocalFault extends Thread{
private User user = new User(0);
ThreadLocal<User> local = new ThreadLocal<>();
@Override
public void run() {
user.setAge(user.getAge()+1);
local.set(user);
System.out.println(Thread.currentThread().getName()+":"+local.get().getAge());
}
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
new ThreadLocalFault().start();
}
}
static class User{
int age;
public User(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
}
結果
Thread-4:1
Thread-1:1
Thread-0:1
Thread-3:1
Thread-2:1
方法二:每次new ThreadLocal的時候,在實現initial方法中,新建一個User對象
public class ThreadLocalFault extends Thread{
//private User user = new User(0);
ThreadLocal<User> local = new ThreadLocal(){
@Override
protected Object initialValue() {
return new User(0);
}
};
@Override
public void run() {
local.get().setAge(local.get().getAge()+1);
//local.set(user);
System.out.println(Thread.currentThread().getName()+":"+local.get().getAge());
}
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
new ThreadLocalFault().start();
}
}
static class User{
int age;
public User(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
}
結果
Thread-4:1
Thread-1:1
Thread-0:1
Thread-3:1
Thread-2:1