ThreadLocal
- 类ThreadLocal主要解决的就是每个线程绑定自己的值,可以将ThreadLocal类比喻成全局存放数据的盒子,盒子中可以存储每个线程的私有数据。而这个盒子里存放的数据是以map的形式将其对应的线程关联起来.
get与set方法
- 首先看其源码
public T get() {
//获取当前线程
Thread t = Thread.currentThread();
//在map中找到当前线程对应的map数据
ThreadLocalMap map = getMap(t);
if (map != null) {
//找到就获取其键值对
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
//返回键值对的value
T result = (T)e.value;
return result;
}
}
//返回默认值
return setInitialValue();
}
public void set(T value) {
//获取当前线程
Thread t = Thread.currentThread();
//获取当前线程的map
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
- 演示
public static void main(String[] args) {
ThreadLocal threadLocal = new ThreadLocal();
if (threadLocal.get() == null) {
System.out.println("未设置值");
threadLocal.set("我是菜鸟");
}
System.out.println(threadLocal.get());
}
-
运行结果
-
从图中的运行结果来看,第一次调用threadLocal 对象的get()方法时返回的值是null,通过调用set()方法赋值后顺利取出值并打印到控制台上。类Threadlocal解决的是变量在不同线程间的隔离性,也就是不同线程拥有自己的值,不同线程中的值是可以放入Threadlocal类中进行保存的。
隔离性
- 虽然2个线程都向同一个threadlocal对象中set数据值,但每个线程还是能取出自己的数据。
public class Demo {
public static ThreadLocal<Date> threadLocal = new ThreadLocal<>();
public static void main(String[] args) throws InterruptedException {
//创建俩个线程去挨个保存当前时间
Thread a = new Thread("A") {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
threadLocal.set(new Date());
System.out.println(Thread.currentThread().getName() + " " + threadLocal.get().getTime());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Thread b = new Thread("B") {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
threadLocal.set(new Date());
System.out.println(Thread.currentThread().getName() + " " + threadLocal.get().getTime());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
a.start();
b.start();
a.join();
b.join();
}
}
覆盖initialValue方法
- 在第一次调用Threadlocal类的get()方法返回值是null,怎么样实现第一次调用get()不返回null呢?也就是具有默认值的效果。就是重写initialValue方法
public class Demo2 {
public static void main(String[] args) {
ThreadLocal threadLocal = new ThreadLocal() {
@Override
protected Object initialValue() {
return "我是默认值";
}
};
if (threadLocal.get() == null) {
System.out.println("未设置值");
threadLocal.set("我是菜鸟");
}
System.out.println(threadLocal.get());
}
}
类InheritableThreadLocal的使用
- 使用类InheritableThreadLocal可以在子线程中取得父线程继承下来的值。
演示值继承
public class Demo3 {
public static InheritableThreadLocal inheritableThreadLocal = new InheritableThreadLocal() {
@Override
protected Object initialValue() {
return new Date().getTime();
}
};
public static void main(String[] args) throws InterruptedException {
System.out.println("main get " + inheritableThreadLocal.get());
System.out.println("main set...");
Thread.sleep(222);
inheritableThreadLocal.set(new Date().getTime());
System.out.println("main get " + inheritableThreadLocal.get());
Thread thread = new Thread("A") {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("A get " + inheritableThreadLocal.get());
try {
Thread.sleep(222);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
thread.start();
Thread.sleep(1000);
System.out.println("main 再次set...");
inheritableThreadLocal.set(new Date().getTime());
System.out.println("main get " + inheritableThreadLocal.get());
thread.join();
}
}
- 上述代码可以看出, 线程A继承了主线程main的值, 而且当主线程将自己的数据修改后, A线程保存的还是旧的那个值.