java ThreadLocal 的目的?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1490919/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Purpose of ThreadLocal?
提问by Ajay
The purpose of ThreadLocal as given herestates that the variable is local to any Thread accessing an object containing the ThreadLocal variable. What difference does it make, in having a ThreadLocal variable as a member of a class and then making it local to a Thread, rather than having a local variable to the Thread itself?
此处给出的 ThreadLocal 的目的表明该变量对于访问包含 ThreadLocal 变量的对象的任何线程都是本地的。它有什么区别,将 ThreadLocal 变量作为类的成员,然后使其成为 Thread 的本地变量,而不是 Thread 本身的局部变量?
回答by leonm
A thread is a unit of execution and so multiple thread can execute the same code at the same time. If multiple threads execute on an object/instance at the same time they will share the instance variables. Each thread will have its own local variables but it is difficult to share these across objects without passing parameters.
线程是一个执行单元,因此多个线程可以同时执行相同的代码。如果多个线程同时在一个对象/实例上执行,它们将共享实例变量。每个线程都有自己的局部变量,但是如果不传递参数就很难跨对象共享这些变量。
It is best explained by way of an example. Say you have a Servlet that gets the logged in user and then executes some code.
最好通过一个例子来解释。假设您有一个 Servlet 获取登录用户,然后执行一些代码。
doGet(HttpServletRequest req, HttpServletResponse resp) {
User user = getLoggedInUser(req);
doSomething()
doSomethingElse()
renderResponse(resp)
}
Now what happens if the doSomething() methods needs access to the user object? You can't make the user object an instance or static variable because each thread will then use the same user object. You could pass the user object around as a parameter but this quickly becomes messy and leaks user objects into every method call:
现在如果 doSomething() 方法需要访问用户对象会发生什么?您不能使用户对象成为实例或静态变量,因为每个线程将使用相同的用户对象。您可以将用户对象作为参数传递,但这很快就会变得混乱,并将用户对象泄漏到每个方法调用中:
doGet(HttpServletRequest req, HttpServletResponse resp) {
User user = getLoggedInUser(req);
doSomething(user)
doSomethingElse(user)
renderResponse(resp,user)
}
A more elegant solution is to put the user object into a ThreadLocal
更优雅的解决方案是将用户对象放入 ThreadLocal
doGet(HttpServletRequest req, HttpServletResponse resp) {
User user = getLoggedInUser(req);
StaticClass.getThreadLocal().set(user)
try {
doSomething()
doSomethingElse()
renderResponse(resp)
}
finally {
StaticClass.getThreadLocal().remove()
}
}
Now any code that requires the user object at any time can get hold of it by extracting it from the thread local, without needing to resort to those pesky extra parameters:
现在任何需要用户对象的代码都可以通过从本地线程中提取它来获取它,而无需求助于那些讨厌的额外参数:
User user = StaticClass.getThreadLocal().get()
If you use this approach be mindful to remove the objects again in a finally block. Otherwise the user object might hang around in environments that use a Thread Pool (like Tomcat app server).
如果您使用这种方法,请注意在 finally 块中再次删除对象。否则,用户对象可能会在使用线程池的环境(如 Tomcat 应用程序服务器)中徘徊。
Edit: The code for static class
编辑:静态类的代码
class StaticClass {
static private ThreadLocal<User> threadLocal = new ThreadLocal<>();
static ThreadLocal<User> getThreadLocal() {
return threadLocal;
}
}
回答by Michael Borgwardt
You have to realize that an instance of a class that extends Thread is notthe same thing as an actual Java thread(which can be imagined as a "execution pointer" that runs through your code and executes it).
你必须认识到,继承Thread类的一个实例是不相同的事,作为一个实际的Java线程(它可以被想象成一个“执行的指针”通过您的代码并执行该运行)。
Instances of such a class representa Java thread and allow to manipulate it (e.g. interrupt it), but apart from that they are just regular objects, and their members can be accessed from all threads that can get hold of a reference to the object (which is not hard).
这种类的实例代表一个 Java 线程并允许对其进行操作(例如中断它),但除此之外,它们只是常规对象,并且它们的成员可以从所有可以获得对象引用的线程中访问(这并不难)。
Of course you can try to keep a member private and make sure that it's only used by the run()or methods called from it (public methods can be called from other threads as well), but this is error-prone and not really feasible for a more complex system where you don't want to keep data all in a Thread subclass (actually you're not supposed to subclass Thread, but to use Runnable instead).
当然,您可以尝试将成员设为私有,并确保它仅由run()从它调用的或 方法使用(公共方法也可以从其他线程调用),但这很容易出错,并且对于更复杂的系统,您不想将数据全部保存在 Thread 子类中(实际上,您不应该将 Thread 子类化,而是使用 Runnable )。
ThreadLocal is a simple, flexible way to have per-thread data that cannotbe accessed concurrently by other threads, without requiring great effort or design compromises.
ThreadLocal 是一种简单、灵活的方法,可以让其他线程无法同时访问每个线程的数据,而无需付出很大的努力或在设计上做出妥协。
回答by cletus
A Thread object can have internal data members but these are accessible to anyone who has (or can get) a reference to the Thread object. A ThreadLocal is deliberately associated only with the each Thread that accesses it. The advantage is that there are no concurrency issues (within the context of the ThreadLocal). A Thread's internal data member has all the same concurrency issues any shared state does.
Thread 对象可以具有内部数据成员,但任何拥有(或可以获得)对 Thread 对象的引用的人都可以访问这些成员。一个 ThreadLocal 故意只与访问它的每个线程相关联。优点是没有并发问题(在 ThreadLocal 的上下文中)。线程的内部数据成员具有与任何共享状态相同的并发问题。
Let me explain the idea of associating a result with a particular thread. The essence of a ThreadLocal is something like this:
让我解释一下将结果与特定线程相关联的想法。ThreadLocal 的本质是这样的:
public class MyLocal<T> {
private final Map<Thread, T> values = new HashMap<Thread, T>();
public T get() {
return values.get(Thread.currentThread());
}
public void set(T t) {
values.put(Thread.currentThread(), t);
}
}
Now there's more to it than that but as you can see the value returned is determined by the current thread. That's why it's localto each thread.
现在还有更多内容,但正如您所见,返回的值是由当前线程决定的。这就是为什么它对每个线程都是本地的。
回答by Kees de Kooter
ThreadLocal is very useful in webapplications. The typical pattern is that somewhere at the start of the processing of a web request (usually in a servlet filter) state is stored in a ThreadLocal variable. Because all of the processing for a request is done in 1 thread all components participating in the request have access to this variable.
ThreadLocal 在 web 应用程序中非常有用。典型的模式是在开始处理 Web 请求时(通常在 servlet 过滤器中)状态存储在 ThreadLocal 变量中。因为请求的所有处理都是在 1 个线程中完成的,所以参与请求的所有组件都可以访问此变量。
回答by dz.
There is a wikipedia entry aboutthis problem area. In our environment it's usually used to keep things local to request. On the server side a request is handled mostly by a single thread. To keep things local you put your data, e.g. the session data, in a thread local variable. This data is invisible to the other request (threads) and therefore you don't need to synchronize it with the other requests.
有一个关于这个问题区域的维基百科条目。在我们的环境中,它通常用于保持本地请求。在服务器端,请求主要由单个线程处理。为了保持本地化,您将数据(例如会话数据)放在线程局部变量中。此数据对其他请求(线程)不可见,因此您无需将其与其他请求同步。
And donn't forget, there are JAVA API constructs, that are notthread safe, e.g. DateFormat. A static instance of DateFormat just doesn't work on the server side.
并且不要忘记,有 JAVA API 构造,它们不是线程安全的,例如DateFormat。DateFormat 的静态实例在服务器端不起作用。
In fact, it's easier to handle multi threaded programming when you use your own private copy of data than handling with locks and monitors.
事实上,当您使用自己的私有数据副本时,处理多线程编程比使用锁和监视器更容易。
回答by Stephen C
The advantage of ThreadLocals is that they are usable by methods run on plain vanilla Threads ... or any subclass of Thread.
ThreadLocals 的优点是它们可以被在普通线程上运行的方法使用......或线程的任何子类。
By contrast, if your thread locals have to be implemented as members of a custom subclass of Thread, there are a lot of things you cannot do. For example, your application will be in trouble if it needs to run methods on pre-existing vanilla Thread instances; i.e. instances that were created by some library code that the application writer did not write, and cannot modify.
相比之下,如果您的线程局部变量必须作为 Thread 的自定义子类的成员来实现,则有很多事情您不能做。例如,如果您的应用程序需要在预先存在的 vanilla Thread 实例上运行方法,它就会遇到麻烦;即由应用程序编写者未编写且无法修改的某些库代码创建的实例。

