ThreadLocal nous permet de créer des variables privées de thread. Cette variable est invisible pour les autres threads. ThreadLocal crée une copie de la variable dans chaque thread, et chaque thread peut accéder à lui-même aux variables de thread privé, l'exemple de code. est la suivante :
public class ThreadLocalDemo { //创建一个ThreadLocal对象,用来为每个线程会复制保存一份变量,实现线程封闭 private static ThreadLocal<Integer> localNum = new ThreadLocal<Integer>(){ @Override protected Integer initialValue() { return 1; } }; public static void main(String[] args) { //线程0 new Thread(){ @Override public void run() { localNum.set(1); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } localNum.set(localNum.get()+10); System.out.println(Thread.currentThread().getName()+":"+localNum.get());//11 } }.start(); //线程1 new Thread(){ @Override public void run() { localNum.set(3); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } localNum.set(localNum.get()+20); System.out.println(Thread.currentThread().getName()+":"+localNum.get());//23 } }.start(); System.out.println(Thread.currentThread().getName()+":"+localNum.get());//0 } }
Comme mentionné ci-dessus, en comptant le thread principal et les deux threads nouvellement créés, il y a trois threads au total. Chaque thread contient sa propre variable privée. Ici, nous définissons la valeur 1, set() et get(. ) sont utilisées pour définir et obtenir des valeurs. Les résultats de l'exécution sont les suivants :
ThreadLocal est une classe générique qui peut accepter tout type d'objet et maintient une classe interne ThreadLocalMap en interne, les get(), set(), etc. que nous utilisons proviennent en fait de cette classe. Chaque fois qu'un objet ThreadLocalMap est créé pour que le thread actuel enregistre des valeurs privées
Regardons d'abord la méthode set()
public void set(T value) { //拿到当前线程 Thread t = Thread.currentThread(); //拿到当前线程map ThreadLocalMap map = getMap(t); if (map != null) //存在设置值 map.set(this, value); else //不存在则创建 createMap(t, value); }
void createMap(Thread t, T firstValue) { //threadLocals属性即为此map t.threadLocals = new ThreadLocalMap(this, firstValue); }
Ensuite, la méthode get()
public T get() { //拿到当前线程 Thread t = Thread.currentThread(); //拿到当前线程对应的map ThreadLocalMap map = getMap(t); //如果已有map if (map != null) { //取值操作, 拿到对应的Entry ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } //没有map, 则去创建初始化一个map return setInitialValue(); }
private T setInitialValue() { //initialValue()方法返回的value为null T value = initialValue(); //拿到当前线程去创建对应的map Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); return value; }
ThreadLocal peut être comprise comme un package de ThreadLocalMap
Dans ThreadLocalMap, l'objet ThreadLocal utilise des références faibles comme clés
Dans ce cas, si un ThreadLocal cal Lorsqu'il n'y a pas de référence externe forte, alors la clé est destinée à être recyclée par GC, ce qui rend la clé dans ThreadLocalMap nulle et la valeur a toujours une chaîne de référence forte
Un thread peut avoir plusieurs ThreadLocals en même temps time. Si la clé en tant que référence faible est recyclée Après cela, la valeur ne peut pas être recyclée, cela entraînera donc un cycle de vie de ce ThreadLocal aussi long que ce thread (car la chaîne de référence forte de cette valeur ne sera pas rompue). jusqu'à ce que le thread termine son exécution). Si le thread ne se termine jamais, la valeur accumulée n'a pas non plus pu être recyclée, il y aura donc un problème de fuite de mémoire
La façon de résoudre le problème ici est : appelez sa méthode remove(). pour effacer les données à chaque fois après avoir utilisé ThreadLocal
public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this); }
Jetons un coup d'œil ici à la force et à la faiblesse de la clé. La différence entre les références
Si la clé est utilisée comme référence forte, son cycle de vie est aussi long que le fil. Il existe une chaîne de référence forte et stable et ne peut pas être recyclée, provoquant des fuites de mémoire. Si elle est utilisée comme référence faible, le GC la recyclera automatiquement. Ils peuvent également mieux recycler la valeur dans la méthode Remove() suivante, nous concevons donc généralement. ThreadLocal doit être statique privé et utilisez la méthode remove() pour les supprimer manuellement après utilisation
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!