ThreadLocal使用注意

ThreadLocal的出现是一种空间换时间的思想的运用,是为了多线程环境下单线程内变量共享的问题。它的原理就是每一个线程经过ThreadLocal.ThreadLocalMap,保存当前线程中全部ThreadLocal变量引用的key和值。至关于每一个线程有各自的变量副本,线程内共享这个变量数据,线程间互不影响。java

ThreadLocal有它本身的使用场景,好比Spring中用它了解决Session、Connection等多线程并发访问问题,但不能它不能用来代替为了解决多线程安全问题的同步关键字,由于它实际上没有多线程间的变量共享,而线程安全问题是指多线程间变量共享,且共享变量可修改,进而可能会出现多线程并发修改共享变量的问题,这种须要经过同步手段解决。安全

ThreadLocal变量通常要声名成static类型,即当前线程中只有一个T类型变量的实例,线程内可共享该实例数据且不会出问题,如将其声名成非static,则一个线程内就存储多个T类型变量的实例,有点存储空间的浪费,通常不多有这样的应用场景。另外根据实际状况,ThreadLocal变量声名时也多加上private final关键词代表它时类内私有、引用不可修改。多线程

在线程池环境下,因为线程是一直运行且复用的,使用ThreadLocal时会出现这个任务看到上个任务ThreadLocal变量值以及内存泄露等问题,解决方法就是在当前任务执行完后将ThreadLocal变量remove或设置为初始值,相似在Struts2 框架中Filter里的处理方法。并发

虽然ThreadLocal的get,set方法能够清除ThreadLocalMap中key为null的value,可是get,set方法在内存泄露后并不会必然调用,因此为了防止此类状况的出现,咱们有两种手段。框架

一、使用完线程共享变量后,显示调用ThreadLocalMap.remove方法清除线程共享变量;this

二、JDK建议ThreadLocal定义为private static,这样ThreadLocal的弱引用问题则不存在了。google

最佳实践

最佳实践的方法参见google guava eventbus中对于ThreadLocal的使用spa

private final ThreadLocal<Boolean> dispatching;
    
    this.dispatching = new ThreadLocal() {
                protected Boolean initialValue() {
                    return Boolean.valueOf(false);
                }
            }
    if(!((Boolean)this.dispatching.get()).booleanValue()) {
                this.dispatching.set(Boolean.valueOf(true));

                Dispatcher.PerThreadQueuedDispatcher.Event nextEvent;
                try {
                    while((nextEvent = (Dispatcher.PerThreadQueuedDispatcher.Event)queueForThread.poll()) != null) {
                        while(nextEvent.subscribers.hasNext()) {
                            ((Subscriber)nextEvent.subscribers.next()).dispatchEvent(nextEvent.event);
                        }
                    }
                } finally {
                    this.dispatching.remove();
                    this.queue.remove();
                }
            }
复制代码
  • 采用匿名内部类赋初始值
  • 显式调用get()、set()
  • 在不用的时候显式地remove()掉
  • 对于显示的remove特别重要,由于这样能够避免entry不被GC的状况
  • 若是为了不ThreadLocal被GC,能够增强ThreadLocal的引用,将其声明成private static
相关文章
相关标签/搜索