ThreadLocal
ThreadLocal :线程本地变量 也叫 线程本地存储,ThreadLocal为变量在每一个线程中创建一个副本,每个线程可以访问自己内部的副本变量。
这句话理解起来还是比较容易理解的。 建议结合源码一起看看,比较容易理解哦。
ThreadLocal类中的方法
threadLocal.get(); 获取ThreadLocal中当前线程共享变量的值
threadLocal.set(); 设置ThreadLocal中当前线程共享变量的值
threadLocal.remove(); 移除ThreadLocal中当前线程共享变量的值
threadLocal.initialValue(); ThreadLocal没有被当前线程赋值是或者当前线程刚调用remove方法后调用get方法,返回此方法的值。
public class ThreadLocalTest {
.// 创建Threadlocal 对象
ThreadLocal<Long> tl = new ThreadLocal();
ThreadLocal<String> t2 = new ThreadLocal();
public void set( ) {
tl.set(Thread.currentThread().getId());
t2.set(Thread.currentThread().getName());
}
public void getTl() {
System.out.println(tl.get());
System.out.println(t2.get());
}
public static void main(String[] args) {
// main 执行
ThreadLocalTest test = new ThreadLocalTest();
test.set();
test.getTl();
// threads 线程执行
Thread threads = new Thread(){
@Override
public void run() {
test.set();
test.getTl();
}
};
threads.start();
try {
threads.join(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
test.set();
test.getTl();
}
}
执行结果
原理是什么呢?
Thread.ThreadLocalMap<ThreadLocal, Object>;
Thread:当前线程,可以通过Thread。currentThread()获取。
ThreadLocal: 是一开始创建的 ThreadLocal对象。
Object :当前线程共享变量
我们调用Threadlocal.get() 方法,实际上就是从当前线程中获取ThreadLocalMap<ThreadLocal . Object>,然后根据当前ThreadLocal获取当前线程共享变量Object。
ThreadLocal.set 和 ThreadLocal.remove 也是同样的原理。
ThreadLocal.get 源码
/**
* Returns the value in the current thread's copy of this
* thread-local variable. If the variable has no value for the
* current thread, it is first initialized to the value returned
* by an invocation of the {@link #initialValue} method.
*
* @return the current thread's value of this thread-local
*/
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
获得当前线程,通过getMap(t)方法获取到 ThreadLocalMap 。从map中取值,map为空就返回setInitialValue();
我们看看 getMap(t)是怎么实现的。
getMap (Thread) 源码
/**
* Get the map associated with a ThreadLocal. Overridden in
* InheritableThreadLocal.
*
* @param t the current thread
* @return the map
*/
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
就是返回了一个t.treadLocals; 这个t.threadLocals就是ThreadLocal.ThreadLocalMap 。
setInitialValue() 源码
/**
* Variant of set() to establish initialValue. Used instead
* of set() in case user has overridden the set() method.
*
* @return the initial value
*/
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
//-----------------------------------------------------------------------------------
protected T initialValue() {
return null;
}
当前线程的ThreadLocalMap为空那就创建一个当前线程的ThreadLocalMap他的值为空。不为空那就设置当前线程的ThreadLocalmap的值为空。
ThreadLocal.set 源码
/**
* Sets the current thread's copy of this thread-local variable
* to the specified value. Most subclasses will have no need to
* override this method, relying solely on the {@link #initialValue}
* method to set the values of thread-locals.
*
* @param value the value to be stored in the current thread's copy of
* this thread-local.
*/
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
是不是和setInitialValue()方法非常像。
ThreadLocal.remove 源码
/**
* Removes the current thread's value for this thread-local
* variable. If this thread-local variable is subsequently
* {@linkplain #get read} by the current thread, its value will be
* reinitialized by invoking its {@link #initialValue} method,
* unless its value is {@linkplain #set set} by the current thread
* in the interim. This may result in multiple invocations of the
* {@code initialValue} method in the current thread.
*
* @since 1.5
*/
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
好了这里的源码就展示完了。
贴一下自己写的代码:
package com.zw.modules.app.utils;
/**
* Created by lgx on 2019/3/20.
*/
public class ThreadLocalTest2 {
static ThreadLocal<Object> threadLocal = new ThreadLocal<Object>(){
@Override
protected String initialValue() {
return "调用get方法时,如果ThreadLocalMap中没有值,默认会返回initialValue()方法的返回值。";
}
};
public void set(){
threadLocal.set(Thread.currentThread().getName());
}
public void get(){
System.out.println(threadLocal.get());
}
public void remvoe(){
threadLocal.remove();
}
public static void main(String[] args) {
ThreadLocalTest2 t2 = new ThreadLocalTest2();
t2.set();
t2.get();
for (int i=0; i<5; i++){
if(i==2){
Thread tt = new Thread(){
@Override
public void run() {
t2.remvoe();
t2.get();
}
};
tt.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
Thread tt = new Thread() {
@Override
public void run() {
t2.set();
t2.get();
}
};
tt.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}