ThreadLocal为线程提供包装对象的独占副本。 我正在执行一个场景
public class CustomerThread extends Thread{
static Integer custId =0;
private static ThreadLocal t1 = new ThreadLocal(){
protected Integer initialValue() {
return ++custId;
}
};
public CustomerThread(String name) {
super(name);
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+ " executing with customer Id : "+t1.get());
}
}
public class ThreadLocalDemo {
public static void main(String[] args) {
CustomerThread c1 = new CustomerThread("A");
CustomerThread c2 = new CustomerThread("B");
CustomerThread c3 = new CustomerThread("C");
CustomerThread c4 = new CustomerThread("D");
CustomerThread c5 = new CustomerThread("E");
CustomerThread c6 = new CustomerThread("F");
CustomerThread c7 = new CustomerThread("G");
CustomerThread c8 = new CustomerThread("H");
CustomerThread c9 = new CustomerThread("I");
CustomerThread c10 = new CustomerThread("J");
c1.start();
c2.start();
c3.start();
c4.start();
c5.start();
c6.start();
c7.start();
c8.start();
c9.start();
c10.start();
}
}
Threadlocal应该为每个客户获得唯一的价值,但是当我在某些情况下运行上述情况时,它正在生产
执行客户ID:1
B与客户ID执行:1
D与客户ID执行:3
C执行客户ID:2
E与客户ID执行:4
F以客户ID执行:5
G与客户ID执行:6
H与客户ID执行:7
我执行客户ID:8
J与客户Id执行:9
这里A和B获得相同的值。
有人可以解释这是正确的行为w.r.t ThreadLocal吗?
答案 0 :(得分:2)
您的问题与ThreadLocal
无关。你的问题是这不是一个原子操作:
++custID;
可能发生的情况是,主题A看到custID == 1
,将其存储在ThreadLocal
对象的自己的bin中,并分配custID=2
。同时,线程B也看到custID == 1
并且它做同样的事情。
您需要某种保护 - 互斥锁或AtomicInteger
,以确保一次只有一个线程尝试获取新的custID
值。
P.S。:我会尽量避免在新代码中使用ThreadLocal
。 ThreadLocal
的主要用途是将使用static
变量的旧代码从单线程转换为多线程。但是,如果您正在编写新代码,那么您应该尽力避免static
。 static
会使您的代码难以维护,并且非常难以正确测试。
在小型一次性课程中使用static
并没有错,只不过它会教你一个坏习惯。
答案 1 :(得分:1)
尝试将AtomicInteger
用于您的计数器。
https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicInteger.html