InheritableThreadLocal类
InheritableThreadLocal类的作用
InheritableThreadLocal类可使子线程继承父线程的值
示例代码:
public class StaticThreadLocal {
public static InheritableThreadLocal<Object> itl = new InheritableThreadLocal<>();
}
class MyThreadX extends Thread{
@Override
public void run() {
try {
for(int i=0;i<5;i++){
System.out.println("MyThreadX中取值=>"+StaticThreadLocal.itl.get());
Thread.sleep(1000);
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
class TestMtl{
public static void main(String[] args) throws InterruptedException {
for(int i=0;i<5;i++){
if(StaticThreadLocal.itl.get()==null){
StaticThreadLocal.itl.set("main");
}
Thread.sleep(1000);
System.out.println("main中取值=>"+StaticThreadLocal.itl.get());
}
Thread.sleep(2000);
MyThreadX myThreadX = new MyThreadX();
myThreadX.start();
}
}
执行结果:
main中取值=>main
main中取值=>main
main中取值=>main
main中取值=>main
main中取值=>main
MyThreadX中取值=>main
MyThreadX中取值=>main
MyThreadX中取值=>main
MyThreadX中取值=>main
MyThreadX中取值=>main
InheritableThreadLocal类源码
InheritableThreadLocal类继承ThreadLocal类,源码如下:
public class InheritableThreadLocal<T> extends ThreadLocal<T> {
protected T childValue(T parentValue) {
return parentValue;
}
ThreadLocalMap getMap(Thread t) {
return t.inheritableThreadLocals;
}
//创建一个ThreadLocalMap,将其赋值给inheritableThreadLocals ,inheritableThreadLocals 是Thread
//类的实例变量类型为ThreadLocal.ThreadLocalMap
void createMap(Thread t, T firstValue) {
t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
}
}
父子线程的inheritableThreadLocals 变量是相互独立的
线程在创建的时候会判断其父线程的inheritableThreadLocals 变量是否为null,不为null就将父线程的inheritableThreadLocals变量赋值给子线程的inheritableThreadLocals变量,赋值源码如下所示:
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
由源码可知线程创建初始赋值的时候新建了一个ThreadLocalMap,所以父线程的inheritableThreadLocals变量和子线程的inheritableThreadLocals是相互独立的。因此子线程创建之后父线程中的inheritableThreadLocals变量值改变,子线程的值是不会跟着改变的。同理子线程inheritableThreadLocals变量有了新值,父线程的inheritableThreadLocals变量也不会跟着改变。
改变父线程的值子线程的值未改变示例代码如下:
public class StaticThreadLocal {
public static InheritableThreadLocal<Object> itl = new InheritableThreadLocal<>();
}
class MyThreadX extends Thread{
@Override
public void run() {
try {
for(int i=0;i<5;i++){
System.out.println("MyThreadX中类中取值=>"+StaticThreadLocal.itl.get());
Thread.sleep(1000);
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
class TestMtl{
public static void main(String[] args) throws InterruptedException {
for(int i=0;i<5;i++){
if(StaticThreadLocal.itl.get()==null){
StaticThreadLocal.itl.set("main");
}
System.out.println("main中取值=>"+StaticThreadLocal.itl.get());
}
Thread.sleep(2000);
MyThreadX myThreadX = new MyThreadX();
myThreadX.start();
Thread.sleep(1000);
StaticThreadLocal.itl.set("main改变了!");
System.out.println("main中取值=>"+StaticThreadLocal.itl.get());
}
}
执行结果:
main中取值=>main
main中取值=>main
main中取值=>main
main中取值=>main
main中取值=>main
MyThreadX中类中取值=>main
MyThreadX中类中取值=>main
main中取值=>main改变了!
MyThreadX中类中取值=>main
MyThreadX中类中取值=>main
MyThreadX中类中取值=>main
改变子线程的值父线程的值未改变代码示例:
public class StaticThreadLocal {
public static InheritableThreadLocal<Object> itl = new InheritableThreadLocal<>();
}
class MyThreadX extends Thread{
@Override
public void run() {
try {
for(int i=0;i<5;i++){
System.out.println("MyThreadX中类中取值=>"+StaticThreadLocal.itl.get());
if(i==2){
StaticThreadLocal.itl.set("MyThreadX改变了!");
}
Thread.sleep(1000);
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
class TestMtl{
public static void main(String[] args) throws InterruptedException {
for(int i=0;i<5;i++){
if(StaticThreadLocal.itl.get()==null){
StaticThreadLocal.itl.set("main");
}
System.out.println("main中取值=>"+StaticThreadLocal.itl.get());
}
Thread.sleep(2000);
MyThreadX myThreadX = new MyThreadX();
myThreadX.start();
Thread.sleep(5000);
System.out.println("--main中取值=>"+StaticThreadLocal.itl.get());
}
}
执行结果:
main中取值=>main
main中取值=>main
main中取值=>main
main中取值=>main
main中取值=>main
MyThreadX中类中取值=>main
MyThreadX中类中取值=>main
MyThreadX中类中取值=>main
MyThreadX中类中取值=>MyThreadX改变了!
MyThreadX中类中取值=>MyThreadX改变了!
--main中取值=>main
如果父线程或子线程改变了inheritableThreadLocals变量中存储的对象的属性值,则他们可以获取到被改变的属性值
上面说的父子线程的inheritableThreadLocals 变量值改变不会相互影响,如果是父线程改变了inheritableThreadLocals变量中存储的对象的属性,那么子线程是可以获取到改变后的属性值的。
示例代码如下:
class User{
String name;
int age;
public User(String name,int age){
this.name = name;
this.age = age;
}
这里省略get、set方法...
}
public class StaticThreadLocal {
public static InheritableThreadLocal<User> itl = new InheritableThreadLocal<>();
}
class MyThreadX extends Thread{
@Override
public void run() {
try {
for(int i=0;i<5;i++){
Thread.sleep(1000);
System.out.println("MyThreadX中取出姓名=>"
+StaticThreadLocal.itl.get().getName()
+" 年龄=>"+StaticThreadLocal.itl.get().getAge());
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
class TestMtl{
public static void main(String[] args) throws InterruptedException {
User user = new User("康康", 10);
StaticThreadLocal.itl.set(user);
MyThreadX myThreadX = new MyThreadX();
myThreadX.start();
Thread.sleep(2000);
user.setName("胖虎");
user.setAge(12);
System.out.println("user属性改变了!");
}
}
执行结果:
MyThreadX中取出姓名=>康康 年龄=>10
MyThreadX中取出姓名=>康康 年龄=>10
user属性改变了!
MyThreadX中取出姓名=>胖虎 年龄=>12
MyThreadX中取出姓名=>胖虎 年龄=>12
MyThreadX中取出姓名=>胖虎 年龄=>12
同样在子线程中改变inheritableThreadLocals变量中存储的对象的属性值父线程中取到的也是改变后的。
实例代码如下:
class User{
String name;
int age;
public User(String name,int age){
this.name = name;
this.age = age;
}
这里省略get、set方法...
}
public class StaticThreadLocal {
public static InheritableThreadLocal<User> itl = new InheritableThreadLocal<>();
}
class MyThreadX extends Thread{
@Override
public void run() {
try {
for(int i=0;i<5;i++){
Thread.sleep(1000);
System.out.println("MyThreadX中取出姓名=>"+
StaticThreadLocal.itl.get().getName()+
" 年龄=>"+StaticThreadLocal.itl.get().getAge());
if(i==2){
StaticThreadLocal.itl.get().setName("胖虎");
StaticThreadLocal.itl.get().setAge(12);
}
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
class TestMtl{
public static void main(String[] args) throws InterruptedException {
User user = new User("康康", 10);
StaticThreadLocal.itl.set(user);
MyThreadX myThreadX = new MyThreadX();
myThreadX.start();
Thread.sleep(6000);
System.out.println("main中取出姓名=>"+StaticThreadLocal.itl.get().getName()+" 年龄=>"+StaticThreadLocal.itl.get().getAge());
}
}
执行结果:
MyThreadX中取出姓名=>康康 年龄=>10
MyThreadX中取出姓名=>康康 年龄=>10
MyThreadX中取出姓名=>康康 年龄=>10
MyThreadX中取出姓名=>胖虎 年龄=>12
MyThreadX中取出姓名=>胖虎 年龄=>12
main中取出姓名=>胖虎 年龄=>12
重写InheritableThreadLocal类中的childValue方法,子线程可以在childValue方法中修改从父线程继承过来的值
示例代码如下:
class MyInheritableThreadLocal extends InheritableThreadLocal<Object>{
@Override
protected Object childValue(Object parentValue) {
return parentValue+"-childValue";
}
}
class StaticThreadLocal {
public static MyInheritableThreadLocal itl = new MyInheritableThreadLocal();
}
class MyThreadX extends Thread{
@Override
public void run() {
try {
for(int i=0;i<5;i++){
System.out.println("MyThreadX=>"+StaticThreadLocal.itl.get());
Thread.sleep(1000);
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
class TestMtl{
public static void main(String[] args) throws InterruptedException {
StaticThreadLocal.itl.set("main");
MyThreadX myThreadX = new MyThreadX();
myThreadX.start();
Thread.sleep(2000);
System.out.println("main=>"+StaticThreadLocal.itl.get());
}
}
执行结果:
MyThreadX=>main-childValue
MyThreadX=>main-childValue
main=>main
MyThreadX=>main-childValue
MyThreadX=>main-childValue
MyThreadX=>main-childValue
它和使用InheritableThreadLocal.set()方法赋值的区别是:
InheritableThreadLocal.set()可以赋任意次新值而重写的childValue方法只会在子线程创建的时候执行一次。
参考书籍:Java多线程编程核心技术(第2版)高洪岩 著