ThreadLocal
中的哪一个或Runnable
中的局部变量将首选?出于性能原因。我希望使用局部变量可以为cpu缓存等提供更多机会。
答案 0 :(得分:14)
ThreadLocal中的哪一个或Runnable中的局部变量将是首选。
如果你有一个在线程类(或Runnable
)内声明的变量,那么局部变量将起作用,你不需要ThreadLocal
。
new Thread(new Runnable() {
// no need to make this a thread local because each thread already
// has their own copy of it
private SimpleDateFormat format = new SimpleDateFormat(...);
public void run() {
...
// this is allocated per thread so no thread-local
format.parse(...);
...
}
}).start();
当您执行公共代码时, ThreadLocal
用于在每个线程的基础上保存状态。例如,SimpleDateFormat
(不幸的是)不是线程安全的,所以如果你想使用它,你需要在ThreadLocal
中存储一个,以便每个线程获得它自己的格式版本。 / p>
private final ThreadLocal<SimpleDateFormat> localFormat =
new ThreadLocal<SimpleDateFormat>() {
@Override
protected SimpleDateFormat initialValue() {
return new SimpleDateFormat(...);
}
};
...
// if a number of threads run this common code
SimpleDateFormat format = localFormat.get();
// now we are using the per-thread format (but we should be using Joda Time :-)
format.parse(...);
何时需要这样的示例是Web请求处理程序。线程在Jetty land(例如)中分配在我们无法控制的某种池中。 Web请求与您的路径匹配,因此Jetty会调用您的处理程序。您需要有一个SimpleDateFormat
对象,但由于其局限性,您必须为每个线程创建一个。那时你需要一个ThreadLocal
。当您编写可由多个线程调用的可重入代码时,您希望存储每个线程的内容。
如果你想将参数传递给Runnable
,那么你应该创建自己的类,然后你可以访问构造函数并传入参数。
new Thread(new MyRunnable("some important string")).start();
...
private static class MyRunnable implements {
private final String someImportantString;
public MyRunnable(String someImportantString) {
this.someImportantString = someImportantString;
}
// run by the thread
public void run() {
// use the someImportantString string here
...
}
}
答案 1 :(得分:3)
每当您的程序正确使用两个(ThreadLocal
或局部变量)中的任何一个时,请选择局部变量:它将更高效。
ThreadLocal
用于存储超出方法执行范围的每线程状态。显然,局部变量不能超出其声明的范围。如果你需要它们,就可以开始使用ThreadLocal
。
另一个选择是使用synchronized
来管理对共享成员变量的访问。这是一个复杂的话题,我不打算在这里讨论它,因为它在其他地方被比我更清晰的人解释和记录。显然,这不是“本地”存储的变体 - 您将以线程安全的方式共享对单个资源的访问。
答案 2 :(得分:1)
这个问题的答案是一个简单的规则,即变量应该在尽可能小的封闭范围内声明。 ThreadLocal
是最大可能的封闭范围,因此您只应将其用于许多词法范围所需的数据。如果它可以是局部变量,那么它应该是。
答案 3 :(得分:1)
当我只能使用局部变量时,我也很困惑为什么我需要ThreadLocal,因为它们都在一个线程内维护它们的状态。但经过大量的搜索和实验,我明白为什么需要ThreadLocal。
到目前为止我找到了两种用途 -
<强> 1 强>
如果你有两个线程在同一个对象上运行,并且两个线程都修改了这个对象 - 那么两个线程都会继续失去彼此的修改。
为了使这个对象对每个线程都有两个独立的状态,我们声明这个对象或它的一部分ThreadLocal。
当然,ThreadLocal只在这里有用,因为两个线程共享同一个对象。如果他们使用不同的对象,则不需要将对象作为ThreadLocal。
<强> 2 强>
ThreadLocal的第二个好处,似乎是它实现的副作用。
ThreadLocal变量可以是一个线程的.set(),然后是.get()其他地方。 .get()将检索此线程在其他位置设置的相同值。我们需要一个全局可用的包装器来执行.get()和.set(),以实际写下代码。
当我们执行threadLocalVar.set()时 - 就好像它放在一些全局“map”中,其中这个当前线程是关键。
好像 - someGlobalMap.put(Thread.currentThread(),threadLocalVar);
当我们执行threadLocalVar.get()时,十层向下 - 我们得到此线程已设置十层的值。
threadLocalVar = someGlobalMap.get(Thread.currentThread());
因此,第十级的函数不必将此变量作为参数进行操作,并且可以使用.get()访问它,而不必担心它是否来自正确的线程。
最后,由于ThreadLocal变量是每个线程的副本,当然,它不需要同步。我之前误解了ThreadLocal作为同步的替代方法,但事实并非如此。这只是它的一个副作用,我们现在不需要同步这个变量的活动。
希望这有所帮助。