Java class ThreadLocal

  • 2020-05-07 19:43:32
  • OfStack

The ThreadLocal class represents one thread-local variable, and by putting the data in ThreadLocal, you can have each thread create one copy of that variable. It can also be seen as another way to synchronize threads, by creating a thread-local copy of one variable for each thread to avoid conflicts when concurrent threads simultaneously read and write to the same variable resource.

Here's an example:


import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import com.sun.javafx.webkit.Accessor;

public class ThreadLocalTest {
 static class ThreadLocalVariableHolder {
  private static ThreadLocal<Integer> value = new ThreadLocal<Integer>() {
   private Random random = new Random();
   
   protected synchronized Integer initialValue() {
    return random.nextInt(10000);
   }
  };
  
  public static void increment() {
   value.set(value.get() + 1);
  }
  
  public static int get() {
   return value.get();
  }
 }
 
 static class Accessor implements Runnable{
  private final int id;
  
  public Accessor(int id) {
   this.id = id;
  }
  
  @Override
  public void run() {
   while (!Thread.currentThread().isInterrupted()) {
    ThreadLocalVariableHolder.increment();
    System.out.println(this);
    Thread.yield();
   }
  }
  
  @Override
  public String toString() {
   return "#" + id + ": " + ThreadLocalVariableHolder.get();
  }
  
 }
 
 public static void main(String[] args) {
  ExecutorService executorService = Executors.newCachedThreadPool();
  for (int i = 0; i < 5; i++) {
   executorService.execute(new Accessor(i));
  }
  try {
   TimeUnit.MICROSECONDS.sleep(1);
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
  executorService.shutdownNow();
 }

}

Operation results:


#1: 9685
#1: 9686
#2: 138
#2: 139
#2: 140
#2: 141
#0: 5255
 . 

From the results of the run, it can be seen that each thread is used for its own Local variable, and each reads and writes without interference.

ThreadLocal provides three methods to operate, set,get, and remove.

In Android, Looper USES ThreadLocal to create separate Looper objects for each thread.


public final class Looper {
 private static final String TAG = "Looper";

 // sThreadLocal.get() will return null unless you've called prepare().
 static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

 private static void prepare(boolean quitAllowed) {
  if (sThreadLocal.get() != null) {
   throw new RuntimeException("Only one Looper may be created per thread");
  }
  sThreadLocal.set(new Looper(quitAllowed));
 }
 
  . 
}

When a thread needs its own Looper and message queue, Looper.prepare () is called. Looper.prepare () creates an Looper object and MessageQueue belonging to the thread, and stores the Looper object in ThreadLocal.


Related articles: