Le but de ThreadLocal?


Duplicata possible: Quand et comment dois-je utiliser une variable Threadlocal


Le but de ThreadLocal tel que donné ici indique que la variable est locale à tout Thread accédant à un objet contenant la variable ThreadLocal. Quelle différence cela fait - il, en ayant une variable ThreadLocal en tant que membre d'une classe, puis en la rendant locale à un Thread, plutôt qu'en ayant une variable locale au Thread lui-même?

Author: Community, 2009-09-29

6 answers

Un thread est une unité d'exécution et donc plusieurs threads peuvent exécuter le même code en même temps. Si plusieurs threads s'exécutent sur un objet / instance en même temps, ils partageront les variables d'instance. Chaque thread aura ses propres variables locales, mais il est difficile de les partager entre les objets sans passer de paramètres.

Il est mieux expliqué à titre d'exemple. Disons que vous avez un Servlet qui obtient l'utilisateur connecté et exécute ensuite du code.

doGet(HttpServletRequest req, HttpServletResponse resp) {
  User user = getLoggedInUser(req);
  doSomething()
  doSomethingElse()
  renderResponse(resp)
}

Maintenant que se passe-t-il si les méthodes doSomething() ont besoin d'accéder à l'objet utilisateur? Vous ne pouvez pas faire de l'objet utilisateur une instance ou une variable statique car chaque thread utilisera alors le même objet utilisateur. Vous pouvez passer l'objet utilisateur en tant que paramètre, mais cela devient rapidement désordonné et fuit les objets utilisateur dans chaque appel de méthode:

doGet(HttpServletRequest req, HttpServletResponse resp) {
  User user = getLoggedInUser(req);
  doSomething(user)
  doSomethingElse(user)
  renderResponse(resp,user)
}

Une solution plus élégante consiste à placer l'objet utilisateur dans un ThreadLocal

doGet(HttpServletRequest req, HttpServletResponse resp) {
  User user = getLoggedInUser(req);
  StaticClass.getThreadLocal().set(user)
  try {
    doSomething()
    doSomethingElse()
    renderResponse(resp)
  }
  finally {
    StaticClass.getThreadLocal().remove()
  }
}

Maintenant, tout code qui nécessite l'objet utilisateur à tout moment peut obtenir en l'extrayant du thread local, sans avoir besoin de recourir à ces paramètres supplémentaires embêtants:

User user = StaticClass.getThreadLocal().get()

Si vous utilisez cette approche, veillez à supprimer à nouveau les objets dans un bloc finally. Sinon, l'objet utilisateur peut traîner dans des environnements qui utilisent un pool de threads (comme Tomcat app server).

Edit: Le code pour la classe statique

class StaticClass {
  static private ThreadLocal threadLocal = new ThreadLocal<User>();

  static ThreadLocal<User> getThreadLocal() {
    return threadLocal;
  }
}
 76
Author: leonm, 2015-09-09 15:59:35

Vous devez réaliser que une instance d'une classe qui étend Thread est pas la même chose qu'un thread Java réel (qui peut être imaginé comme un "pointeur d'exécution" qui parcourt votre code et l'exécute).

Les instances d'une telle classe représentent un thread Java et permettent de le manipuler (par exemple, l'interrompre), mais en dehors de cela, ce ne sont que des objets réguliers, et leurs membres sont accessibles à partir de tous les threads qui peuvent obtenir une référence à la objet (qui est pas dur).

Bien sûr, vous pouvez essayer de garder un membre privé et vous assurer qu'il n'est utilisé que par le run() ou les méthodes appelées à partir de celui-ci (les méthodes publiques peuvent également être appelées à partir d'autres threads), mais cela est sujet aux erreurs et pas vraiment faisable pour un système plus complexe où vous ne voulez pas garder les données dans une sous-classe de Thread (en fait, vous n'êtes pas censé sous-classe Thread, mais utiliser Runnable à la place).

ThreadLocal est un moyen simple et flexible de avoir des données par thread qui ne peuvent pas être accessibles simultanément par d'autres threads, sans nécessiter de gros efforts ou des compromis de conception.

 12
Author: Michael Borgwardt, 2009-09-29 11:42:23

Un objet Thread peut avoir des membres de données internes mais ceux-ci sont accessibles à toute personne qui a (ou peut obtenir) une référence à l'objet Thread. Un ThreadLocal est délibérément associé uniquement à chaque Thread qui y accède. L'avantage est qu'il n'y a pas de problèmes de concurrence (dans le contexte du ThreadLocal). Le membre de données interne d'un thread a tous les mêmes problèmes de concurrence que tout état partagé.

Permettez-moi d'expliquer l'idée d'associer un résultat à un fil. L'essence d'un ThreadLocal est quelque chose comme ceci:

public class MyLocal<T> {
  private final Map<Thread, T> values = new HashMap<Thread, T>();

  public T get() {
    return values.get(Thread.currentThread());
  }

  public void set(T t) {
    values.put(Thread.currentThread(), t);
  }
}

Maintenant, il y a plus que cela, mais comme vous pouvez le voir, la valeur renvoyée est déterminée par le thread actuel. C'est pourquoi il est local à chaque thread.

 7
Author: cletus, 2009-09-29 07:40:27

ThreadLocal est très utile dans les applications Web. Le modèle typique est que quelque part au début du traitement d'une requête Web (généralement dans un filtre de servlet), l'état est stocké dans une variable ThreadLocal. Étant donné que tout le traitement d'une requête est effectué dans 1 thread, tous les composants participant à la requête ont accès à cette variable.

 5
Author: Kees de Kooter, 2009-09-29 06:55:31

Il y a une entrée wikipedia sur cette zone à problème. Dans notre environnement, il est généralement utilisé pour garder les choses locales à demander. Côté serveur, une requête est principalement gérée par un seul thread. Pour garder les choses locales, vous placez vos données, par exemple les données de session, dans une variable locale de thread. Ces données sont invisibles pour l'autre requête (threads) et vous n'avez donc pas besoin de les synchroniser avec les autres requêtes.

Et n'oubliez pas, il existe des constructions API JAVA, qui sont pas thread-safe, par exemple DateFormat. Une instance statique de DateFormat ne fonctionne tout simplement pas côté serveur.

En fait, il est plus facile de gérer la programmation multithread lorsque vous utilisez votre propre copie privée de données que de gérer avec des verrous et des moniteurs.

 2
Author: dz., 2009-09-29 07:01:38

L'avantage des ThreadLocals est qu'ils sont utilisables par des méthodes exécutées sur des Threads plain vanilla ... ou d'une sous-classe de Thread.

En revanche, si vos sections locales de thread doivent être implémentées en tant que membres d'une sous-classe personnalisée de Thread, vous ne pouvez pas faire beaucoup de choses. Par exemple, votre application aura des problèmes si elle doit exécuter des méthodes sur des instances de thread vanilla préexistantes; c'est-à-dire des instances créées par du code de bibliothèque que le rédacteur de l'application n'a pas fait écrire, et ne peut pas modifier.

 1
Author: Stephen C, 2009-09-29 06:49:47