潍坊做网站张家口,贵阳网站定制,网站建设有限公,创新设计方案开发人员中鲜为人知的功能之一是线程本地存储。 这个想法很简单#xff0c;并且在需要数据的情况下很有用。 如果我们有两个线程#xff0c;则它们引用相同的全局变量#xff0c;但我们希望它们具有彼此独立初始化的单独值。 大多数主要的编程语言都有该概念的实现。 例如并且在需要数据的情况下很有用。 如果我们有两个线程则它们引用相同的全局变量但我们希望它们具有彼此独立初始化的单独值。 大多数主要的编程语言都有该概念的实现。 例如C 11甚至具有thread_local关键字Ruby选择了一种API 方法 。 从1.2版开始Java还使用java.lang.ThreadLocal T及其子类java.lang.InheritableThreadLocal T来实现该概念因此这里没有什么新鲜的东西。 假设由于某种原因我们需要为线程指定一个Long特定值。 使用线程本地将很简单 public class ThreadLocalExample {public static class SomethingToRun implements Runnable {private ThreadLocal threadLocal new ThreadLocal();Overridepublic void run() {System.out.println(Thread.currentThread().getName() threadLocal.get());try {Thread.sleep(2000);} catch (InterruptedException e) {}threadLocal.set(System.nanoTime());System.out.println(Thread.currentThread().getName() threadLocal.get());}}public static void main(String[] args) {SomethingToRun sharedRunnableInstance new SomethingToRun();Thread thread1 new Thread(sharedRunnableInstance);Thread thread2 new Thread(sharedRunnableInstance);thread1.start();thread2.start();}} 以下代码的一个可能示例运行将导致 Thread-0 nullThread-0 132466384576241Thread-1 nullThread-1 132466394296347 在开始时两个线程的值都设置为null显然每个线程都使用单独的值因为在将Thread-0的值设置为System.nanoTime之后 它不会对Thread-1的值产生任何影响如我们所愿一个线程作用域的long变量。 一个不错的副作用是线程从各种类调用多个方法的情况。 他们都将能够使用相同的线程范围变量而无需进行重大的API更改。 由于未明确传递价值因此可能会难以测试且不利于设计但这完全是一个单独的主题。 在哪些地区流行使用线程局部语言的框架 作为Java中最受欢迎的框架之一Spring在内部将ThreadLocals用于许多部分可通过简单的github 搜索轻松显示。 大多数用法与当前用户的操作或信息有关。 实际上这实际上是JavaEE世界中ThreadLocals的主要用途之一例如在RequestContextHolder中存储当前请求的信息 private static final ThreadLocalRequestAttributes requestAttributesHolder new NamedThreadLocalRequestAttributes(Request attributes); 或UserCredentialsDataSourceAdapter中的当前JDBC连接用户凭据。 如果我们回到RequestContextHolder则可以使用此类访问代码中任何位置的所有当前请求信息。 常见的用例是LocaleContextHolder 它可以帮助我们存储当前用户的语言环境。 Mockito使用它来存储当前的“全局” 配置 如果我们看看那里的任何框架那么我们也很有可能会找到它。 线程本机和内存泄漏 我们了解了这个很棒的小功能所以让我们在各处使用它。 我们可以做到这一点但很少有Google搜索而且我们发现那里的大多数人都说ThreadLocal是邪恶的。 并非完全正确它是一个很好的实用程序但在某些情况下可能容易造成内存泄漏。 “您是否可以通过线程局部变量导致意外的对象保留 你当然可以。 但是您也可以使用数组来执行此操作。 这并不意味着线程局部变量或数组是坏事。 只是您必须谨慎使用它们。 使用线程池需要格外小心。 随意使用线程池与随意使用线程本地变量相结合会导致意外的对象保留这在许多地方都已提到。 但是将责任归咎于线程本机是没有根据的。” –约书亚·布洛赫Joshua Bloch 如果它在应用程序服务器上运行则使用ThreadLocal在服务器代码中创建内存泄漏非常容易。 ThreadLocal上下文与运行它的线程相关联一旦线程死掉它将被丢弃。 现代的应用服务器使用线程池而不是在每个请求上创建新线程这意味着您最终可能会无限期地在应用程序中保存大型对象。 由于线程池来自应用程序服务器因此即使卸载应用程序后我们的内存泄漏仍会保留。 修复方法很简单可以释放不需要的资源。 另一个ThreadLocal滥用是API设计。 我经常看到到处都在使用RequestContextHolder 它持有ThreadLocal 例如DAO层。 后来如果有人在诸如和调度程序之类的请求之外调用相同的DAO方法他将得到一个非常糟糕的惊喜。 这使黑魔法和许多维护开发人员最终找到了您的住所并进行了访问。 即使ThreadLocal中的变量是线程本地的它们在代码中还是非常全局的。 使用它之前请确保您确实需要此线程作用域。 有关该主题的更多信息 http://en.wikipedia.org/wiki/Thread-local_storage http://www.appneta.com/blog/introduction-to-javas-threadlocal-storage/ https://plumbr.eu/blog/how-to-shoot-yourself-in-foot-with-threadlocals http://stackoverflow.com/questions/817856/when-and-how-should-i-use-a-threadlocal-variable https://plumbr.eu/blog/when-and-how-to-use-a-threadlocal https://weblogs.java.net/blog/jjviana/archive/2010/06/09/dealing-glassfish-301-memory-leak-or-threadlocal-thread-pool-bad-ide https://software.intel.com/zh-CN/articles/use-thread-local-storage-to-reduce-synchronization 翻译自: https://www.javacodegeeks.com/2014/12/thread-local-storage-in-java.html