Correct use of ThreadLocal in java

  • 2020-06-15 08:56:09
  • OfStack

Correct use of ThreadLocal in java

Usage 1: JDK to create private static ThreadLocalThreaLocal in associated data class ThreadLocal instances are typically private static fields that wish to state a thread If we want to associate a state (such as user ID, transaction ID) with a thread through a class, it is common to define an ThreadLocal instance of type private static in this class.

For example, in the following class, a private static ThreadLocal instance (serialNum) maintains a "sequence number" for each thread that calls the static SerialNum.get () method of the class, which returns the sequence number of the current thread. (The thread's sequence number is assigned on the first call to SerialNum.get () and does not change on subsequent calls.)


public class SerialNum { 
  // The next serial number to be assigned 
  private static int nextSerialNum = 0; 
 
  private static ThreadLocal serialNum = new ThreadLocal() { 
    protected synchronized Object initialValue() { 
      return new Integer(nextSerialNum++); 
    } 
  }; 
 
  public static int get() { 
    return ((Integer) (serialNum.get())).intValue(); 
  } 
} 

[example]


public class ThreadContext {
 
 private String userId;
 private Long transactionId;
 
 private static ThreadLocal threadLocal = new ThreadLocal(){
  @Override
    protected ThreadContext initialValue() {
      return new ThreadContext();
    }
 
 };
 public static ThreadContext get() {
  return threadLocal.get();
 }

 public String getUserId() {
  return userId;
 }
 public void setUserId(String userId) {
  this.userId = userId;
 }
 public Long getTransactionId() {
  return transactionId;
 }
 public void setTransactionId(Long transactionId) {
  this.transactionId = transactionId;
 }
 
}

Usage 2: Create ThreadLocal in the Util class

This is an extension of the above usage, putting the creation of ThreadLocal into a utility class.

For example, hibernate's utility class:


public class HibernateUtil {
  private static Log log = LogFactory.getLog(HibernateUtil.class);
  private static final SessionFactory sessionFactory;   // define SessionFactory
 
  static {
    try {
      //  By default configuration file hibernate.cfg.xml create SessionFactory
      sessionFactory = new Configuration().configure().buildSessionFactory();
    } catch (Throwable ex) {
      log.error(" Initialize the SessionFactory Failure! ", ex);
      throw new ExceptionInInitializerError(ex);
    }
  }

  // Create thread local variables session , used to preserve Hibernate the Session
  public static final ThreadLocal session = new ThreadLocal();
 
  /**
   *  Gets in the current thread Session
   * @return Session
   * @throws HibernateException
   */
  public static Session currentSession() throws HibernateException {
    Session s = (Session) session.get();
    //  if Session If you haven't opened it, open it again 1 a Session
    if (s == null) {
      s = sessionFactory.openSession();
      session.set(s);     // Will the new Session Save to a thread local variable 
    }
    return s;
  }
 
  public static void closeSession() throws HibernateException {
    // Gets a thread local variable and casts to Session type 
    Session s = (Session) session.get();
    session.set(null);
    if (s != null)
      s.close();
  }
}

Usage 3: Create ThreadLocal in Runnable

Another use is to create ThreadLocal inside a thread class, as follows:

1. In a multithreaded class (such as ThreadDemo class), create an ThreadLocal object threadXxx to save the object xxx that needs to be processed in isolation between threads.

2. In the ThreadDemo class, create a method getXxx() to obtain the data to be isolated. Judge in the method that if the ThreadLocal object is null, new() should be an object of isolated access type and cast to the type to be applied.

3. In the run() method of ThreadDemo class, the data to be operated can be obtained by calling the getXxx() method, so that each thread corresponds to one data object, which is operated on at any time.


public class ThreadLocalTest implements Runnable{
  
  ThreadLocal<Studen> studenThreadLocal = new ThreadLocal<Studen>();

  @Override
  public void run() {
    String currentThreadName = Thread.currentThread().getName();
    System.out.println(currentThreadName + " is running...");
    Random random = new Random();
    int age = random.nextInt(100);
    System.out.println(currentThreadName + " is set age: " + age);
    Studen studen = getStudent(); // With this method, each thread is independent new1 a student Object of each thread student Objects can be set to different values 
    studen.setAge(age);
    System.out.println(currentThreadName + " is first get age: " + studen.getAge());
    try {
      Thread.sleep(500);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    System.out.println( currentThreadName + " is second get age: " + studen.getAge());
    
  }
  
  private Studen getStudent() {
    Studen studen = studenThreadLocal.get();
    if (null == studen) {
      studen = new Studen();
      studenThreadLocal.set(studen);
    }
    return studen;
  }

  public static void main(String[] args) {
    ThreadLocalTest t = new ThreadLocalTest();
    Thread t1 = new Thread(t,"Thread A");
    Thread t2 = new Thread(t,"Thread B");
    t1.start();
    t2.start();
  }
  
}

class Studen{
  int age;
  public int getAge() {
    return age;
  }
  public void setAge(int age) {
    this.age = age;
  }
  
}

Thank you for reading, I hope to help you, thank you for your support to this site!


Related articles: