错误使用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