/*
* Copyright (c) 1998, 2004, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package com.hanlin.fadp;
import java.lang.ref.*;
/**
* This class extends ThreadLocal to provide inheritance of values
* from parent thread to child thread: when a child thread is created, the
* child receives initial values for all inheritable thread-local variables
* for which the parent has values. Normally the child's values will be
* identical to the parent's; however, the child's value can be made an
* arbitrary function of the parent's by overriding the childValue
* method in this class.
*
*
Inheritable thread-local variables are used in preference to
* ordinary thread-local variables when the per-thread-attribute being
* maintained in the variable (e.g., User ID, Transaction ID) must be
* automatically transmitted to any child threads that are created.
*
* @author Josh Bloch and Doug Lea
* @see ThreadLocal
* @since 1.2
*/
public class InheritableThreadLocal
/**
* 这个方法留给子类实现
*
* @param parentValue the parent thread's value
* @return the child thread's initial value
*/
protected T childValue(T parentValue) {
return parentValue;
}
/**
* 重写getMap方法,返回的是Thread的inheritableThreadLocals引用
*
* @param t the current thread
*/
ThreadLocalMap getMap(Thread t) {
return t.inheritableThreadLocals;
}
/**
* 重写createMap方法,构造的ThreadLocalMap会传给Thread的inheritableThreadLocals 变量
*
* @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);
}
}
它是如何实现父子线程间 ThreadLocal 传递的了?
首先,重写了 getMap 和 createMap 方法,因为 ThreadLocal 在执行 set 方法或者 get 方法的时候,会用到.
是不是发现了啥?这里使用的是 inheritableThreadLocals,而不再是 ThreadLocal 中的 threadLocals.
再看 Thread 类的 init 方法:
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc) {
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name.toCharArray();
Thread parent = currentThread();
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();
if (security == null || isCCLOverridden(parent.getClass()))
this.contextClassLoader = parent.getContextClassLoader();
else
this.contextClassLoader = parent.contextClassLoader;
this.inheritedAccessControlContext =
acc != null ? acc : AccessController.getContext();
this.target = target;
setPriority(priority);
// 这里 inheritableThreadLocals 将不再为空,ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); 语句会把父类中的 ThreadLocal 中的值拷贝一份到子类中.
if (parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize;
/* Set thread ID */
tid = nextThreadID();
}
说明:父子线程 ThreadLocal 在拷贝的时候,拷贝的是引用,也就是说如果父线程修改了 ThreadLocal 中的某个对象,那么子线程中 ThreadLocal 的值也会跟着变.
理论分析:
测试:
package com.hanlin.fadp;
public class InheritableThreadLocalTest {
static class Person{
String name;
public Person(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
public static ThreadLocal
static CountDownLatch latch = new CountDownLatch(1);
public static void main(String args[]) throws InterruptedException {
Person tom = new Person("tom");
inheritableThreadLocal.set(tom);
new Thread(new Runnable() {
@Override
public void run() {
try {
Person p = inheritableThreadLocal.get();
p.setName("sdsds");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("子线程
latch.countDown();
}
}, "AAAAA").start();
System.out.println("父线程
Thread.sleep(1000);
// Person p = inheritableThreadLocal.get();
// p.setName("sdsds");
// inheritableThreadLocal.set(p);
latch.await();
System.out.println("父线程
}
}
结果: