ThreadLocal与Runnable中的局部变量

时间:2012-04-11 23:45:00

标签: java multithreading thread-local

ThreadLocal中的哪一个或Runnable中的局部变量将首选?出于性能原因。我希望使用局部变量可以为cpu缓存等提供更多机会。

4 个答案:

答案 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. 将线程特定值保存在同一共享对象中
  2. 替代通过N层代码传递变量作为参数
  3. <强> 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作为同步的替代方法,但事实并非如此。这只是它的一个副作用,我们现在不需要同步这个变量的活动。

    希望这有所帮助。