This post is part of the third session of the Nuggets Creators Training Camp.Digg project | Creator Boot Camp phase 3 is underway, “write” to make a personal impact.


πŸ“– preface

Today I’m going to share with you Java (Essential for an interview) : During an interviewThreadLocalPrinciple and use scenarios, do not like spray, if there are objections welcome to discuss!

I’m sure you’ve been asked this question a lot in job interviewsThreadLocalAlthough I have always known the existence of this thing, I have not thoroughly studied the principle and do not have my own knowledge system. Today’s Amway wave needs to be improved


πŸš€ThreadLocalWhat is the

ThreadLocal 是 JDK java.langA tool for implementing isolation of data from different threads shared by the same thread. JDK source code

The ThreadLocal class provides thread-local variables, which differ from normal variables in that each thread accessing the variable has a separate initialized copy inside it; ThreadLocal instance variables are usually decorated in classes using private static.

Each thread holds a copy of the ThreadLocal variable as long as it can be accessed and the thread is alive. When a thread terminates, all copies of ThreadLocal instances it holds can be reclaimed.

In a wordThreadLocalThis applies to scenarios where each thread needs its own independent instance and that instance needs to be used in multiple methods (same thread data sharing), that is, variables are isolated between threads (data isolation between different threads) and shared between methods or classes.


✨ThreadLocaluse

 package com.test;

import java.util.concurrent.CountDownLatch;

/**
 * 
 * @Description: ζˆ‘ηš„ζ΅‹θ―•η±»
 * @ClassName: MyDemo.java
 * @author ChenYongJia
 * @Date 2019εΉ΄4月17ζ—₯ ζ™šδΈŠ23:25
 * @Email [email protected]
 */
public class MyDemo {

	private String string;

	private String getString() {
		return string;
	}

	private void setString(String string) {
		this.string = string;
	}

	public static void main(String[] args) {
		int threads = 9;
		MyDemo demo = new MyDemo();
		CountDownLatch countDownLatch = new CountDownLatch(threads);
		for (int i = 0; i < threads; i++) {
			Thread thread = new Thread(() -> {
				demo.setString(Thread.currentThread().getName());
				System.out.println("demo.getString()================>" + demo.getString());
				countDownLatch.countDown();
			}, "ζ‰§θ‘ŒηΊΏη¨‹ - " + i);
			thread.start();
		}

	}

}
Copy the code

Console output

Demo. Get string () = = = = = = = = = = = = = = = = > executing thread - 0 demo. Get string () = = = = = = = = = = = = = = = = > thread of execution Demo. Get string () = = = = = = = = = = = = = = = = > executing thread - 2 demo. Get string () = = = = = = = = = = = = = = = = > thread of execution Demo. Get string () = = = = = = = = = = = = = = = = > executing thread - 4 demo. Get string () = = = = = = = = = = = = = = = = > thread of execution The demo. Get string () = = = = = = = = = = = = = = = = > executing thread - 7 demo. Get string () = = = = = = = = = = = = = = = = > thread of execution - 5 Demo.getstring ()================> Thread of execution -8Copy the code

The result shows that there are exceptions when multiple threads access the same variable. Data between threads is not isolated. Now let’s look at adoptionThreadLocalExamples of variable ways to solve this problem.

package com.test; import java.util.concurrent.CountDownLatch; /** ** @description: My test class * @className: Mythreadlocaldemo. Java * @author ChenYongJia * @date April 17, 2019 23:28 PM * @email [email protected] */ public class MyThreadLocalDemo { private static ThreadLocal<String> threadLocal = new ThreadLocal<>(); private String getString() { return threadLocal.get(); } private void setString(String string) { threadLocal.set(string); } public static void main(String[] args) { int threads = 9; MyThreadLocalDemo demo = new MyThreadLocalDemo(); CountDownLatch countDownLatch = new CountDownLatch(threads); for (int i = 0; i < threads; i++) { Thread thread = new Thread(() -> { demo.setString(Thread.currentThread().getName()); System.out.println("demo.getString()================>" + demo.getString()); countDownLatch.countDown(); }, "thread of execution -" + I); thread.start(); }}}Copy the code

Console output

Demo. Get string () = = = = = = = = = = = = = = = = > executing thread - 0 demo. Get string () = = = = = = = = = = = = = = = = > thread of execution Demo. Get string () = = = = = = = = = = = = = = = = > executing thread - 4 demo. Get string () = = = = = = = = = = = = = = = = > thread of execution The demo. Get string () = = = = = = = = = = = = = = = = > executing thread - 2 demo. Get string () = = = = = = = = = = = = = = = = > thread of execution - 7 Demo. Get string () = = = = = = = = = = = = = = = = > executing thread - 5 demo. Get string () = = = = = = = = = = = = = = = = > thread of execution - 8 Demo.getstring ()================> Thread of execution - 6Copy the code

As a result, this is a very convenient solution to the problem of data isolation between multiple threads.

Some of you might think that in example 1 we could have done this by locking. Yes, locking can solve this problem, but here we emphasize the problem of thread data isolation, not the problem of multithreading data sharing. If there are many other methods that use this String besides getString(), then there is no explicit data passing between the methods and they can be retrieved directly from the ThreadLocal variable, which is the core of ThreadLocal. The same thread data shares different thread data isolation.

Due to theThreadLocalGenerics are supported, so here we’re going to store oneStringTo demonstrate, in fact, can store any type, the effect is the same.


🐱 🏍ThreadLocalSource code analysis

One thing we know before we analyze the source code is that object instances andThreadLocalVariables are mapped by threadThreadTo maintain object instances andThreadLocalVariables are mapped by threadThreadTo maintain object instances andThreadLocalVariables are mapped by threadThreadTo maintain. It’s so important that it should be repeated for three times.

It’s just an object instance andThreadLocalThe mapping of variables is the one storedMapInside (thisMapIt’s abstractMapIs notjava.utilIn theMap), and thisMap 是 ThreadClass a field! And the ones that actually store the mappingsMapisThreadLocalMap. Let’s look at the concrete implementation through several methods of the source code.

Public void set(T) {Thread T = thread.currentThread (); ThreadLocalMap map = getMap(t); if (map ! = null) map.set(this, value); else createMap(t, value); } // Get the ThreadLocalMap field in the thread!! ThreadLocalMap getMap(Thread t) { return t.threadLocals; } void createMap(Thread t, t firstValue) {t.htreadlocals = new ThreadLocalMap(this, firstValue); }Copy the code

insetMethod to get the current thread, and then passgetMapOf the current threadThreadLocalMapType variablethreadLocals, if it exists, it is directly assigned, if it does not exist, it is created for the threadThreadLocalMapVariable and assign. That’s where it was assignedthisIs the instance of the object calling the variable itself.

public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map ! = null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e ! = null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); } 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; }Copy the code

getThe method is also relatively simple, is also the first to get the current threadThreadLocalMapVariable that returns a value if it exists and creates and returns an initial value if it does not.


🎢ThreadLocalMapSource code analysis

ThreadLocalThe underlying implementation is all throughThreadLocalMapSo let’s seeThreadLocalMapAnd then look at the correspondingset ε’Œ getMethods.

static class ThreadLocalMap { /** * The entries in this hash map extend WeakReference, using * its main ref field as the key (which is always a * ThreadLocal object). Note that null keys (i.e. entry.get() * == null) mean that the key is no longer referenced, so the * entry can be expunged from table. Such entries are referred to * as "stale entries" in the code that follows. */ static class Entry extends WeakReference<ThreadLocal<? >> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<? > k, Object v) { super(k); value = v; } } /** * The table, resized as necessary. * table.length MUST always be a power of two. */ private Entry[] table; }Copy the code

ThreadLocalMapThe use ofEntry[]Array to store the relationship between object instances and variables, and instance objects askey, variable asvalueImplement correspondence. And herekeyA weak reference to the instance object is used, (because ourkeyIs an object instance, each object instance has its own life cycle, here using weak reference can be referenced without affecting the life cycle of the object instance.

private void set(ThreadLocal<? > key, Object value) { Entry[] tab = table; int len = tab.length; Int I = key.threadLocalHashCode & (len-1); // Get the hash value for the subscript int I = key.threadLocalHashCode & (len-1); For (Entry e = TAB [I]; e ! = null; e = tab[i = nextIndex(i, len)]) { ThreadLocal<? > k = e.get(); If (k == key) {e.value = value; return; If (k == null) {replaceStaleEntry(key, value, I); if (k == null) {replaceStaleEntry(key, value, I); return; TAB [I] = new Entry(key, value); int sz = ++size; if (! cleanSomeSlots(i, sz) && sz >= threshold) rehash(); } private Entry getEntry(ThreadLocal<? > key) { int i = key.threadLocalHashCode & (table.length - 1); Entry e = table[i]; if (e ! = null && e.get() == key) return e; else return getEntryAfterMiss(key, i, e); }Copy the code

After reading the JDK source code related to ThreadLocal, I also have a certain understanding, and I hope to help you. *


Java: In the interviewThreadLocalPrinciple and use scenarios, share the end, go to try it!


πŸŽ‰ finally

  • You can use this to hold Connection objects while processing transactions at the Service layer.

  • For more references, see here:The Blog of Chan Wing Kai

  • Like the small partner of the blogger can add a concern, a thumbs-up oh, continue to update hey hey!