在以下程序中,我想为每个线程分配不同的ID,但是在输出中,每个线程的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
您的代码不是线程安全,因为++
操作员不是线程安全。
您应该使用AtomicInteger
,并且没有理由使用ThreadLocal
。
将您的班级更改为此,以在创建时分配ID,即按创建顺序,直到首次使用直到首次使用:
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);
}
}
样本输出
Sampath executing with id: 1
Harsha executing with id: 3
Gowtham executing with id: 4
Harish executing with id: 2
您无法在不同的线程中安全地递增Integer
,您应该将AtomicInteger
与getAndIncrement()
方法一起使用。
您的代码有两个问题:
- 您的静态CUSTID值的非线程安全递增
- 每次都在创建此类的新实例时(即,您的类的单个实例都不会在线程上共享,而每个线程已经具有该类的实例(。
问题1的修复是使用AtomicInteger,或在同步块中执行增量操作。
问题2的修复是简单地删除静态螺纹局部变量,然后只需使用常规的非静态变量。
您的代码的固定版本:
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);
}
}
您在这里看到的是ThreadLocal.initialValue()
和Integer增量默认不是线程安全,因此它们的组合也不会成为线程安全。
"官方" ThreadLocal
示例使用了原子图(这也是其他人也建议的(,这使整数增量螺纹安全。但是您也可以通过使其synchronized
来自由地制作initialValue()
方法线程安全:
// ... your original code ...
synchronized protected Integer initialValue() {
// ... your original code ...
然后,您的代码可以与简单的Integer
一起工作。