ThreadLocal问题

ThreadLocal issue

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 应该为每个客户获得唯一的价值,但是当我在上面的场景中运行时,它有时会产生

A 使用客户 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 吗?

您的问题与ThreadLocal无关。你的问题是这不是一个原子操作:

++custID;

可能发生的情况是,线程 A 看到 custID == 1,将其存储到 ThreadLocal 对象中自己的 bin 中,并分配 custID=2。同时,线程 B 也看到 custID == 1 并且它做同样的事情。

您需要某种保护——互斥锁或 AtomicInteger,以确保一次只有一个线程尝试获取新的 custID 值。


P.S.: 我会尽量避免在新代码中使用 ThreadLocalThreadLocal 的主要用途是将使用 static 变量的旧代码从单线程转换为多线程。但是如果你正在编写新代码,你应该首先尽力避免 staticstatic 使您的代码难以维护,并且 非常 难以正确测试。

在一次性的小程序中使用 static 没有任何问题,只是它会教给你一个坏习惯。

尝试使用 AtomicInteger 作为您的计数器。 https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicInteger.html