The cause of

Recently, when I was working on a project team, I saw the following comment while browsing someone else’s code.

When I first saw it, I didn’t know why it said so. When my colleague explained the reason to me, it suddenly became clear. Come to think of it, we can easily ignore this problem if we don’t pay attention to it in our work. Before explaining this, let’s look at ThreadLocal.

ThreadLocal

ThreadLocal provides thread-local variables, creating separate copies of variables for each thread. In a multi-threaded environment, since each thread has a separate variable, there is no concurrency problem caused by variable sharing. Of course, we can use the synchronization mechanism to solve the problem.

Synchronization is different from ThreadLocal

Using synchronization mechanism, multi-threaded environment shares the same variable, which requires us to display lock when using, to ensure that the variable can be used by only one thread at the same time, which is equivalent to adopting time policy for thread safety.

With ThreadLocal, each thread has its own independent copy of variables, which is equivalent to using a spatial policy in exchange for thread safety.

Let’s look at the differences between the two approaches in code. Now suppose we need the current time tool class as follows:

    private final static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public static String getDateStr(Date date) {
        return format.format(date);
    }
Copy the code

Looking at the Demo above, we can easily see that the getDateStr method is not thread-safe because SimpleDateFormat is not thread-safe.

Now we modify it using synchronization.

    private final static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public static synchronized String getDateStrSync(Date date) {
        return format.format(date);
    }
Copy the code

This uses display locking to avoid thread safety in multi-threaded environments. However, this approach can affect efficiency in high concurrency situations.

Let’s transform it using ThreadLocal.

    private final static ThreadLocal<SimpleDateFormat> formatLocal = new ThreadLocal<SimpleDateFormat>() {
        protected synchronized SimpleDateFormat initialValue(a) {
            return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); }};public static String getDateByLocal(Date date){
        return formatLocal.get().format(date);
    }
Copy the code

Use ThreadLocal to make shared variables proprietary and thread-safe. But this scheme increases the overhead of creating objects.

To sum up, how to choose the above two modes must be based on the current service mode.

With ThreadLocal out of the way, let’s look at Dubbo’s threading model.

Dubbo thread model

Dubbo handles calls in a single long connection plus thread pool by default.

By default, Dispatcher=all dispatches are sent to the thread pool, including requests, responses, connection events, disconnection events, heartbeats, etc. Thread pool is a fixed size thread pool by default. Threads are created at startup, not closed, and are always held. The default is 100 threads.

Analyze using ThreadLocal in Dubbo

With ThreadLocal in Dubbo, if the default Settings are used, the Dubbo processing response thread is not destroyed at the end of each Dubbo call, but is returned to the thread pool. As you can see from the ThreadLocal source code, each time we set the value, it will actually be stored in the ThreadLocalMap variable in the Thread.

As a result, the next time the Dubbo processing response happens to continue using this thread, the thread will be able to invoke the same value that was set in ThreadLocal in the last response. This can cause memory leaks and possibly business exceptions. Not only in Dubbo, but also in Web projects that use thread pools.

Threadlocal summary

Using Threadlocal, we need to note a few things:

  1. Using a Threadlocal requires the same thing as using a related stream, calling its remove method last to clear its Settings and prevent memory leaks.
  2. You can’t use Threadlocal to pass every parameter up and down a method, which would cause invisible coupling, and the code is not easy to maintain.
  3. In high concurrency, we can use Threadlocal instead of synchronous locks to improve performance.

Refer to the link

  1. Deep dive into ThreadLocal
  2. Talk about thread safety in Spring
  3. Gracefully use ThreadLocal to pass parameters
  4. www.baeldung.com/java-thread…
  5. www.cnblogs.com/youzhibing/…
  6. Dubbo thread model
  7. How to shoot yourself in foot with ThreadLocals

If you feel good, please give the author a thumbs up ~ thank you

To those who like this article, please click on our subscription number and let me share with you about our app.