log4j中再次看ThreadLoal用法

[size=large] 关于ThreadLocal坛子里面ThreadLocal的帖子很多,说法也有好多不一致
每次举例都是hibernate里面的session,这周使用log4j做一些东东,发现log4j的代码用这个ThreadLocal可是清晰多了,而且很有意思。[/size]

[size=medium] log4j里的MDC说起,这个是个键值对存储的容器,在里面加你的键值对,在配置文件配置你输出的格式,需要输出的内容时候取里面的键
如:[/size]

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);

配置文件里面
[quote]
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}')
[/quote]

[size=large]这个实例MDC.put那个logger实例也MDC.put,里面不是会很崩溃,会覆盖一些东西,越来越大之类的[/size]

直接上代码:

/*
* 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);
}
}

[size=large]先调用ThreadLocalMap.get()获取,注意此处ThreadLocalMap是log4j自己写的继承自ThreadLocal的子类,但get,set方法还是没有覆盖的。
如下代码所示:[/size]


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();
}

[size=large]Thread t = Thread.currentThread();-->>取出当前线程
ThreadLocalMap map = getMap(t);--->>根据当前线程取出里面的变量return t.threadLocals;[/size]

ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}

[size=large]Thread类里面定义[/size]
ThreadLocal.ThreadLocalMap threadLocals = null;

可以看出ThreadLocalMap是ThreadLocal的一个内部类,不过这个六百多行的内部类确实不容易看
map.getEntry(this)-->> 在map不为空时候,取出里面存放的实体,为什么传this?
到这一步,已经从当前线程 当前对象 这两个纬度锁定到了这个map,对static class ThreadLocalMap这样一个静态内部类来说, 已经可以控制每个线程分配一个独立占用的虚拟内存地带了,如果其它线程要操作这个,就用这两个纬度去获取

[size=large]再理一下这种方式的思路[/size]
[size=medium]
每个线程有一个ThreadLocalMap,这个是在线程本身就定义的,Thread里面有
ThreadLocal.ThreadLocalMap threadLocals = null;

那么每个线程里面可根据当前对象取出里面的实体。[/size]

这个实体看你自己使用什么就可以指定什么,反正是个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);
}


[size=large]log4j使用上述方式,保证调用MDC的线程实例,通过二个纬度确定里面有唯一一份object(hashtable)[/size]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值