log(四)——MDC使用

来源:互联网 发布:英语辅导软件三年级 编辑:程序博客网 时间:2024/06/06 06:51

1.MDC put

用MDC的put方法,把需要的context添加到当前线程的context map中。

之前说过,子线程在创建的时候会把父线程中的inheritableThreadLocals变量设置到子线程的inheritableThreadLocals中,而MDC内部是用InheritableThreadLocal实现的,所以自然会把父线程中的上下文带到子线程中。

2.getCopyOfContextMap

对于线程池中的线程来说,这部分线程是可以重用的,但是线程本身只会初始化一次,所以之后重用线程的时候,就不会进行初始化操作了,也就不会有上一段中提到的父线程inheritableThreadLocals拷贝到子线程中的过程了。
这个时候如果还想传递父线程的上下文的话,就要使用getCopyOfContextMap方法。
/**   * Return a copy of the current thread's context map. Returned value may be   * null.   */  public Map getCopyOfContextMap() {    lastOperation.set(READ_OPERATION);    Map<String, String> hashMap = copyOnInheritThreadLocal.get();    if (hashMap == null) {      return null;    } else {      return new HashMap<String, String>(hashMap);    }  }
该方法会把当前线程的context制作一份副本返回。
ExecutorService.execute(new Runnable())的时候,在Runnable构造的时候,用这个方法得到一个Map,保存起来,这时的context是父线程的。
然后在执行run方法的时候,放到MDC中去——子线程的context map中去。
可以自己封装一个AbstractRunnable类,对Runnable的run方法进行一个包装,
public abstract class MdcRunnable implements Runnable {    /**     * 为了线程池中的线程在复用的时候也能获得父线程的MDC中的信息,     * 子线程第一次初始化的时候没事,因为通过InheritableThreadLocal     * 已经可以获得MDC中的内容了     */    private final Map mdcContext = MDC.getCopyOfContextMap();    @Override    public final void run() {        // 线程重用的时候,把父线程中的context map内容带入当前线程的context map中,        // 因为线程已经初始化过了,不会像初始化时那样通过拷贝父线程inheritableThreadLocals到子线程        // 的inheritableThreadLocals操作来完成线程间context map的传递。        // 真正执行到这个run方法的时候,已经到了子线程中了,所以要在初始化的时候用        // MDC.getCopyOfContextMap()来获得父线程contest map,那时候还在父线程域中        if (mdcContext != null) {            MDC.setContextMap(mdcContext);        }        try {            runWithMdc();        } finally {            MDC.clear();        }    }    protected abstract void runWithMdc();}


用户真正需要实现的执行任务的方法是runWithMdc方法。

0 0
原创粉丝点击