In addition to controlling access to resources, we can add resources to keep all objects thread-safe. For example, if you ask 100 people to fill out a personal information form, if there is only one pen, then everyone has to fill it out one by one. For the management, it is important to ensure that people do not scramble for the only pen left, otherwise, no one can fill it out. On the other hand, let’s just have 100 pens, one for each of us, and everyone can fill out the form quickly.

If locks take the first approach, ThreadLocal takes the second.

Simple use of ThreadLocal

public class ThreadLocalDemo {

    private static final ThreadLocal<SimpleDateFormat> tl = new ThreadLocal<>();

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 10000; i++) {
            executorService.execute(new ParseDate(i));
        }
        executorService.shutdown();
    }

    static class ParseDate implements Runnable {

        int i = 0;

        public ParseDate(int i) {
            this.i = i;
        }

        @Override
        public void run(a) {
            try {
                / / 1
                if (tl.get() == null) {
                    tl.set(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
                }
                Date date = tl.get().parse("The 2020-06-28 now." + i % 60);
                System.out.println(i+ ":" + date);
            } catch(ParseException e) { e.printStackTrace(); }}}}Copy the code

Simpledateformat.parse () is not thread-safe, and we use ThreadLocal to generate an instance of the SimpleDateFormat object for each thread.

Comment 1 determines if the current thread does not hold an instance of the SimpleDateFormat object. Create a new one and set it to the current thread, or use it if it already exists. As you can see, the task of assigning an object to each thread hand is not done by ThreadLocal, but is ensured at the application level. ThreadLocal is also not thread-safe if the same object instance is assigned to every thread in the application.

Assigning different objects to each thread needs to be ensured at the application level. ThreadLocal acts as a simple container.

How ThreadLocal works

The ThreadLocal methods are set() and get().

public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if(map ! =null)
        map.set(this, value);
    else
        createMap(t, value);
}
Copy the code

On set, we first get the current thread object, then get the thread’s ThreadLocalMap via getMap() and set the value to ThreadLocalMap.

public T get(a) {
    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;
            returnresult; }}return setInitialValue();
}
Copy the code

On GET, the ThreadLocalMap object is first obtained. It then uses itself as the key to get the actual data inside.

When using ThreadLocal, the maintained variables are maintained in the ThreadLocalMap inside the Thread class, which means that references to objects persist as long as the Thread does not exit.

So if we use a thread pool, that means the current thread may not exit. If so, setting some large objects into ThreadLocal could expose the system to the possibility of memory leaks.

At this point, if you want to recycle objects in a timely manner, it is best to use the threadlocal.remove () method to remove the variable. Just as we routinely close database connections. If you do not need the object, you should tell the virtual machine to reclaim it to prevent memory leaks.

static class Entry extends WeakReference<ThreadLocal<? >>{
    /** The value associated with this ThreadLocal. */Object value; Entry(ThreadLocal<? > k, Object v) {super(k); value = v; }}Copy the code

A ThreadLocalMap is similar to a Map where the key is the this weak reference to the ThreadLocal variable currently defined and the value is the value we set using the set method.