上篇说的是ThreadLocal,如果对ThreadLocal足够了解的话,InheritableThreadLocal也很好理解。InheritableThreadLocal类继承于ThreadLocal类,所以它具有ThreadLocal类的特性,但又是一种特殊的ThreadLocal,其特殊性在于InheritableThreadLocal变量值会自动传递给所有子线程,而普通ThreadLocal变量不行,那么子线程是否可以修改InheritableThreadLocal变量值然后反向传递给主线程了,答案是对于引用类型来说,其内部的属性改变是可以传递给主线程的,对于基本数据类型以及String,Integer等包装类型来说是不可以的,原因是子线程的变量来源于父线程变量的浅拷贝,首先来个例子:
package com.lzzl.thread10;
public class Person {
private String name;
private int id;
@Override
public String toString() {
return "Person [name=" + name + ", id=" + id + "]";
}
public Person(){
}
public Person(String name, int id) {
super();
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
package com.lzzl.thread10;
public class MyThreadLocal extends ThreadLocal<Person>{
@Override
protected Person initialValue() {
// TODO Auto-generated method stub
return new Person("初始值",0);
}
}
package com.lzzl.thread10;
public class MyInheritableThreadLocal extends InheritableThreadLocal<Person>{
@Override
protected Person initialValue() {
// TODO Auto-generated method stub
return new Person("in初始值",0);
}
}
package com.lzzl.thread10;
public class Tools {
public static MyThreadLocal t1 = new MyThreadLocal();
public static MyInheritableThreadLocal t2 = new MyInheritableThreadLocal();
}
package com.lzzl.thread10;
public class Run {
public static void main(String[] args) {
Tools.t2.set(new Person("inmain",1));//执行步骤1
new Thread(new Runnable() {
public void run() {
System.out.println("线程A获t2得的值"+Tools.t2.get());//执行步骤4
Tools.t2.get().setName("---main");//执行步骤5,这里修改了存入的变量的属性
System.out.println("线程A修改t2的值");//执行步骤6
System.out.println("线程A获得t2的值"+Tools.t2.get());//执行步骤7
}
},"A").start();
System.out.println("main线程获得t2的值"+Tools.t2.get());//执行步骤2
try {
Thread.sleep(3000);//执行步骤3
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("main线程获得t2的值"+Tools.t2.get());
}
}
输出
线程A获t2得的值Person [name=inmain, id=1]
线程A修改t2的值
main线程获得t2的值Person [name=inmain, id=1]
线程A获得t2的值Person [name=—main, id=1]
main线程获得t2的值Person [name=—main, id=1]
到这里已经看出的子线程修改变量的属性反映到了主线程之中
来看看其原理吧,贴上源代码
public class InheritableThreadLocal<T> extends ThreadLocal<T> {
/**
* Computes the child's initial value for this inheritable thread-local
* variable as a function of the parent's value at the time the child
* thread is created. This method is called from within the parent
* thread before the child is started.
* <p>
* This method merely returns its input argument, and should be overridden
* if a different behavior is desired.
*//这里可以对从父线程得到的变量进行自己的改变
* @param parentValue the parent thread's value
* @return the child thread's initial value
*/
protected T childValue(T parentValue) {
return parentValue;
}
/**
* Get the map associated with a ThreadLocal.
*
* @param t the current thread
*/
ThreadLocalMap getMap(Thread t) {
return t.inheritableThreadLocals;
}
/**
* Create the map associated with a ThreadLocal.
*
* @param t the current thread
* @param firstValue value for the initial entry of the table.
* @param map the map to store.
*/
void createMap(Thread t, T firstValue) {
t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
}
}
public
class Thread implements Runnable {
ThreadLocal.ThreadLocalMap threadLocals = null;
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
if (name == null) {
throw new NullPointerException("name cannot be null");
}
Thread parent = currentThread();//parent为当前线程
SecurityManager security = System.getSecurityManager();
if (g == null) {
/* Determine if it's an applet or not */
/* If there is a security manager, ask the security manager
what to do. */
if (security != null) {
g = security.getThreadGroup();
}
/* If the security doesn't have a strong opinion of the matter
use the parent thread group. */
if (g == null) {
g = parent.getThreadGroup();
}
}
/* checkAccess regardless of whether or not threadgroup is
explicitly passed in. */
g.checkAccess();
/*
* Do we have the required permissions?
*/
if (security != null) {
if (isCCLOverridden(getClass())) {
security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
}
g.addUnstarted();
this.group = g;
this.daemon = parent.isDaemon();
this.priority = parent.getPriority();
this.name = name.toCharArray();
if (security == null || isCCLOverridden(parent.getClass()))
this.contextClassLoader = parent.getContextClassLoader();
else
this.contextClassLoader = parent.contextClassLoader;
this.inheritedAccessControlContext = AccessController.getContext();
this.target = target;
setPriority(priority);
if (parent.inheritableThreadLocals != null)//拷贝父线程的inheritableThreadLocals
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize;
/* Set thread ID */
tid = nextThreadID();
}
static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {
return new ThreadLocalMap(parentMap);
}
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal k, Object v) {
super(k);
value = v;
}
}
private ThreadLocalMap(ThreadLocalMap parentMap) {//拷贝父线程中的map
Entry[] parentTable = parentMap.table;
int len = parentTable.length;
setThreshold(len);
table = new Entry[len];
for (int j = 0; j < len; j++) {
Entry e = parentTable[j];
if (e != null) {
ThreadLocal key = e.get();
if (key != null) {
//这里可以看出来只是进行了浅拷贝,这里就是上面样例中子线程改变变量属性,父线程的
//变量属性改变的原因了
Object value = key.childValue(e.value);
Entry c = new Entry(key, value);
int h = key.threadLocalHashCode & (len - 1);
while (table[h] != null)
h = nextIndex(h, len);
table[h] = c;
size++;
}
}
}
}
}
}