Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to use ThreadLocal in Java

2025-02-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article is about how to use ThreadLocal in Java. The editor thinks it is very practical, so share it with you as a reference and follow the editor to have a look.

Introduction

The official API of ThreadLocal is interpreted as:

"this class provides thread thread-local variables. These variables are different from their normal counterparts because each thread that accesses a variable (through its get or set method) has its own local variable, which is independent of the initialization copy of the variable. ThreadLocal instances are usually private static fields in a class that want to associate state with a thread (for example, user ID or transaction ID)."

There are two general meanings:

ThreadLocal provides a special way to access a variable: the accessed variable belongs to the current thread, that is, it ensures that the variable of each thread is different, while the same thread gets the same variable everywhere, which is called thread isolation.

If you want to use ThreadLocal, it is usually defined as the private static type, and in my opinion * * is defined as the private static final type.

Application scenario

ThreadLocal is usually used to share data. When you want to use a variable in multiple methods, this variable is the state of the current thread, and other threads do not rely on this variable. All you can think of in your time is to define the variable inside the method, and then pass parameters between methods to use. This method can solve the problem, but the annoying thing is that each method needs to declare formal parameters, multiple declarations. Multiple calls. Affect the beauty and maintenance of the code. Is there a way to access variables in the form of private static? This can be used anywhere in the class. At this time, ThreadLocal showed his skills.

Practice

Let's first look at a piece of code:

Mport java.util.HashMap; import java.util.Map; public class TreadLocalTest {/ / static ThreadLocal threadLocal = new ThreadLocal () {/ / @ Override / / protected HashMap initialValue () {/ / System.out.println (Thread.currentThread (). GetName () + "initialValue"); / / return new HashMap (); / /} / /}; public static class T1 implements Runnable {private final static Map map = new HashMap (); int id; public T1 (int id) {this.id = id } public void run () {/ / Map map = threadLocal.get (); for (int I = 0; I

< 20; i++) { map.put(i, i + id * 100); try { Thread.sleep(100); } catch (Exception ex) { } } System.out.println(Thread.currentThread().getName() + "# map.size()=" + map.size() + " # " + map); } } public static void main(String[] args) { Thread[] runs = new Thread[15]; T1 t = new T1(1); for (int i = 0; i < runs.length; i++) { runs[i] = new Thread(t); } for (int i = 0; i < runs.length; i++) { runs[i].start(); } } } 这段程序的本意是,启动15个线程,线程向map中写入20个整型值,然后输出map。运行该程序,观察结果,我们会发现,map中压根就不止20个元素,这说明程序产生了线程安全问题。 我们都知道HashMap是非线程安全的,程序启动了15个线程,他们共享了同一个map,15个线程都往map写对象,这势必引起线程安全问题。 我们有两种方法解决这个问题: 将map的声明放到run方法中,这样map就成了方法内部变量,每个线程都有一份new HashMap(),无论多少个线程执行run方法,都不会有线程安全问题。这个方法也正如应用场景中提到的,如果有多处地方使用到map,传值是个烦人的地方。 将HashMap换成Hashtable。用线程同步来解决问题,然而我们的程序只是想向一个map中写入20个整型的KEY-VALUE而已,并不需要线程同步,同步势必影响性能,得不偿失。 ThreadLocal提供另外一种解决方案,即在解决方案a上边,将new HashMap()得到的实例变量,绑定到当前线程中。之后从任何地方,都可以通过ThreadLocal获取到该变量。将程序中的注释代码恢复,再将 private final static Map map = new HashMap();注释掉,运行程序,结果就是我们想要的。 实现原理 程序调用了get()方法,我们来看一下该方法的源码: 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(); } getMap方法的源码: ThreadLocalMap getMap(Thread t) { return t.threadLocals; } 该方法返回的是当前线程中的ThreadLocalMap实例。阅读Thread的源码我们发现Thread中有如下变量声明: /* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ ThreadLocal.ThreadLocalMap threadLocals = null; 我们暂时可以将ThreadLocalMap理解为一个类似Map的这么个类,之后再讲解它。 get()方法的大致意思就是从当前线程中拿到ThreadLocalMap的实例threadLocals,如果threadLocals不为 空,那么就以当前ThreadLocal实例为KEY从threadLocals中拿到对应的VALUE。如果不为空,那么就调用 setInitialValue()方法初始化threadLocals,最终返回的是initialValue()方法的返回值。下面是 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; } 我们看到map.set(this, value);这句代码将ThreadLocalMap的实例作为KEY,将initialValue()的返回值作为VALUE,set到了threadLocals中。 程序在声明ThreadLocal实例的时候覆写了initialValue(),返回了VALUE,当然我们可以直接调用set(T t)方法来设置VALUE。下面是set(T t)方法的源码: public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); } 我们看到它比setInitialValue()方法就少了个return语句。这两种方式都能达到初始化ThreadLocalMap实例的效果。 我们再来看一下ThreadLocal类的结构。 ThreadLocal类只有三个属性,如下: /*ThreadLocal的hash值,map用它来存储值*/ private final int threadLocalHashCode = nextHashCode(); /*改类能以原子的方式更新int值,这里主要是在产生新的ThreadLocal实例时用来产生一个新的hash值,map用该值来存储对象*/ private static AtomicInteger nextHashCode = new AtomicInteger(); /*该变量标识每次产生新的ThreadLocal实例时,hash值的增量*/ private static final int HASH_INCREMENT = 0x61c88647; 剩下的就是一些方法。最关键的地方就是ThreadLocal定义了一个静态内部类ThreadLocalMap。我们在下一章节再来分析这个类。 从ThreadLocal的类结构,我们可以看到,实际上问题的关键先生是ThreadLocalMap,ThreadLocal只是提供了管理的功能, 我们也可以说ThreadLocal只是代理了ThreadLocalMap而已。 ThreadLocalMap源码分析 既然ThreadLocalMap实现了类似map的功能,那我们首先来看看它的set方法源码: private void set(ThreadLocal key, Object value) { // We don’t use a fast path as with get() because it is at // least as common to use set() to create new entries as // it is to replace existing ones, in which case, a fast // path would fail more often than not. Entry[] tab = table; int len = tab.length; 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); return; } } tab[i] = new Entry(key, value); int sz = ++size; if (!cleanSomeSlots(i, sz) && sz >

= threshold) rehash ();}

The main function of this method is to store KEY-VALUE in ThreadLocalMap. At least we can see that KEY is actually key.threadLocalHashCode,ThreadLocalMap and also maintains the Entry array, which we will talk about in the next section. This involves the handling of Hash conflicts, which are not added in the form of a linked list like HashMap. If you are interested in this Hash conflict resolution, you can further study the source code.

Since ThreadLocalMap also uses Entry to store objects, let's take a look at the declaration of the Entry class. Entry is defined inside ThreadLocalMap:

Static class Entry extends WeakReference {/ * * The value associated with this ThreadLocal. * / Object value; Entry (ThreadLocal k, Object v) {super (k); value = v;}}

Here we see that Entry integrates the WeakReference class, and generics declare ThreadLocal, that is, every Entry object retains a weak reference to the ThreadLocal instance because the thread needs to remove the ThreadLocal instance from the map after the thread finishes in order to reclaim memory space.

Summary

First of all, ThreadLocalMap is not intended to solve thread safety problems, but provides a mechanism for binding instances to the current thread, similar to the effect of isolation. In fact, new variables in the method can achieve a similar effect. ThreadLocalMap basically has nothing to do with thread safety, and the bound instance is not common to multiple threads, but a share of new for each thread. This instance is definitely not shared. If it is shared, it will cause thread safety problems. The purpose of ThreadLocalMap*** is to share instance variables as global variables, which can be accessed in any method of the program. Many people on the Internet say that ThreadLocalMap solves the problem of thread safety, but in fact, it is literal, and the two are not similar problems.

Thank you for reading! This is the end of the article on "how to use ThreadLocal in Java". I hope the above content can be of some help to you, so that you can learn more knowledge. if you think the article is good, you can share it for more people to see!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report