In-depth analysis ThreadLocal memory leaks

  The old routine, first listed on ThreadLocal under common question, hoping to solve these problems through this study notes:
  
  ThreadLocal is to solve any problem?
  
  How to use ThreadLocal?
  
  The principle ThreadLocal what is?
  
  Can a few cases of actual projects using the ThreadLocal?
  
  Basics
  
  ThreadLocal thread-local variables, and different common variables are: Each thread holds a copy of this variable can be modified independently (set method) and access (get method) of this variable, and no conflict between threads .
  
  ThreadLocal instance of a class defined in general will be modified private static, which would allow ThreadLocal instance of state and Thread bound, business, usually with some business ThreadLocal package ID (user ID or transaction ID) - use a different thread the ID is not the same.
  
  How to use
  
  case1
  
  from a certain point of view, ThreadLocal provide additional ideas for concurrent programming in Java - Avoid concurrent, if an object itself is not thread-safe, but you want to achieve the effect of multi-thread synchronization access, such as SimpleDateFormat, you You can use ThreadLocal variable.
  
  class Foo public
  
  {
  
  // the SimpleDateFormat IS Not Thread-Safe, SO One to give each Thread
  
  Final the ThreadLocal static Private <the SimpleDateFormat> = new new Formatter the ThreadLocal <the SimpleDateFormat> () {
  
  @Override
  
  protected the SimpleDateFormat the initialValue ()
  
  {
  
  return new new the SimpleDateFormat ( "yyyyMMdd HHMM");
  
  }
  
  };
  
  public String formatIt (a Date DATE)
  
  {
  
  return formatter.get () .format (DATE);
  
  }
  
  }
  
  Note that this only needs to initialize once SimpleDateFormat objects for each thread, in fact, with the definition of a custom thread SimpleDateFormat member variable, and when the process initializes the new object, the effect is the same , but this seems more regular codes.
  
  case2
  
  time before yunos cool disk for data migration projects, we need to follow users to lock dimensions, each thread before the migration process, you need to obtain the current user locks, each key is with the user information , it can also be achieved using ThreadLocal variables: image.png
  
  Case3
  
  the following example, we define a MyRunnable object, and this object is MyRunnable using threads 1 and 2 thread, but by internal ThreadLocal variable, each thread access to integer They are their own separate copy.
  
  package org.java.learn.concurrent.threadlocal;
  
  /**
  
  * @author duqi
  
  * @createTime 2018-12-29 23:25
  
  **/
  
  public class ThreadLocalExample {
  
  public static class MyRunnable implements Runnable {
  
  private ThreadLocal<Integer> threadLocal =
  
  new ThreadLocal<Integer>();
  
  @Override
  
  public void run() {
  
  threadLocal.set((int) (Math.random() * 100D));
  
  try {
  
  Thread.sleep(2000);
  
  } catch (InterruptedException e) {
  
  }
  
  System.out.println(threadLocal.get());
  
  }
  
  }
  
  public static void main(String[] args) throws InterruptedException {
  
  MyRunnable sharedRunnableInstance = new MyRunnable();
  
  = New new Thread1 the Thread the Thread (sharedRunnableInstance);
  
  the Thread = new new Thread2 the Thread (sharedRunnableInstance);
  
  thread1.start ();
  
  thread2.start ();
  
  thread1.join (www.jinmagjt.com); // for the wait. 1 to Terminate Thread
  
  Thread2 .join (); // the wait for the thread 2 to the Terminate
  
  }
  
  }
  
  ThreadLocal key knowledge
  
  source code analysis
  
  ThreadLocal thread is how it is used? Principle as shown below: Thread ThreadLocal references and references on the stack, references a reference ThreadLocalMap the Thread object, which is a key in the map ThreadLocal objects (using WeakReference package), the service value is the value of the variable. image.png
  
  first look at the code in java.lang.Thread:
  
  public
  
  class the implements the Thread Runnable {
  
  // ...... other source
  
  / * ThreadLocal values pertaining to this thread This map is maintained by the ThreadLocal class * /..
  
  ThreadLocals = null ThreadLocal.ThreadLocalMap;
  
  / *
  
  . * InheritableThreadLocal values pertaining to the this Maintained by the Thread This IS the Map at The InheritableThreadLocal class.
  
  * /
  
  ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
  
  // ...... other source
  
  threadLocals of variables Thread points to a map, the map is ThreadLocal.ThreadLocalMap, which is stored ThreadLocal variable with the current thread binding; inheritableThreadLocals the same effect, which is also stored in ThreadLocal variable, but the store is inherited from the parent thread the current thread the ThreadLocal variable.
  
  Looking java.lang.ThreadLocal class, and the main members of the interfaces are as follows: image.png
  
  withInitial method, Java initialization method after a ThreadLocal 8 for outside calls get () method when the variable will be determined by the Supplier initial value;
  
  public static <S> the ThreadLocal <S> withInitial (Supplier <? S the extends> Supplier) {
  
  return new new SuppliedThreadLocal <www.leyouzaixan.cn> (Supplier);
  
  }
  
  GET method, obtaining a copy of the variable current thread, if the current thread further copy of the variable is not created, it is necessary to set the initial value by calling initialValue method; get method The source code, first obtains the current thread corresponding to the map by the current thread , if the map is not empty, from the map corresponding to the Entry removed, and then the corresponding value taken; if the map is empty, an initial value is set setInitialValue call; if the map is not empty, the current corresponding to Entry ThreadLocal instance is empty, also set an initial value.
  
  T GET public () {
  
  the Thread Thread.currentThread = T ();
  
  ThreadLocalMap the getMap Map = (T);
  
  IF (Map = null!) {
  
  ThreadLocalMap.Entry map.getEntry E = (the this);
  
  IF (! = null E) {
  
  @SuppressWarnings ( "an unchecked" www.tdcqpt.cn)
  
  T Result = (T) e.Value;
  
  return Result;
  
  }
  
  }
  
  return setInitialValue ();
  
  }
  
  SET method, as with the get method, the current thread to acquire the corresponding map, If the map is empty, the call createMap create a map, otherwise the value of the variable into the map - key to the current ThreadLocal objects, value is the value of the variable.
  
  public void set (T value) {
  
  T = Thread.currentThread the Thread ();
  
  ThreadLocalMap the Map = getMap (t);
  
  IF (the Map = null!)
  
  Map.set (the this, value);
  
  the else
  
  CreateMap (t, value);
  
  }
  
  the Remove method to delete the current thread binding this copy of the
  
  public void Remove (www.zzxcscl.com) {
  
  ThreadLocalMap the getMap m = (Thread.currentThread ());
  
  IF (! www.kunLunyuLegw.com m = null)
  
  m.remove (the this);
  
  }
  
  digital 0x61c88647, this value is the value of HASH_INCREMENT, Common hashmap is used to process the list of conflicts, but ThreadLocalMap using a linear method to detect a conflict, HASH_INCREMENT is increased each time the step size, according to said reference 1, this number is selected to let the probability of conflict to a minimum.
  
  / **
  
  * Generated at The -difference the BETWEEN successively hash Codes - turns
  
  * the Implicit Sequential the Thread-local IDs INTO near-optimally in the Spread
  
  Multiplicative hash values for Power *-of-the Tables TWO-sized.
  
  * /
  
  Private static int HASH_INCREMENT Final = 0x61c88647;
  
  parent and child data sharing
  
  InheritableThreadLocal mainly used for child thread is created, you need to automatically inherit parent thread ThreadLocal variables, to achieve sub-thread access threadlocal variable parent thread. InheritableThreadLocal inherited ThreadLocal, and rewrite the childValue, getMap, createMap three methods.
  
  InheritableThreadLocal class public <T> the extends ThreadLocal <T> {
  
  / **
  
  * Create a thread when and if you need to inherit parent thread ThreadLocal variable, you will need a parent thread ThreadLocal variable copied.
  
  * /
  
  Protected childValue T (T http://www.wanxinyulept.com/chaoyue parentValue) {
  
  return parentValue;
  
  }
  
  / **
  
  * Since the getMap rewritten, so when InheritableThreadLocal operating variables, operating only the class Thread inheritableThreadLocals variables, no relation to threadLocals variable
  
  ** /
  
  The getMap ThreadLocalMap (Thread T) {
  
  return t.inheritableThreadLocals;
  
  }
  
  / **
  
  * similar with getMap, set or getInheritableThreadLocal variable, only operate in inheritableThreadLocals Thread class variables
  
  * /
  
  void CreateMap (HTTP Thread: //www.zzhehong .com / Chaoyue /, T firstValue) {
  
  t.inheritableThreadLocals = new new ThreadLocalMap (the this, firstValue);
  
  }
  
  }
  
  on childValue say a few words, is a copy of what happened?
  
  First look Thread.init method,
  
  Private void the init (of ThreadGroup G, the Runnable target, String name, Long the stackSize, the AccessControlContext ACC, Boolean inheritThreadLocals) {
  
  // other source
  
  IF (inheritThreadLocals parent.inheritableThreadLocals &&! = Null)
  
  this.inheritableThreadLocals WWW. zbzxyL12.com =
  
  ThreadLocal.createInheritedMap (parent.inheritableThreadLocals);
  
  / * The Stash Stack size specified in The Case CARES the VM * /
  
  this.stackSize the stackSize =;
  
  / * * the Set ID Thread /
  
  TID = nextThreadID ();
  
  }
  
  then look ThreadLocal.createInheritedMap method, the final will be called to newThreadLocalMap method of childValue InheritableThreadLocal here to do a rewrite, we can see here is indeed the content associated with the parent thread ThreadLocalMap in turn copied to the child in the thread ThreadLocalMap.
  
  ThreadLocalMap Private (ThreadLocalMap parentMap) {
  
  the Entry [] = ParentTable parentMap.table;
  
  int len = parentTable.length;
  
  SetThreshold (len);
  
  Table new new = the Entry [len];
  
  for (int J = 0; J <len; J ++) {
  
  E = ParentTable the Entry [J];
  
  IF (E = null!) {
  
  @SuppressWarnings ( "an unchecked")
  
  The ThreadLocal <Object> = Key (the ThreadLocal <Object>) e.get ();
  
  IF (Key = null!) {
  
  Object value = key.childValue (e.Value);
  
  the Entry new new C = the Entry (Key, value);
  
  int & key.threadLocalHashCode = H (len -. 1);
  
  the while (! Table [H] = null)
  
  H = nextIndex (H, len);
  
  Table [H] = C;
  
  size ++;
  
  }
  
  }
  
  }
  
  }
  
  the ThreadLocal when the object was recovered ?
  
  ThreadLocalMap The key is ThreadLocal object, and then ThreadLocal object is WeakReference packaged, so that when there is no strong reference point after the ThreadLocal object or Map of ThreadLocal object is determined to be weak reference unreachable, garbage collection will be in It was recovered off. Look Entry Definition:
  
  static class Entry WeakReference the extends <ThreadLocal <>> {?
  
  / ** Associated with the this ThreadLocal at The value * /.
  
  Object value;
  
  The Entry (ThreadLocal K, V Object <?>) {
  
  Super (K);
  
  value = V;
  
  }
  
  }
  
  used with ThreadLocal and thread pools?
  
  Lifecycle ThreadLocal object like a thread of life cycle is long, so if used together ThreadLocal object and the thread pool, you may encounter this situation: ThreadLocal object is a thread will ThreadLocal objects and other threads of string out, generally do not recommended to use both together.
  
  Case study
  
  Dubbo use in the ThreadLocal
  
  I found from Dubbo ThreadLocal example, which is mainly used in the request cache scene, specific code as follows:
  
  @Activate (Group = {Constants.CONSUMER, Constants.PROVIDER}, value = the Constants .CACHE_KEY)
  
  public class CacheFilter the implements the Filter {
  
  Private the CacheFactory CacheFactory;
  
  public void setCacheFactory (the CacheFactory CacheFactory) {
  
  this.cacheFactory = CacheFactory;
  
  }
  
  @Override
  
  public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
  
  if (cacheFactory != null && ConfigUtils.isNotEmpty(invoker.getUrl().getMethodParameter(invocation.getMethodName(), Constants.CACHE_KEY))) {
  
  Cache cache = cacheFactory.getCache(invoker.getUrl(), invocation);
  
  if (cache != null) {
  
  String key = StringUtils.toArgumentString(invocation.getArguments());
  
  Object value = cache.get(key);
  
  if (value != null) {
  
  if (value instanceof ValueWrapper) {
  
  return new RpcResult(((ValueWrapper)value).get());
  
  } else {
  
  return new RpcResult(value);
  
  }
  
  }
  
  Result result = invoker.invoke(invocation);
  
  if (!result.hasException()) {
  
  cache.put (Key, new new ValueWrapper (result.getValue ()));
  
  }
  
  return Result;
  
  }
  
  }
  
  return invoker.invoke (Invocation);
  
  }
  
  can be seen in the RPC call (Invoke) link, will first use request parameter to determine whether the current thread has just been launched by invoking the same argument - this call will be used ThreadLocalCache saved. Specifically see, ThreadLocalCache implemented as follows:
  
  Package org.apache.dubbo.cache.support.threadlocal;
  
  Import org.apache.dubbo.cache.Cache;
  
  Import org.apache.dubbo.common.URL;
  
  Import the java.util.HashMap ;
  
  Import a java.util.Map;
  
  / **
  
  * ThreadLocalCache
  
  * /
  
  public class ThreadLocalCache the implements the Cache {
  
  // the ThreadLocal is stored in the result parameter to the mapping of
  
  private final ThreadLocal <map <Object, Object >> store;
  
  ThreadLocalCache public (the URL URL) {
  
  this.store the ThreadLocal new new = <the Map <Object, Object >> () {
  
  @Override
  
  protected the Map <Object, Object> the initialValue () {
  
  return new new the HashMap <Object, Object> ();
  
  }
  
  } ;
  
  }
  
  @Override
  
  public void PUT (Object Key, Object value) {
  
  store.get () PUT (Key, value);.
  
  }
  
  @Override
  
  public GET Object (Object Key) {
  
  return store.get () GET (Key). ;
  
  }
  
  }
  
  RocketMQ
  
  in RocketMQ I also found ThreadLocal figure, it is used in a scene message sent, MQClientAPIImpl is RMQ responsible to send messages to implement the service end, wherein there is a step necessary to select a particular queue, selected when a specific queue, a different thread has its own index value responsible ThreadLocal mechanism used here, can look to achieve ThreadLocalIndex of:
  
  Package Penalty for org.apache.rocketmq.client.common;
  
  import java.util.Random;
  
  public class ThreadLocalIndex {
  
  private final ThreadLocal<Integer> threadLocalIndex = new ThreadLocal<Integer>();
  
  private final Random random = new Random();
  
  public int getAndIncrement() {
  
  Integer index = this.threadLocalIndex.get();
  
  if (null == index) {
  
  index = Math.abs(random.nextInt());
  
  if (index < 0)
  
  index = 0;
  
  this.threadLocalIndex.set(index);
  
  }
  
  index = Math.abs(index + 1);
  
  if (index < 0)
  
  index = 0;
  
  this.threadLocalIndex.set(index);
  
  return index;
  
  }
  
  @Override
  
  public String toString() {
  
  return "ThreadLocalIndex{" +
  
  "threadLocalIndex =" + threadLocalIndex.get () +
  
  '}';
  
  }
  
  }
  
  summary
  
  This article is resolved several issues regarding the ThreadLocal: (1) the specific concept is what? (2) the use of Java in the development of what the scene? The principle (3) ThreadLocal is like? (4) open source projects in which case you can refer to? I do not know whether these few questions you have some understanding of it? If you have questions, please exchange.
  
  References
  
  Why 0x61c88647?
  
  Java ThreadLocal
  
  the When and How Should the I use A ThreadLocal variable?
  
  Technical dark room: Understanding Java's ThreadLocal in
  
  -depth analysis of ThreadLocal memory leaks
  
  "Java Concurrency in combat"
  
  InheritableThreadLocal Detailed
  
  ThreadLocal Detailed
  
  use ThreadLocal scene
  
  data structures : hash table

Guess you like

Origin www.cnblogs.com/qwangxiao/p/11222917.html