使用ThreadLocal将ID分配给每个线程



在以下程序中,我想为每个线程分配不同的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,您应该将AtomicIntegergetAndIncrement()方法一起使用。

您的代码有两个问题:

  1. 您的静态CUSTID值的非线程安全递增
  2. 每次都在创建此类的新实例时(即,您的类的单个实例都不会在线程上共享,而每个线程已经具有该类的实例(。

问题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一起工作。

最新更新