Comment ThreadLocal est-il implémenté? Est-il implémenté en Java (en utilisant un mappage simultané de ThreadID en objet) ou utilise-t-il un hook JVM pour le faire plus efficacement?
Réponses
Trop de publicités?Toutes les réponses ici sont correctes, mais un peu décevant car ils ont un peu de brillance plus comment cool ThreadLocal de mise en œuvre. Je viens de regarder le code source pour ThreadLocal et a été agréablement impressionné par la façon dont il est mis en œuvre.
L'Implémentation Naïve
Si je vous demande de mettre en œuvre un ThreadLocal<T>
classe de l'API décrite dans la javadoc, que feriez-vous? Une première mise en œuvre serait susceptible d'être un ConcurrentHashMap<Thread,T>
l'aide Thread.currentThread()
que sa clé. Cela pourrait fonctionner raisonnablement bien, mais ne ont quelques inconvénients.
- Fil de contention -
ConcurrentHashMap
est un très intelligent de la classe, mais, au final, il a encore à faire face à la prévention de plusieurs threads de coucher avec elle en quelque sorte, et si les différents threads frapper régulièrement, il y aura des ralentissements. - Maintient en permanence un pointeur à la fois le Fil et de l'objet, même après que le Thread a fini et pourrait être GC ed.
Le GC-amicale de la mise en Œuvre
Ok essayez de nouveau, permet de traiter la collecte des ordures problème à l'aide de références faibles. Traiter avec WeakReferences peut être source de confusion, mais il devrait être suffisant pour l'utilisation d'une carte construite comme suit:
Collections.synchronizedMap(new WeakHashMap<Thread, T>())
Ou si nous sommes à l'aide de Goyave (et on doit!):
new MapMaker().weakKeys().makeMap()
Cela signifie que, une fois personne n'est tenue sur le sujet (ce qui implique qu'il est terminé) la clé/valeur peut être des ordures collectées, ce qui est une amélioration, mais encore ne pas aborder le fil de contention de problème, en ce sens jusqu'à présent notre ThreadLocal
n'est pas étonnant d'une classe. En outre, si quelqu'un a décidé de retenir Thread
objets après qu'ils aient fini, qu'ils n'avaient jamais être GC ed, et par conséquent, ni les objets, même s'ils sont techniquement inaccessible maintenant.
La Mise En Oeuvre Habile
Nous avons réfléchi ThreadLocal
comme une cartographie de threads à des valeurs, mais c'est peut-être pas la bonne façon de penser à ce sujet. Au lieu de penser à cela comme une cartographie à partir de Fils à valeurs dans chaque ThreadLocal un objet, que si nous avons pensé qu'un mappage de ThreadLocal objets de valeurs dans chaque Thread? Si chaque thread magasins de la cartographie, et ThreadLocal fournit simplement une interface agréable dans cette cartographie, on peut éviter tous les problèmes de la implémentations précédentes.
Une mise en œuvre devrait ressembler à quelque chose comme ceci:
// called for each thread, and updated by the ThreadLocal instance
new WeakHashMap<ThreadLocal,T>()
Il n'y a pas besoin de s'inquiéter à propos de la simultanéité ici, parce que seul un thread sera jamais accès à cette carte.
La Java devs ont un grand avantage sur nous, ils peuvent développer directement la classe Thread et ajouter des champs et des opérations, et c'est exactement ce qu'ils ont fait.
En java.lang.Thread
il y a le code suivant:
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
Qui, comme le commentaire suggère est en effet un colis-privé cartographie de toutes les valeurs qui sont suivis par ThreadLocal
objets pour cette Thread
. La mise en œuvre de l' ThreadLocalMap
n'est pas un WeakHashMap
, mais il suit le même contrat de base, y compris la tenue de ses touches par la faiblesse de référence.
ThreadLocal.get()
est ensuite mis en œuvre comme suit:
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
return setInitialValue();
}
Et ThreadLocal.setInitialValue()
comme:
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
Essentiellement, l'utilisation d'une carte dans ce Fil de discussion pour contenir tous nos ThreadLocal
objets. De cette façon, nous n'avons jamais besoin de s'inquiéter à propos de la valeur dans d'autres Threads (ThreadLocal
littéralement ne peut accéder aux valeurs dans le Thread en cours) et donc n'ont pas de problèmes de concurrence. En outre, une fois l' Thread
est fait, sa carte sera automatiquement GC ed et tous les objets locaux seront nettoyés. Même si l' Thread
est maintenu, l' ThreadLocal
objets sont conservés par la faiblesse de référence, et peuvent être nettoyés dès que l' ThreadLocal
objet est hors de portée.
Inutile de dire que j'ai été plutôt impressionné par cette mise en œuvre, assez élégamment obtient autour d'un lot de problèmes de simultanéité (certes en prenant avantage de faire partie du noyau de Java, mais je peux leur pardonner puisque c'est si cool de la classe) et permet d'obtenir rapidement et thread-safe d'accès à des objets qui ne doivent être accessibles que par un seul thread à la fois.
tl;dr ThreadLocal
's la mise en œuvre est assez cool, et beaucoup plus rapide/plus intelligentes que vous pourriez penser au premier coup d'œil.
Thread
/ThreadLocal
code des bribes de Oracle mise en œuvre de Java 7
Je pense que vous faites référence à ThreadLocal?
La source est ici .