slf4j+logback的MDC原生就支持多线程的困惑
Closed this issue · 5 comments
taotao365s commented
我在验证slf4j+logback的MDC时,是支持在多线程中输出;还需要你这种扩展么?
@Test
public void run32() throws IOException {
String token = UUID.randomUUID().toString();
MDC.put("G_TOKEN", token);
log.debug("token is {}", token);
new Thread(new Runnable() {
@Override
public void run() {
log.debug("thread-2 start");
log.debug("map={}", MDC.getCopyOfContextMap());
new Thread(new Runnable() {
@Override
public void run() {
log.debug("thread-3 start");
log.debug("map={}", MDC.getCopyOfContextMap());
Runnable runable = new Runnable() {
@Override
public void run() {
log.debug("abc");
}
};
ExecutorService executor = Executors.newFixedThreadPool(1);
executor.submit(runable);
}
}).start();
}
}).start();
System.in.read();
MDC.clear();
}
输出
2017/07/20 13:23:15.433 DEBUG [main][7f7f35f0-7adf-4792-810d-0a6c56502b04] com.spy.test.log.MDCTest:39>>token is 7f7f35f0-7adf-4792-810d-0a6c56502b04
2017/07/20 13:23:15.437 DEBUG [Thread-0][7f7f35f0-7adf-4792-810d-0a6c56502b04] com.spy.test.log.MDCTest$1:44>>thread-2 start
2017/07/20 13:23:15.437 DEBUG [Thread-0][7f7f35f0-7adf-4792-810d-0a6c56502b04] com.spy.test.log.MDCTest$1:46>>map={G_TOKEN=7f7f35f0-7adf-4792-810d-0a6c56502b04}
2017/07/20 13:23:15.439 DEBUG [Thread-1][7f7f35f0-7adf-4792-810d-0a6c56502b04] com.spy.test.log.MDCTest$1$1:51>>thread-3 start
2017/07/20 13:23:15.440 DEBUG [Thread-1][7f7f35f0-7adf-4792-810d-0a6c56502b04] com.spy.test.log.MDCTest$1$1:53>>map={G_TOKEN=7f7f35f0-7adf-4792-810d-0a6c56502b04}
2017/07/20 13:23:15.446 DEBUG [pool-2-thread-1][7f7f35f0-7adf-4792-810d-0a6c56502b04] com.spy.test.log.MDCTest$1$1$1:59>>abc
wuwen5 commented
这个测试没有验证线程池的问题哦,这种情况下测试肯定是好的。
线程池在共享的时候,假设第二次调用的时候,如果线程池是新扩展的线程来执行,那么没有问题,如果是复用池中上一次执行完的空闲线程,那么就取不到这次的本地变量值了, 所以第一次执行是正常的。
你可以仔细看下transmittable-thread-local#功能详细介绍
wuwen5 commented
而且你应该是使用的logback-1.1.5以下的版本测试的吧,1.1.5以上的高版本即使子线程测试也是不生效的。
wuwen5 commented
把你的测试代码改成这样就理解了.
static ExecutorService executor = Executors.newFixedThreadPool(1);
@Test
public void run32() throws IOException {
for (int i = 0; i < 2; i++) {
String token = UUID.randomUUID().toString();
MDC.put("G_TOKEN", token);
log.debug("token is {}", token);
new Thread(new Runnable() {
@Override
public void run() {
log.debug("thread-2 start");
log.debug("map={}", MDC.getCopyOfContextMap());
new Thread(new Runnable() {
@Override
public void run() {
log.debug("thread-3 start");
log.debug("map={}", MDC.getCopyOfContextMap());
Runnable runable = new Runnable() {
@Override
public void run() {
log.debug("abc");
}
};
executor.submit(runable);
}
}).start();
}
}).start();
//System.in.read();
MDC.clear();
sleep(1000)
}
sleep(2000)
}
2017-07-20 14:22:47.653|f3bd42c3-9e9f-4fb2-a1db-fec6e8481689|DEBUG|run32|com.Test:45|main|token is f3bd42c3-9e9f-4fb2-a1db-fec6e8481689|""
2017-07-20 14:22:47.670|f3bd42c3-9e9f-4fb2-a1db-fec6e8481689|DEBUG|run|com.Test$1:50|Thread-14|thread-2 start|""
2017-07-20 14:22:47.672|f3bd42c3-9e9f-4fb2-a1db-fec6e8481689|DEBUG|run|com.Test$1:52|Thread-14|map={G_TOKEN=f3bd42c3-9e9f-4fb2-a1db-fec6e8481689}|""
2017-07-20 14:22:47.687|f3bd42c3-9e9f-4fb2-a1db-fec6e8481689|DEBUG|run|com.Test$1$2:57|Thread-15|thread-3 start|""
2017-07-20 14:22:47.688|f3bd42c3-9e9f-4fb2-a1db-fec6e8481689|DEBUG|run|com.Test$1$2:59|Thread-15|map={G_TOKEN=f3bd42c3-9e9f-4fb2-a1db-fec6e8481689}|""
2017-07-20 14:22:47.697|f3bd42c3-9e9f-4fb2-a1db-fec6e8481689|DEBUG|run|com.Test$1$2$3:65|pool-1-thread-1|abc|""
2017-07-20 14:22:48.676|df1871aa-9689-4125-b778-4f69b092cac0|DEBUG|run32|com.Test:45|main|token is df1871aa-9689-4125-b778-4f69b092cac0|""
2017-07-20 14:22:48.677|df1871aa-9689-4125-b778-4f69b092cac0|DEBUG|run|com.Test$1:50|Thread-16|thread-2 start|""
2017-07-20 14:22:48.678|df1871aa-9689-4125-b778-4f69b092cac0|DEBUG|run|com.Test$1:52|Thread-16|map={G_TOKEN=df1871aa-9689-4125-b778-4f69b092cac0}|""
2017-07-20 14:22:48.679|df1871aa-9689-4125-b778-4f69b092cac0|DEBUG|run|com.Test$1$2:57|Thread-17|thread-3 start|""
2017-07-20 14:22:48.679|df1871aa-9689-4125-b778-4f69b092cac0|DEBUG|run|com.Test$1$2:59|Thread-17|map={G_TOKEN=df1871aa-9689-4125-b778-4f69b092cac0}|""
2017-07-20 14:22:48.680|f3bd42c3-9e9f-4fb2-a1db-fec6e8481689|DEBUG|run|com.Test$1$2$3:65|pool-1-thread-1|abc|""
+ 2017-07-20 14:22:48.679|df1871aa-9689-4125-b778-4f69b092cac0|DEBUG|run|com.Test$1$2:59|Thread-17|map={G_TOKEN=df1871aa-9689-4125-b778-4f69b092cac0}|""
- 2017-07-20 14:22:48.680|f3bd42c3-9e9f-4fb2-a1db-fec6e8481689|DEBUG|run|com.Test$1$2$3:65|pool-1-thread-1|abc|""
taotao365s commented
@wuwen5 好的,多谢指正,我再细看一下
Qsimple commented
早上过来想了下,简单粗暴点在Runnable上再封装一个Runnable就好了,我在学习学习TTL的代码吧
public class MDCTask implements Runnable{
private final Map<String, String> parentMDCMap;
private final Runnable task;
@Override
public void run() {
MDC.setContextMap(parentMDCMap);
task.run();
MDC.clear();
}
public static MDCTask getMDCTask(final Runnable task)
{
Map<String, String> parentMDCMap = MDC.getCopyOfContextMap();
return new MDCRunnableFactory(task, parentMDCMap);
}
private MDCRunnableFactory(final Runnable task, Map<String, String> parentMDCMap)
{
this.parentMDCMap = parentMDCMap;
this.task = task;
}
}