为什么 slf4j 记录器有时会打印出父线程,即使代码应该由子线程执行?
Why is slf4j logger sometimes print out parent thread even though the code is suppose to be executed by child thread?
考虑这个例子
@Test
public void test2() throws InterruptedException {
int MAX_ENTRIES = 2;
Map cache = new LinkedHashMap(MAX_ENTRIES+1, .75F, true) {
public boolean removeEldestEntry(Map.Entry eldest) {
return size() > MAX_ENTRIES;
}
};
MyBufferService testService = new MyBufferService("test2");
for (int i = 0; i < 100000; i++) {
testService.putBufferTask(Integer.toString(i));
}
TimeUnit.SECONDS.sleep(1);
}
public class MyBufferService {
private ThreadPoolExecutor executor;
private final Logger LOGGER = LoggerFactory.getLogger(MyBufferService.class);
private final Map cache;
final int MAX_ENTRIES = 1;
public MyBufferService(String buffName) {
executor = new ThreadPoolExecutor(1, // corePoolSize
1, // maximumPoolSize
60, TimeUnit.SECONDS, // keepAlive
new LinkedBlockingQueue<>(10000), // workQueue
new ThreadFactoryBuilder().setNameFormat(buffName + "-MyBufferService-thread-%d").build(), // factory
new ThreadPoolExecutor.CallerRunsPolicy() // rejected execution handler
);
this.cache = new LinkedHashMap(MAX_ENTRIES+1, .75F, true) {
public boolean removeEldestEntry(Map.Entry eldest) {
return size() > MAX_ENTRIES;
}
};
}
private class BufferTask implements Runnable {
private final String mystring;
private final Map cache;
BufferTask(String mystring, Map cache) throws NullPointerException {
this.mystring = mystring;
this.cache = cache;
}
@Override
public void run() {
try {
synchronized (this.cache) {
this.cache.put(this.mystring, "hi");
if (this.cache.size() > 0) {
LOGGER.info("this is size {}", this.cache.size() );
}
}
} catch (Throwable t) {
}
}
}
public void putBufferTask(
String mystring) throws RejectedExecutionException, NullPointerException {
executor.submit(new BufferTask(mystring, this.cache));
}
}
并考虑以下行中的输出片段
LOGGER.info("this is size {}", this.cache.size() );
2018-06-13 18:19:46,760 [INFO] [main] c.t.u.w.$MyBufferService - this is size 1
2018-06-13 18:19:46,761 [INFO] [main] c.t.u.w.$MyBufferService - this is size 1
2018-06-13 18:19:46,761 [INFO] [main] c.t.u.w.$MyBufferService - this is size 1
2018-06-13 18:19:46,761 [INFO] [main] c.t.u.w.$MyBufferService - this is size 1
2018-06-13 18:19:46,761 [INFO] [main] c.t.u.w.$MyBufferService - this is size 1
2018-06-13 18:19:46,761 [INFO] [test2-MyBufferService-thread-0] c.t.u.w.$MyBufferService - this is size 1
2018-06-13 18:19:46,761 [INFO] [test2-MyBufferService-thread-0] c.t.u.w.$MyBufferService - this is size 1
2018-06-13 18:19:46,761 [INFO] [test2-MyBufferService-thread-0] c.t.u.w.$MyBufferService - this is size 1
2018-06-13 18:19:46,761 [INFO] [test2-MyBufferService-thread-0] c.t.u.w.$MyBufferService - this is size 1
我们看到 BufferTask
中的代码被 2 个线程 运行 执行,main
线程和 main
线程中的子线程 MyBufferService-thread-0
我原以为只有子线程在执行任务,但似乎父线程也在执行任务。
为什么会这样?我做错了什么吗?
您将被拒绝的 excecution policy 设置为让来电者 运行 完成任务。这意味着如果任务在 #execute 中被拒绝,则调用线程(即您的情况下的主线程)将 运行 任务,这就是您所看到的。更改该策略或处理 #execute 方法中的异常。
考虑这个例子
@Test
public void test2() throws InterruptedException {
int MAX_ENTRIES = 2;
Map cache = new LinkedHashMap(MAX_ENTRIES+1, .75F, true) {
public boolean removeEldestEntry(Map.Entry eldest) {
return size() > MAX_ENTRIES;
}
};
MyBufferService testService = new MyBufferService("test2");
for (int i = 0; i < 100000; i++) {
testService.putBufferTask(Integer.toString(i));
}
TimeUnit.SECONDS.sleep(1);
}
public class MyBufferService {
private ThreadPoolExecutor executor;
private final Logger LOGGER = LoggerFactory.getLogger(MyBufferService.class);
private final Map cache;
final int MAX_ENTRIES = 1;
public MyBufferService(String buffName) {
executor = new ThreadPoolExecutor(1, // corePoolSize
1, // maximumPoolSize
60, TimeUnit.SECONDS, // keepAlive
new LinkedBlockingQueue<>(10000), // workQueue
new ThreadFactoryBuilder().setNameFormat(buffName + "-MyBufferService-thread-%d").build(), // factory
new ThreadPoolExecutor.CallerRunsPolicy() // rejected execution handler
);
this.cache = new LinkedHashMap(MAX_ENTRIES+1, .75F, true) {
public boolean removeEldestEntry(Map.Entry eldest) {
return size() > MAX_ENTRIES;
}
};
}
private class BufferTask implements Runnable {
private final String mystring;
private final Map cache;
BufferTask(String mystring, Map cache) throws NullPointerException {
this.mystring = mystring;
this.cache = cache;
}
@Override
public void run() {
try {
synchronized (this.cache) {
this.cache.put(this.mystring, "hi");
if (this.cache.size() > 0) {
LOGGER.info("this is size {}", this.cache.size() );
}
}
} catch (Throwable t) {
}
}
}
public void putBufferTask(
String mystring) throws RejectedExecutionException, NullPointerException {
executor.submit(new BufferTask(mystring, this.cache));
}
}
并考虑以下行中的输出片段
LOGGER.info("this is size {}", this.cache.size() );
2018-06-13 18:19:46,760 [INFO] [main] c.t.u.w.$MyBufferService - this is size 1
2018-06-13 18:19:46,761 [INFO] [main] c.t.u.w.$MyBufferService - this is size 1
2018-06-13 18:19:46,761 [INFO] [main] c.t.u.w.$MyBufferService - this is size 1
2018-06-13 18:19:46,761 [INFO] [main] c.t.u.w.$MyBufferService - this is size 1
2018-06-13 18:19:46,761 [INFO] [main] c.t.u.w.$MyBufferService - this is size 1
2018-06-13 18:19:46,761 [INFO] [test2-MyBufferService-thread-0] c.t.u.w.$MyBufferService - this is size 1
2018-06-13 18:19:46,761 [INFO] [test2-MyBufferService-thread-0] c.t.u.w.$MyBufferService - this is size 1
2018-06-13 18:19:46,761 [INFO] [test2-MyBufferService-thread-0] c.t.u.w.$MyBufferService - this is size 1
2018-06-13 18:19:46,761 [INFO] [test2-MyBufferService-thread-0] c.t.u.w.$MyBufferService - this is size 1
我们看到 BufferTask
中的代码被 2 个线程 运行 执行,main
线程和 main
线程中的子线程 MyBufferService-thread-0
我原以为只有子线程在执行任务,但似乎父线程也在执行任务。
为什么会这样?我做错了什么吗?
您将被拒绝的 excecution policy 设置为让来电者 运行 完成任务。这意味着如果任务在 #execute 中被拒绝,则调用线程(即您的情况下的主线程)将 运行 任务,这就是您所看到的。更改该策略或处理 #execute 方法中的异常。