Java Tomcat, как поставить в очередь только определенный поток HTTP? - PullRequest
1 голос
/ 31 октября 2011

У меня приложение Java без сохранения состояния, развернутое на веб-сервере Tomcat. Из-за характера данных в любой момент времени все http-потоки должны обрабатывать разные ключи (другими словами: все потоки должны обрабатывать разные ключи).

Следовательно, я написал модуль, который ставит в очередь сообщение http, если ключ запроса находится в процессе выполнения (сообщением http до этого). Я продолжу обрабатывать текущую запись http только после завершения предыдущей записи http с тем же ключом.

Я написал простой цикл while с concurrenthashmap, чтобы проверить, выполняется ли какой-либо предыдущий запрос с тем же ключом. Производительность ниже номинальной и наблюдается непредвиденное поведение. Это фрагмент кода:

//This part of code is place inside the servlet 
private static ConcurrentHashMap<String, String> transQueue = new ConcurrentHashMap<String, String>();
private void inQueuePoll(String queueKey) {
   while(transQueue.containsKey(queueKey)){     
      synchronized(this){
         try{
            Thread.sleep(50); // i know this is bad, any idea to improve this?
            logger.trace("Wait for Que Key: "+queueKey + " );

            }catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    transQueue.put(queueKey, "");
}

В конце каждого http-сообщения, в блоке finally, я помещаю: transQueue.remove (queueKey), чтобы убедиться, что я удалил его из таблицы concurrenthashmap. Тем не менее, в своем худшем кошмаре из журнала сервера я заметил, что перед удалением queueKey, еще одной нити HTTP-поста, удается выйти из цикла while и продолжить обработку.

Что-то я сделал неправильно в приведенном выше коде, чтобы "поставить в очередь" поток http?

Также очень ценится любая идея о том, как я могу сделать это лучше.

1 Ответ

0 голосов
/ 01 ноября 2011

Во-первых, если я могу переформулировать ваше дело для ясности. Для любого данного ключа все запросы должны обрабатываться в одном потоке; однако запрос на другие ключи может обрабатываться одновременно с обработкой запроса на первый ключ.

Это кажется мне подходящим для ExecutorService . Я бы сделал вашу карту картой <String, ExecutorService>, где ключом является ключ вашей очереди, а значением является однопоточный исполнитель (который можно получить через Executors.newSingleThreadExecutor () ).

Получив ключ, вы получите ExecutorService с карты и отправите Callable для обработки. Поскольку Executor для этого ключа является однопоточным, вы можете быть уверены, что он будет ожидать обработки предыдущего запроса (запросов) для этого ключа, прежде чем обрабатывать этот. Вызов get будет блокироваться до тех пор, пока не будет выполнена обработка этого запроса.

...