ThreadLocal与Runnable中的局部变量

sab*_*sab 9 java multithreading thread-local

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

Gra*_*ray 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();
Run Code Online (Sandbox Code Playgroud)

ThreadLocal用于在执行公共代码时基于每个线程保存状态.例如,SimpleDateFormat(遗憾的是)不是线程安全的,所以如果你想使用它,你需要在一个中存储一个,ThreadLocal以便每个线程获得它自己的格式版本.

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(...);
Run Code Online (Sandbox Code Playgroud)

必要时的示例是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
       ...
    }
}
Run Code Online (Sandbox Code Playgroud)


Mik*_*ark 5

只要您的程序可以正确使用这两个变量(ThreadLocal 局部变量)中的一个,请选择局部变量:它将提高性能。

ThreadLocal用于存储超出方法执行范围的每个线程状态。显然,局部变量不能持续超出其声明的范围。如果您需要它们,那么您可能会开始使用ThreadLocal.

另一种选择是使用synchronized来管理对共享成员变量的访问。这是一个复杂的话题,我不想在这里深入讨论,因为其他地方比我更善于表达的人已经对此进行了解释和记录。显然,这不是“本地”存储的变体——您将以线程安全的方式共享对单个资源的访问。

  • 我一直不理解ThreadLocal存储。我编写多线程应用程序已经有 30 年了,但从未使用过 TLS。当线程启动时,CreateThread() 或其他调用会获取线程应执行的地址。在大多数语言中,这是一个过程/函数,并且在那里声明的本地堆栈变量将具有线程的生命周期。在面向对象语言中,创建调用中通常有一个额外的参数可以传输“this”,因此线程也可以拥有实例数据成员。那么,为什么选择 TLS?它给了我什么“特别”的东西? (2认同)