Je lisais le JavaDoc pour Threadlocal ici
http://Java.Sun.com/j2se/1.5.0/docs/api/Java/lang/ThreadLocal.html
et il est écrit "Les instances de ThreadLocal sont généralement des champs statiques privés dans les classes souhaitant associer un état à un fil (par exemple, un ID utilisateur ou un ID de transaction)."
Mais ma question est la suivante: pourquoi ont-ils choisi de le rendre statique (généralement)? Cela rend les choses un peu confuses d’avoir l’état "par thread" mais les champs sont statiques?
Parce que s'il s'agissait d'un champ de niveau instance, il s'agirait en réalité de "Per Thread - Per Instance", pas simplement d'un "Per Thread" garanti. Ce n'est pas normalement la sémantique que vous recherchez.
Habituellement, il contient des objets tels que des objets liés à une conversation utilisateur, une requête Web, etc. Vous ne voulez pas qu'ils soient également sous-appliqués à l'instance de la classe.
Une demande Web => une session de persistance.
Pas une seule requête Web => une session de persistance par objet.
Rendez-la statique ou si vous essayez d'éviter les champs statiques de votre classe - faites de la classe elle-même un singleton, puis vous pouvez utiliser en toute sécurité le niveau d'instance ThreadLocal tant que ce singleton est disponible globalement.
Ce n'est pas obligé. L'important est que ce soit un singleton.
La raison en est que les variables sont accessibles via un pointeur associé au thread. Elles agissent comme des variables globales avec une étendue de thread, par conséquent statique est la solution la plus proche. C’est ainsi que vous obtenez l’état local des threads dans des tâches telles que pthreads. Cela pourrait donc être un simple accident de l’historique et de la mise en œuvre.
Reportez-vous à this , cela vous donnera une meilleure compréhension.
En bref, l’objet ThreadLocal
fonctionne comme une mappe valeur-clé. Lorsque le thread appelle la méthode ThreadLocal
get/set
, il récupère/stocke l'objet de thread dans la clé de la carte et la valeur dans la valeur de la carte. C'est pourquoi différents threads ont différentes valeurs copiées (que vous souhaitez stocker localement), car elles résident dans l'entrée de la carte différente.
C'est pourquoi vous n'avez besoin que d'une seule carte pour conserver toutes les valeurs. Bien que cela ne soit pas nécessaire, vous pouvez avoir plusieurs mappes (sans déclarer static) pour conserver chaque objet thread, ce qui est totalement redondant, raison pour laquelle la variable statique est préférée.
Une utilisation pour un threadlocal sur une instance par thread est si vous voulez que quelque chose soit visible dans toutes les méthodes d'un objet et que celui-ci soit thread-safe sans synchroniser l'accès à celui-ci comme vous le feriez pour un champ ordinaire.
static final ThreadLocal
les variables sont thread-safe.
static
rend la variable ThreadLocal disponible dans plusieurs classes pour le thread respectif uniquement. c'est une sorte de définition de variable globale des variables locales de thread respectives sur plusieurs classes.
Nous pouvons vérifier la sécurité de ce fil avec l'exemple de code suivant.
CurrentUser
- stocke l'ID utilisateur actuel dans ThreadLocalTestService
- Service simple avec la méthode - getUser()
pour extraire l'utilisateur actuel de CurrentUser.TestThread
- cette classe utilisée pour créer plusieurs threads et définir des ID utilisateur simultanément.
public class CurrentUser
public class CurrentUser {
private static final ThreadLocal<String> CURRENT = new ThreadLocal<String>();
public static ThreadLocal<String> getCurrent() {
return CURRENT;
}
public static void setCurrent(String user) {
CURRENT.set(user);
}
}
public class TestService {
public String getUser() {
return CurrentUser.getCurrent().get();
}
}
.
import Java.util.ArrayList;
import Java.util.List;
public class TestThread {
public static void main(String[] args) {
List<Integer> integerList = new ArrayList<>();
//creates a List of 100 integers
for (int i = 0; i < 100; i++) {
integerList.add(i);
}
//parallel stream to test concurrent thread execution
integerList.parallelStream().forEach(intValue -> {
//All concurrent thread will set the user as "intValue"
CurrentUser.setCurrent("" + intValue);
//Thread creates a sample instance for TestService class
TestService testService = new TestService();
//Print the respective thread name along with "intValue" value and current user.
System.out.println("Start-"+Thread.currentThread().getName()+"->"+intValue + "->" + testService.getUser());
try {
//all concurrent thread will wait for 3 seconds
Thread.sleep(3000l);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//Print the respective thread name along with "intValue" value and current user.
System.out.println("End-"+Thread.currentThread().getName()+"->"+intValue + "->" + testService.getUser());
});
}
}
.
Exécutez la classe principale TestThread . Sortie -
Start-main->62->62
Start-ForkJoinPool.commonPool-worker-2->31->31
Start-ForkJoinPool.commonPool-worker-3->81->81
Start-ForkJoinPool.commonPool-worker-1->87->87
End-main->62->62
End-ForkJoinPool.commonPool-worker-1->87->87
End-ForkJoinPool.commonPool-worker-2->31->31
End-ForkJoinPool.commonPool-worker-3->81->81
Start-ForkJoinPool.commonPool-worker-2->32->32
Start-ForkJoinPool.commonPool-worker-3->82->82
Start-ForkJoinPool.commonPool-worker-1->88->88
Start-main->63->63
End-ForkJoinPool.commonPool-worker-1->88->88
End-main->63->63
...
Résumé d'analyse
main
exécution se termine et affiche l'utilisateur actuel sous la forme "62". Parallèlement, l'exécution ForkJoinPool.commonPool-worker-1
prend fin et affiche l'utilisateur actuel sous la forme "87". Parallèlement, l'exécution ForkJoinPool.commonPool-worker-2
s'achève et affiche l'utilisateur actuel sous la forme "31". __ parallèlement ForkJoinPool.commonPool-worker-3
l'exécution se termine et affiche l'utilisateur actuel sous "81"Inférence
Les threads simultanés sont capables d'extraire les ID utilisateur corrects même s'ils ont été déclarés comme "statique final ThreadLocal"