ThreadLocal的作用
ThreadLocal的作用是给每个线程创建一个变量副本,它是线程的局部变量,可以在多线程的环境下相互之间不影响。
比如在Java中线程创建有哪几种方式 使用实现runnable接口 的方法创建的例子中,多个线程是共享一个count变量的,如下:
public class MyThreadTask implements Runnable {
private int count = 10;
@Override
public void run() {
while(count-- >0)
{
System.out.println("线程名" + Thread.currentThread().getName() + ",次数(" + count + ")");
}
}
public static void main(String[] args) {
Runnable myTask = new MyThreadTask();
Thread task1 = new Thread(myTask);
Thread task2 = new Thread(myTask);
task1.start();
task2.start();
}
}
输出
线程名Thread-0,次数(9)
线程名Thread-0,次数(7)
线程名Thread-0,次数(6)
线程名Thread-0,次数(5)
线程名Thread-0,次数(4)
线程名Thread-0,次数(3)
线程名Thread-0,次数(2)
线程名Thread-0,次数(1)
线程名Thread-0,次数(0)
线程名Thread-1,次数(8)
线程名Thread-0,次数(7)
线程名Thread-0,次数(6)
线程名Thread-0,次数(5)
线程名Thread-0,次数(4)
线程名Thread-0,次数(3)
线程名Thread-0,次数(2)
线程名Thread-0,次数(1)
线程名Thread-0,次数(0)
线程名Thread-1,次数(8)
现在我们使用ThreadLocal创建线程的局部变量
public class ThreadLocalExample implements Runnable {
private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return 10; // 这里设置期望的初始值
}
};
@Override
public void run() {
while(threadLocal.get() >0)
{
threadLocal.set(threadLocal.get()-1);//减1
System.out.println("线程名" + Thread.currentThread().getName() + ",次数(" + threadLocal.get() + ")");
}
}
public static void main(String[] args) {
Runnable myTask = new ThreadLocalExample ();
Thread task1 = new Thread(myTask);
Thread task2 = new Thread(myTask);
task1.start();
task2.start();
}
}
线程名Thread-0,次数(9)
线程名Thread-1,次数(9)
线程名Thread-0,次数(8)
线程名Thread-1,次数(8)
线程名Thread-0,次数(7)
线程名Thread-1,次数(7)
线程名Thread-0,次数(6)
线程名Thread-1,次数(6)
线程名Thread-0,次数(5)
线程名Thread-1,次数(5)
线程名Thread-0,次数(4)
线程名Thread-1,次数(4)
线程名Thread-0,次数(3)
线程名Thread-1,次数(3)
线程名Thread-0,次数(2)
线程名Thread-1,次数(2)
线程名Thread-0,次数(1)
线程名Thread-1,次数(1)
线程名Thread-0,次数(0)
线程名Thread-1,次数(0)
线程名Thread-1,次数(9)
线程名Thread-0,次数(8)
线程名Thread-1,次数(8)
线程名Thread-0,次数(7)
线程名Thread-1,次数(7)
线程名Thread-0,次数(6)
线程名Thread-1,次数(6)
线程名Thread-0,次数(5)
线程名Thread-1,次数(5)
线程名Thread-0,次数(4)
线程名Thread-1,次数(4)
线程名Thread-0,次数(3)
线程名Thread-1,次数(3)
线程名Thread-0,次数(2)
线程名Thread-1,次数(2)
线程名Thread-0,次数(1)
线程名Thread-1,次数(1)
线程名Thread-0,次数(0)
线程名Thread-1,次数(0)
从结果中看出线程之间threadLocal 值是相互不影响的,安全的。
ThreadLocal原理
ThreadLocal类中有一个map对象用于存储每个线程的变量副本。map中的key为线程对象,value为变量值。ThreadLocal的set函数
private void set(ThreadLocal<?> key, Object value) {
// We don't use a fast path as with get() because it is at
// least as common to use set() to create new entries as
// it is to replace existing ones, in which case, a fast
// path would fail more often than not.
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1);
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
ThreadLocal<?> k = e.get();
if (k == key) {
e.value = value;
return;
}
if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
}
tab[i] = new Entry(key, value);
int sz = ++size;
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
ThreadLocal应用场景
常用于web服务器保存临时会话对象,我们知道web服务器是多线程的,比如tomcat,用户的每次请求都要保存到一个临时变量里,方便下次的调用获取,那么此时就需要ThreadLocal了。