应用
在日常项目中,为了记录一个服务的调用与输出日志,我们通常会使用AOP的方式拦截记录参数,这在平时的问题溯源过程中起到了极大的作用,但在调用链系统应用中大多使用多线程的方式,所以很多链路追踪的组件就应运而生。
ThreadLocal
This class provides thread-local variables. These variables differ from
* their normal counterparts in that each thread that accesses one (via its
* {@code get} or {@code set} method) has its own, independently initialized
* copy of the variable. {@code ThreadLocal} instances are typically private
* static fields in classes that wish to associate state with a thread (e.g.,
* a user ID or Transaction ID).
threadlocal是为了绑定当前线程,并不是为了保证线程安全,而是为了在线程内方便共享变量跨方法的传递,如果跨线程传递其本身实例就比较繁琐了,其副本是可以跨线程传递的,我们可以写一个简单例子看一下
package com.atkk.kk.netty.websocket;
public class ThreadLocalDemo {
public static ThreadLocal<Order> orderThreadLocal = new ThreadLocal<>();
public static void main(String[] args) {
Order order = new Order();
System.out.println(order.hashCode());
orderThreadLocal.set(order);
EntityBussiness1 entityBussiness1 = new EntityBussiness1();
其他线程下是隔离的
new Thread(()->{
EntityBussiness2 entityBussiness2 = new EntityBussiness2();
entityBussiness2.run();
}).start();
entityBussiness1.run();
}
static class EntityBussiness1{
public void run(){
Order order = orderThreadLocal.get();
if(order == null){
System.out.println("threadlocal == null in thread: " + Thread.currentThread().getName());
return;
}
System.out.println(order.hashCode());
}
}
static class EntityBussiness2{
public void run(){
Order order = orderThreadLocal.get();
if(order == null){
System.out.println("threadlocal == null in thread: " + Thread.currentThread().getName());
return;
}
System.out.println(order.hashCode());
}
}
}
控制台输出
205125520
205125520
threadlocal == null in thread: Thread-0
而为了解决父子线程之间私有变量问题,InheritableThreadLocal应运而生。
InheritableThreadLocal
源码
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.
*/
void createMap(Thread t, T firstValue) {
t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
}
}
当在InheritableThreadLocal点击thread跳转时会直接跳转到thread的构造函数
public Thread(ThreadGroup group, Runnable target, String name,
long stackSize, boolean inheritThreadLocals) {
this(group, target, name, stackSize, null, inheritThreadLocals);
}
注意是线程,不是线程池,这个构造函数有些陌生。
还有这里的Entry在后续仍会用到
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
所谓的线程的初始化可能会有些出入
/**
* Allocates a new {@code Thread} object. This constructor has the same
* effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
* {@code (null, null, gname)}, where {@code gname} is a newly generated
* name. Automatically generated names are of the form
* {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
*/
public Thread() {
this(null, null, "Thread-" + nextThreadNum(), 0);
}
传递参数的原因
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
核心代码
/**
* Construct a new map including all Inheritable ThreadLocals
* from given parent map. Called only by createInheritedMap.
*
* @param parentMap the map associated with parent thread.
*/
private ThreadLocalMap(ThreadLocalMap parentMap) {
Entry[] parentTable = parentMap.table;
int len = parentTable.length;
setThreshold(len);
table = new Entry[len];
for (Entry e : parentTable) {
if (e != null) {
@SuppressWarnings("unchecked")
ThreadLocal<Object> key = (ThreadLocal<Object>) 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++;
}
}
}
}
/**
* 构建一个包含所有parentMap中Inheritable ThreadLocals的ThreadLocalMap
* 该函数只被 createInheritedMap() 调用.
*/
private ThreadLocalMap(ThreadLocalMap parentMap) {
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) {
@SuppressWarnings("unchecked")
ThreadLocal<Object> key = (ThreadLocal<Object>) 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++;
}
}
}
}
评论(0)