JUC-ThreadLocal
前言
多线程访问同一个共享变量的时候也别容易出现并发问题,特别是在多线程需要对一个共享变量进行写入的时候。为了保证线程的安全,一般使用者在访问共享变量的时候需要进行适当的同步。如下图所示
同步的措施一般是加锁,但是加锁显然加重了使用者的负担。那么有没有一种方式可以做到,当创建一个线程过后,每个线程对其访问的时候,访问的是自己线程的变量呢?其实ThreadLocal就可以做出这样一件事。
ThreadLocal
ThreadLocal是JDK提供的,它提供了线程本地变量,也就是说如果你创建了一个ThreadLocal变量,那么访问这个变量的每个线程都会有这个变量的一个本地副本。当多个线程操作这个变量的时候,实际上操作的是自己本地内存里面的变量,从而避免了线程安全问题。创建一个ThreadLocal变量后,每个线程都会复制一个变量到自己的本地内存,如下图所示:
ThreadLocal测试
代码如下:
public class ThreadLocalTest {
static void print(String str){
System.out.println(str+":"+localVariable.get());
localVariable.remove();
}
static ThreadLocal<String> localVariable=new ThreadLocal<String>();
public static void main(String[] args) throws Exception{
Thread threadone=new Thread(() -> {
localVariable.set("threadone local variable");
print("threadone");
System.out.println("threadone remove after"+":"+localVariable.get());
});
Thread threadtwo=new Thread(() -> {
localVariable.set("threadtwo local variable");
print("threadtwo");
System.out.println("threadtwo remove after"+":"+localVariable.get());
});
threadone.start();
threadtwo.start();
}
}
结果:
ThreadLocal类结构
ThreadLocal不支持继承性
看一个栗子:
public class ThreadLocaltest2 {
public static ThreadLocal<String> threadLocal=new ThreadLocal<>();
public static void main(String[] args) {
threadLocal.set("hello world");
Thread thread=new Thread(() -> {
System.out.println("thread:"+threadLocal.get());
});
thread.start();
System.out.println("main:"+threadLocal.get());
}
}
输出结果:
threadlocal变量是在main父线程中声明的,因此子线程thread是获取不到的。
InheritableThreadLocal
为了解决上诉问题,InheritableThreadLocal应运而生。
public class InheritableThreadLocalTest {
public static InheritableThreadLocal<String> threadLocal=new InheritableThreadLocal<>();
public static void main(String[] args) {
threadLocal.set("hello world");
Thread thread=new Thread(() -> {
System.out.println("thread:"+threadLocal.get());
});
thread.start();
System.out.println("main:"+threadLocal.get());
}
}
输出结果: