Чтобы добавить к принятому ответу Тима и последующий вопрос от pacman, вам нужно быть осторожным при использовании AsyncResponse или аналогичной функции вместе с разъемом NIO.Я не уверен, что Тим имеет в виду, «ваш [асинхронный] сервлет может быть вызван несколько раз за один запрос» ... но если «запрос» ссылается на один «GET», «PUT», «POST»или «УДАЛИТЬ», а затем AFAIK, что приведет к одному вызову соответствующего метода ресурса в вашем сервлете.
Одна проблема, с которой вы можете столкнуться с ThreadLocals и асинхронными ресурсами, - это если поток обработки в асинхронных ресурсах нуждаетсякопия переменной ThreadLocal из цикла обработки событий NIO Thread.Другими словами, цикл событий NIO Thread принимает запрос, затем передает управление вашему асинхронному ресурсу ... затем этот ресурс передает управление дочернему потоку ... затем цикл события NIO Thread может обработать другой запрос ... таклюбые переменные ThreadLocal в цикле событий NIO. Поток может быть растоптан последующим запросом.
Обратите внимание, что для каждого нового запроса также возможно создать новый экземпляр объекта, хранящийся вThreadLocal ... в этом случае каждый новый запрос не будет вытесняться из старых экземпляров, которые были сохранены в том же ThreadLocal во время предыдущих запросов ... но вы должны быть уверены, с каким случаем вы имеете дело ... давайте рассмотрим некоторыеexamples.
Исходный вопрос относится к Spring, поэтому хорошим примером является RequestContextHolder, который имеет ThreadLocal.Допустим, цикл обработки событий NIO имеет имя «http-nio-8080-exec-1» и передает управление ресурсу AsyncResponse, который затем запускает новый поток (с именем «pool-2-thread-3») через исполнителя,Новый поток имеет код, которому нужно что-то из RequestAttributes, чтобы получить ответ для передачи обратно через AsyncResponse.resume ().Поскольку код, выполняющийся в потоке "pool-2-thread-3", должен получить доступ к атрибутам RequestAttributes из "http-nio-8080-exec-1", вам необходимо убедиться в двух вещах:
1)Ваш ресурс получает ссылку на атрибуты RequestAttributes из "http-nio-8080-exec-1" и передает ее в "pool-2-thread-3"
2) Когда "http-nio-8080-exec-1 "принимает новый запрос, создает новую копию RequestAttributes и устанавливает ее в свою ThreadLocal копию для RequestContextHolder для нового запроса (обратите внимание, код Spring работает таким образом, поэтому он безопасен).
Aпротивоположным примером является копия LogCj MDC ThreadLocal карты.В этом случае каждый новый запрос повторно использует одну и ту же карту ..., поэтому небезопасно передавать ссылку на карту из потока событий NIO в поток AsyncResponse ... вам нужно сделать копию карты и передать ее.См. MDCAwareThreadPoolExectutor для примера того, как это сделать.
По сути, вам необходимо проверить каждую переменную ThreadLocal, которую нужно передать из потока событий NIO Thread в ваш поток AsyncResponse.... и посмотреть, безопасно ли просто передать ссылку на исходный объект или вам нужно сделать копию объекта перед установкой копии в переменную ThreadLocal рабочего потока.
Кстати, вот некоторыекод, который объединяет два приведенных выше примера:
public class RequestContextAwareThreadPoolExecutor extends MDCAwareThreadPoolExecutor {
/* ... constructors left out ... */
@Override
public void execute(Runnable runnable) {
super.execute(wrap(runnable, RequestContextHolder.currentRequestAttributes()));
}
Runnable wrap(final Runnable runnable, final RequestAttributes requestAttributes) {
return () -> {
RequestContextHolder.setRequestAttributes(requestAttributes);
try {
runnable.run();
} finally {
RequestContextHolder.resetRequestAttributes();
}
};
}
}
Из вашего ресурса AsyncResponse просто позвоните так:
executor.execute(() -> {
// veryLongOperation() needs to access the RequestAttributes and the MDC
asyncResponse.resume(veryLongOperation());
});