[英]Assign ID to each thread using ThreadLocal
在下面的程序中,我想為每個線程分配唯一的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
您的代碼不是線程安全的,因為++
運算符不是線程安全的。
您應該使用AtomicInteger
,沒有理由使用ThreadLocal
。
將您的類更改為此,以在創建時分配ID,即按創建順序分配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()
方法。
您的代碼有兩個問題:
問題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);
}
}
您在此處看到的是,默認情況下, ThreadLocal.initialValue()
和整數增量不是線程安全的,因此它們的組合也不會變為線程安全的。
“官方” ThreadLocal
示例使用AtomicInteger(這也是其他人的建議),這使得整數增量線程安全。 但是您也可以通過使其synchronized
來自由地使initialValue()
方法成為線程安全的:
// ... your original code ...
synchronized protected Integer initialValue() {
// ... your original code ...
然后,您的代碼將可以與簡單的Integer
一起正常工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.