早在JDK1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。但是ThreadLocal并不是一个线程,他是一个线程变量。意思是ThreadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的。伴随整个线程生命周期存在,可以作为线程执行,对象跨层,父子线程通信,线程追踪的标记。
ThreadLocal作用
1、在进行对象跨层传递的时候,使用ThreadLocal可以避免多次传递,打破层次间的约束。
2、线程间数据隔离
3、进行事务操作,用于存储线程事务信息。
4、数据库连接,Session会话管理。
ThreadLocal怎么用
public class ThreadLocalTest {
static ThreadLocal<String> local = new ThreadLocal<>();
static void print(String str) {
//打印当前线程中本地内存中本地变量的值
System.out.println(str + " :" + local.get());
//清除本地内存中的本地变量
local.remove();
}
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
//设置线程1中本地变量的值
local.set("local1");
//调用打印方法
print("thread1");
//打印本地变量
System.out.println("after remove : " + local.get());
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
//设置线程1中本地变量的值
local.set("local2");
//调用打印方法
print("thread2");
//打印本地变量
System.out.println("after remove : " + local.get());
}
});
t1.start();
t2.start();
}
}
ThreadLocal源码分析
重点是get,set,remove方法
get方法源码
public Object get()
{
Thread thread = Thread.currentThread();
ThreadLocalMap threadlocalmap = getMap(thread);
if(threadlocalmap != null)
{
ThreadLocalMap.Entry entry = threadlocalmap.getEntry(this);
if(entry != null)
return entry.value;
}
return setInitialValue();
}
set方法源码
private void set(ThreadLocal threadlocal, Object obj)
{
Entry aentry[] = table;
int i = aentry.length;
int j = threadlocal.threadLocalHashCode & i - 1;
for(Entry entry = aentry[j]; entry != null; entry = aentry[j = nextIndex(j, i)])
{
ThreadLocal threadlocal1 = (ThreadLocal)entry.get();
if(threadlocal1 == threadlocal)
{
entry.value = obj;
return;
}
if(threadlocal1 == null)
{
replaceStaleEntry(threadlocal, obj, j);
return;
}
}
aentry[j] = new Entry(threadlocal, obj);
int k = ++size;
if(!cleanSomeSlots(j, k) && k >= threshold)
rehash();
}
remove方法源码
private void remove(ThreadLocal threadlocal)
{
Entry aentry[] = table;
int i = aentry.length;
int j = threadlocal.threadLocalHashCode & i - 1;
for(Entry entry = aentry[j]; entry != null; entry = aentry[j = nextIndex(j, i)])
if(entry.get() == threadlocal)
{
entry.clear();
expungeStaleEntry(j);
return;
}
}
ThreadLocal内存泄漏问题
使用set方法移除key,但是value依然在并不会被垃圾回收器回收,value会一直持续到线程结束才会被回收,这就存在内存泄漏的可能性。可以使用remove移除value来避免内存泄漏。