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();
}
}
复制代码