background

ThreadLocal does thread data isolation by default, which in itself avoids data contention. But sometimes you run into data sharing issues, where you need different implementation classes.

Thread data sharing

Utility class

Introduction to the

  1. ThreadLocal

Data is isolated between parent and child threads and the parent thread does not pass a copy of threadLocal to the child thread

  1. InheritatbleThreadLocal

When a child thread is created, a copy of the parent thread threadLocal is passed to the child thread (the reuse thread does not). When a threadLocal is flushed by the main thread, however, the thread pool thread is not recreated, only reused, so the new copy of the threadLocal cannot be passed.

  1. TransmittableThreadLocal

[InheritatbleThreadLocal] [InheritatbleThreadLocal] [InheritatbleThreadLocal] [InheritatbleThreadLocal] [InheritatbleThreadLocal] [InheritatbleThreadLocal]

There is a big hole that must be wrapped in ali’s thread pool utility class!! Otherwise use an InheritatbleThreadLocal effect.

  1. ThreadLocal

private static final ThreadLocal<String> THREAD_LOCAL = new ThreadLocal<>(); ExecutorService executorService = Executors.newFixedThreadPool(10); PostMapping("/threadLocalAndExecutorService") @ResponseBody public Boolean threadLocalAndExecutorService(@RequestBody String tenantId) { THREAD_LOCAL.set(tenantId); for (int i = 0; i < 10; i++) { executorService.submit( ()->{ String content = THREAD_LOCAL.get(); / / can't directly access to the log. The info (" > > > the concurrent flow Thread called {}, {} content for {} ", tenantId, Thread. The currentThread (). The getName (), content); }); } return true; }Copy the code

The output is

The 09:38:35 2021-12-09. 26719-856 the INFO [pool - 6 - thread - 4] C.Y.U.C ontroller. ThreadLocalController: >>> 7 Null 2021-12-09 09:38:35.856 INFO 26719 -- [pool-6-thread-3] C.Y.U.C ontroller. ThreadLocalController: > > > 7 parallel flow thread called pool - 6 - thread - 3, content is nullCopy the code

With ThreadLocal, the parent thread does not pass copies of ThreadLocal to the child thread, so the child thread gets null values.

The child thread here could be

  1. Reuse threads in the thread pool
  2. New thread in parallel stream (the first thread in parallel stream is still the main thread, so get the value)

  1. InheritableThreadLocal

Note: If you have run through the code above, please restart the service (reset the thread pool)

InheritableThreadLocal is used to pass a copy of threadLocal from the parent thread to the child thread when the child thread is created.

However, thread pool reuse is used in production environments, which results in new copies of threadLocal not being put into child threads.

private static final ThreadLocal<String> INHERITABLE_CONTEXT = new InheritableThreadLocal<>(); ExecutorService executorService = Executors.newFixedThreadPool(10); @PostMapping("/inheritableAndExecutor") @ResponseBody public Boolean inheritableAndExecutor(@RequestBody String TenantId) {log.info(" parameters passed in {}",tenantId); INHERITABLE_CONTEXT.set(tenantId); for (int i = 0; i < 10; i++) { executorService.submit( ()->{ String content = INHERITABLE_CONTEXT.get(); / / there will be a series of environmental problems the info (" > > > the incoming flow parallel threads, called {} {}, content is {} \ n ", tenantId, Thread. The currentThread (). The getName (), content); }); } return true; }Copy the code

The output

Pool-6-thread-1 correctly obtains values for the first time.

The 09:41:04 2021-12-09. 27540-851 the INFO [pool - 6 - thread - 1] C.Y.U.C ontroller. ThreadLocalController: >>> 10 parallel stream threads named pool-6-thread-1 are passed with the content of 10Copy the code

However, the pool-6-thread-1 thread does not get a new copy of threadLocal on the second request, which is a limitation of InheritableThreadLocal.

The 09:42:48 2021-12-09. 27540-827 the INFO [pool - 6 - thread - 1] C.Y.U.C ontroller. ThreadLocalController: >>> Pass in 4 parallel stream threads named pool-6-thread-1 with content 10Copy the code

  1. TransmittableThreadLocal

Ali provides a toolkit for passing ThreadLocal values in the case of pooled reusable execution components such as thread pools. Solve the problem of context transfer in asynchronous upload. The thread pool cannot be flushed because threadLocal is flushed.

  1. Implement the class with TransmittableThreadLocal
  2. Use TtlExecutors.GetTtlExecutorService () gets the thread pool
ExecutorService ttlExecutorService = TtlExecutors.getTtlExecutorService(Executors.newFixedThreadPool(10)); private static final ThreadLocal<String> TRANSMITTABLE_THREAD_LOCAL = new TransmittableThreadLocal(); @PostMapping("/ttlAndTtlExecutorService") @ResponseBody public Boolean ttlAndTtlExecutorService(@RequestBody String tenantId) { TRANSMITTABLE_THREAD_LOCAL.set(tenantId); for (int i = 0; i < 10; i++) { ttlExecutorService.submit( ()->{ String content = TRANSMITTABLE_THREAD_LOCAL.get(); / / there is no any problem log. The info (" > > > {} in parallel flows in the TTL Thread called {}, content is {} ", tenantId, Thread. The currentThread () getName (), content); }); } return true; }Copy the code

Note:

If you don’t wrap the class thread pool, for example

  1. Create a thread pool directly
  2. Parallelstreams

With InheritableThreadLocal, data can’t be refreshed when the thread is reusing.

reference

Juejin. Cn/post / 699855…

Github.com/alibaba/tra…