在下面的程序中,我想为每个线程分配不同的id,但是在输出中,每个线程都有不一致的id,如输出中所示。但是,如果我取消注释system.out语句,则会为每个线程分配唯一的ID,但不确定原因。
class ThreadLocalDemo {
public static void main(String[] args) throws InterruptedException,
ExecutionException {
CustomerThread custThread1 = new CustomerThread("Sampath");
CustomerThread custThread2 = new CustomerThread("Harish");
CustomerThread custThread3 = new CustomerThread("Harsha");
CustomerThread custThread4 = new CustomerThread("Gowtham");
custThread1.start();
custThread2.start();
custThread3.start();
custThread4.start();
}
}
class CustomerThread extends Thread {
static Integer custId = 0;
private static ThreadLocal<Integer> tl = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
//System.out.println("will work");
return ++custId;
}
};
CustomerThread(String name) {
super(name);
}
public void run() {
System.out.println(Thread.currentThread().getName() + " executing with id: " + tl.get());
}
}
输出是:
Sampath executing with id: 1
Harish executing with id:
Harsha executing with id: 2
Gowtham executing with id: 1
预期输出是具有唯一ID的线程:
Sampath executing with id: 1
Harish executing with id: 2
Harsha executing with id: 3
Gowtham executing with id: 4
答案 0 :(得分:2)
您的代码不是线程安全的,因为class CustomerThread extends Thread {
private static final AtomicInteger prevCustId = new AtomicInteger();
private final int custId;
CustomerThread(String name) {
super(name);
this.custId = prevCustId.incrementAndGet();
}
@Override
public void run() {
System.out.println(getName() + " executing with id: " + this.custId);
}
}
运算符不是线程安全的。
您应该使用AtomicInteger
,并且没有理由使用ThreadLocal
。
将您的班级更改为此,在创建时分配ID,即按创建顺序分配,而不是在首次使用时延期:
Sampath executing with id: 1
Harsha executing with id: 3
Gowtham executing with id: 4
Harish executing with id: 2
示例输出
{{1}}
答案 1 :(得分:1)
您无法在不同的主题中安全地增加Integer
,您应该使用AtomicInteger
getAndIncrement()
方法来处理您的情况。
答案 2 :(得分:1)
您的代码存在两个问题:
问题1的修复是使用AtomicInteger,还是在同步块中执行增量操作。
问题2的修复是简单地删除静态ThreadLocal变量,只使用常规的非静态变量。
代码的固定版本:
public class ThreadLocalDemo
{
public static void main(String[] args) throws InterruptedException {
CustomerThread custThread1 = new CustomerThread("Sampath");
CustomerThread custThread2 = new CustomerThread("Harish");
CustomerThread custThread3 = new CustomerThread("Harsha");
CustomerThread custThread4 = new CustomerThread("Gowtham");
custThread1.start();
custThread2.start();
custThread3.start();
custThread4.start();
}
}
class CustomerThread extends Thread {
static AtomicInteger custId = new AtomicInteger(0);
private int tl;
CustomerThread(String name) {
super(name);
tl = custId.incrementAndGet();
}
public void run() {
System.out.println(Thread.currentThread().getName() + " executing with id: " + tl);
}
}
答案 3 :(得分:1)
你在这里看到的是ThreadLocal.initialValue()
并且整数增量在默认情况下不是线程安全的,因此它们的组合也不会成为线程安全的。
'官方'ThreadLocal
示例使用AtomicInteger(这也是其他人的建议),这使整数增量成为线程安全的。但是你也可以自由地使initialValue()
方法成为线程安全的,synchronized
:
// ... your original code ...
synchronized protected Integer initialValue() {
// ... your original code ...
然后您的代码可以使用简单的Integer
。