45 Is Thread Local Used to Solve the Problem of Multi Threaded Access to Shared Resources

45 Is ThreadLocal Used to Solve the Problem of Multi-threaded Access to Shared Resources #

This lesson mainly discusses a question: Is ThreadLocal used to solve the problem of multiple-thread access to shared resources?

This is a common interview question. If you are asked about ThreadLocal, it may follow up with the question: Is ThreadLocal used to solve the problem of multiple-thread access to shared resources? If you encounter such a question, you need to have a clear understanding. Here is a reference answer.

How to answer when asked during an interview #

The answer to this question is clear - no, ThreadLocal is not used to solve the problem of shared resources. Although ThreadLocal can indeed be used to solve the thread safety issue in a multi-threaded scenario, the resources are not shared, but rather unique to each thread. So, this question actually has a certain trap element.

When ThreadLocal is used to solve thread safety issues, it takes a different approach compared to using locks. It makes the resources unique to each thread and cleverly avoids synchronization operations. Specifically, it can create thread-specific resources in the initialValue method. The objects accessed by multiple threads are not shared, so there are no concurrency issues. This is the main idea behind ThreadLocal in solving concurrency problems.

If we make the resource placed in ThreadLocal static, making it a shared resource, even if ThreadLocal is used, there will still be thread safety issues. For example, if we modify the example in Lesson 44 and use the static keyword to modify SimpleDateFormat, and store this static object in ThreadLocal, the code would be like this:

public class ThreadLocalStatic {

    public static ExecutorService threadPool = Executors.newFixedThreadPool(16);

    static SimpleDateFormat dateFormat = new SimpleDateFormat("mm:ss");

    public static void main(String[] args) throws InterruptedException {

        for (int i = 0; i < 1000; i++) {

            int finalI = i;

            threadPool.submit(new Runnable() {

                @Override

                public void run() {

                    String date = new ThreadLocalStatic().date(finalI);

                    System.out.println(date);

                }

            });

        }

        threadPool.shutdown();

    }

    public String date(int seconds) {

        Date date = new Date(1000 * seconds);

        SimpleDateFormat dateFormat = ThreadSafeFormatter.dateFormatThreadLocal.get();

        return dateFormat.format(date);

    }

}

class ThreadSafeFormatter {

    public static ThreadLocal<SimpleDateFormat> dateFormatThreadLocal = new ThreadLocal<SimpleDateFormat>() {

        @Override

        protected SimpleDateFormat initialValue() {

            return ThreadLocalStatic.dateFormat;

        }

    }

}

In this case, when this resource is accessed and used in multiple threads, there will also be a problem of duplicate time, resulting in thread safety issues. This means that if the object we need to place in ThreadLocal is shared and has the static modifier, then we actually do not need to use ThreadLocal at all. Even if ThreadLocal is used, it cannot solve the thread safety issue.

On the contrary, for this kind of shared variable, if we want to ensure its thread safety, we should use other methods, such as using synchronized or locks to solve thread safety issues, rather than using ThreadLocal, because that is not the scenario ThreadLocal should be used in.

That’s the answer to this question, which may lead to the following question.

What is the relationship between ThreadLocal and synchronized? #

An interviewer may ask: since you said that both ThreadLocal and synchronized can solve thread safety issues, what is the relationship between ThreadLocal and synchronized?

Let’s first consider the first case. When ThreadLocal is used to solve thread safety issues, which means creating a unique copy of an object for each thread, in this scenario, both ThreadLocal and synchronized can be understood as means to ensure thread safety. For example, in Lesson 44, we used both synchronized and ThreadLocal as implementation solutions. However, their effects and implementation principles are different:

  • ThreadLocal avoids resource competition by making each thread maintain a copy of the resource.
  • synchronized is mainly used for the allocation of critical resources, limiting only one thread to access the resource at the same time.

Compared to ThreadLocal, synchronized has lower efficiency but consumes less memory. In this scenario, although ThreadLocal and synchronized have different effects, they can both achieve the goal of thread safety.

But for ThreadLocal, it has different usage scenarios as well. For example, when ThreadLocal is used to allow multiple classes to conveniently access information that we want to save independently for each thread (such as each thread corresponds to a user information, i.e., a user object), in this scenario, ThreadLocal focuses on avoiding parameter passing, so ThreadLocal and synchronized are two different tools in this case.

That’s all for the content of this lesson.

In this lesson, we first discussed whether ThreadLocal is used to solve the problem of multiple-thread access to shared resources. The answer is “no” because for ThreadLocal, the resources in each thread are not shared. Then we discussed the relationship between ThreadLocal and synchronized.