log4j中看ThreadLocal用法
来源:互联网 发布:云来网络 编辑:程序博客网 时间:2024/06/06 12:28
关于ThreadLocal的帖子很多,说法也有好多不一致,每次举例都是hibernate里面的session,这周使用log4j做一些东东,发现log4j的代码用这个ThreadLocal可是清晰多了,而且很有意思。
首先从log4j里的MDC说起,这个是个键值对存储的容器,在里面加你的键值对,在配置文件配置你输出的格式,需要输出的内容时候取里面的键
如:
MDC.put("usr_id", usr_id); MDC.put("log_title", "网站访问记录"); MDC.put("log_type", "记录"); MDC.put("log_title", "网站访问记录"); MDC.put("log_datetime", format.format(now)); MDC.put("log_ip", log_ip);
配置文件里面
log4j.appender.project-util-db.sql=insert into user_log (usr_id,log_title,log_category,log_type,log_datetime,log_ip) VALUES ('%X{usr_id}','%X{log_title}','%X{log_type}','%X{log_title}','%X{log_datetime}','%X{log_ip}')
这个实例MDC.put那个logger实例也MDC.put,里面不是会很崩溃,会覆盖一些东西,越来越大之类的
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.log4j; import java.util.Hashtable; import org.apache.log4j.helpers.Loader; import org.apache.log4j.helpers.ThreadLocalMap; /** The MDC class is similar to the {@link NDC} class except that it is based on a map instead of a stack. It provides <em>mapped diagnostic contexts</em>. A <em>Mapped Diagnostic Context</em>, or MDC in short, is an instrument for distinguishing interleaved log output from different sources. Log output is typically interleaved when a server handles multiple clients near-simultaneously. <p><b><em>The MDC is managed on a per thread basis</em></b>. A child thread automatically inherits a <em>copy</em> of the mapped diagnostic context of its parent. <p>The MDC class requires JDK 1.2 or above. Under JDK 1.1 the MDC will always return empty values but otherwise will not affect or harm your application. @since 1.2 @author Ceki Gülcü */ public class MDC { final static MDC mdc = new MDC(); static final int HT_SIZE = 7; boolean java1; Object tlm; private MDC() { java1 = Loader.isJava1(); if(!java1) { tlm = new ThreadLocalMap(); } } /** Put a context value (the <code>o</code> parameter) as identified with the <code>key</code> parameter into the current thread's context map. <p>If the current thread does not have a context map it is created as a side effect. */ static public void put(String key, Object o) { if (mdc != null) { mdc.put0(key, o); } } /** Get the context identified by the <code>key</code> parameter. <p>This method has no side effects. */ static public Object get(String key) { if (mdc != null) { return mdc.get0(key); } return null; } /** Remove the the context identified by the <code>key</code> parameter. */ static public void remove(String key) { if (mdc != null) { mdc.remove0(key); } } /** * Get the current thread's MDC as a hashtable. This method is * intended to be used internally. * */ public static Hashtable getContext() { if (mdc != null) { return mdc.getContext0(); } else { return null; } } /** * Remove all values from the MDC. * @since 1.2.16 */ public static void clear() { if (mdc != null) { mdc.clear0(); } } private void put0(String key, Object o) { if(java1 || tlm == null) { return; } else { Hashtable ht = (Hashtable) ((ThreadLocalMap)tlm).get(); if(ht == null) { ht = new Hashtable(HT_SIZE); ((ThreadLocalMap)tlm).set(ht); } ht.put(key, o); } } private Object get0(String key) { if(java1 || tlm == null) { return null; } else { Hashtable ht = (Hashtable) ((ThreadLocalMap)tlm).get(); if(ht != null && key != null) { return ht.get(key); } else { return null; } } } private void remove0(String key) { if(!java1 && tlm != null) { Hashtable ht = (Hashtable) ((ThreadLocalMap)tlm).get(); if(ht != null) { ht.remove(key); } } } private Hashtable getContext0() { if(java1 || tlm == null) { return null; } else { return (Hashtable) ((ThreadLocalMap)tlm).get(); } } private void clear0() { if(!java1 && tlm != null) { Hashtable ht = (Hashtable) ((ThreadLocalMap)tlm).get(); if(ht != null) { ht.clear(); } } } }
重点看里面的put方法
private void put0(String key, Object o) { if(java1 || tlm == null) { return; } else { Hashtable ht = (Hashtable) ((ThreadLocalMap)tlm).get(); if(ht == null) { ht = new Hashtable(HT_SIZE); ((ThreadLocalMap)tlm).set(ht); } ht.put(key, o); } }
先调用ThreadLocalMap.get()获取,注意此处ThreadLocalMap是log4j自己写的继承自ThreadLocal的子类,但get,set方法还是没有覆盖的。
如下代码所示:
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) return (T)e.value; } return setInitialValue(); }
Thread t = Thread.currentThread();–>>取出当前线程
ThreadLocalMap map = getMap(t);—>>根据当前线程取出里面的变量return t.threadLocals;
ThreadLocalMap getMap(Thread t) { return t.threadLocals; }
Thread类里面定义
ThreadLocal.ThreadLocalMap threadLocals = null;
可以看出ThreadLocalMap是ThreadLocal的一个内部类,不过这个六百多行的内部类确实不容易看
map.getEntry(this)–>> 在map不为空时候,取出里面存放的实体,为什么传this?
到这一步,已经从当前线程 当前对象 这两个纬度锁定到了这个map,对static class ThreadLocalMap这样一个静态内部类来说, 已经可以控制每个线程分配一个独立占用的虚拟内存地带了,如果其它线程要操作这个,就用这两个纬度去获取
再理一下这种方式的思路:
每个线程有一个ThreadLocalMap,这个是在线程本身就定义的,Thread里面有:
ThreadLocal.ThreadLocalMap threadLocals = null;
那么每个线程里面可根据当前对象取出里面的实体。
这个实体看你自己使用什么就可以指定什么,反正是个object,MDC里面指定为hashtable
最终调用
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
log4j使用上述方式,保证调用MDC的线程实例,通过二个纬度确定里面有唯一一份object(hashtable)
- log4j中看ThreadLocal用法
- ThreadLocal用法
- ThreadLocal 用法
- ThreadLocal用法
- ThreadLocal用法
- ThreadLocal用法
- 【log4j】log4j的用法
- Log4j用法
- log4j用法
- Log4J用法
- log4j用法
- Log4j用法
- Log4j用法
- log4j用法
- log4j用法
- log4j用法
- log4j 用法
- log4j用法
- 用static和static方法封装类的例子
- 纯CSS画的基本图形(矩形、圆形、三角形、多边形、爱心、八卦等)
- 获取ip
- SpringMVC注解@RequestParam
- C# 中的委托和事件
- log4j中看ThreadLocal用法
- UVA oj 10055 Hashmat the Brave Warrior(坑题)
- 水水笔-续1(06/01)
- 静态库
- hdu 5402 Travelling Salesman Problem
- iOS学习路线图
- 提取胡数据通过区分管道号分类
- LeetCode-347.Top K Frequent Elements
- mesos解读