Это значит, что каждый поток имеет свой собственный, индивидуально инициализируемый экземпляр ThreadLocal-переменной, доступ к которой он получает через методы get() или set(). Даже если это поле будет статическое, оно все равно у каждого потока будет своё.
Как работает ThreadLocal? У каждого потока - т.е. экземпляра класса Thread - есть ассоциированная с ним таблица ThreadLocal-переменных. Ключами таблицы являются cсылки на объекты класса ThreadLocal, а значениями - ссылки на объекты, "захваченные" ThreadLocal-переменными.
Например, если мы объявим ThreadLocal-переменную:
ThreadLocal<Object> local = new ThreadLocal<Object>();
А затем, в потоке, сделаем:
local.set(myObject);
то ключом таблицы будет ссылка на объект local, а значением - ссылка на объект myObject. При этом для другого потока мы можем "положить" внутрь local другое значение.
class MyLogger {
static ThreadLocal<Integer> countTasks = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return 0;
}
};
public void toLog(String message) {
LocalDateTime date = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("mm:ss:n");
System.out.println(date.format(formatter) + " " + message);
}
class MyTask extends Thread {
MyLogger logger;
int countTasks;
String threadName;
MyTask(MyLogger logger, int countTasks) {
this.logger = logger;
this.countTasks = countTasks;
}
@Override
public void run() {
threadName = Thread.currentThread().getName();
for (int i = 1; i <= countTasks; i++) {
doSomeUseful();
String message = threadName + " done task #" + i;
logger.toLog(message);
MyLogger.countTasks.set(i);
}
System.out.println(threadName
+ ": count of tasks is "
+ MyLogger.countTasks.get());
}
private void doSomeUseful() {
try {
Thread.sleep((long) Math.random() * 1000);
} catch (InterruptedException e) {
e.printStackTrace(System.out);
}
}
}
MyLogger logger = new MyLogger();
MyTask task1 = new MyTask(logger, 5);
MyTask task2 = new MyTask(logger, 3);
task1.start();
task2.start();
Возможный вывод:
/*
24:52:538000000 Thread-0 done task #1
24:52:538000000 Thread-1 done task #1
24:52:553000000 Thread-0 done task #2
24:52:553000000 Thread-1 done task #2
24:52:553000000 Thread-0 done task #3
24:52:553000000 Thread-1 done task #3
Thread-1: count of tasks is 3
24:52:553000000 Thread-0 done task #4
24:52:553000000 Thread-0 done task #5
Thread-0: count of tasks is 5
*/
Хорошая статья о ThreadLockal-переменных