В системе у меня есть объект - назовем его TaskProcessor
.Он содержит очередь задач, которые выполняются некоторым пулом потоков (ExecutorService
+ PriorityBlockingQueue
). Результат каждой задачи сохраняется в базе данных под некоторым уникальным идентификатором.
Пользователь, который знает этоуникальный идентификатор, может проверить результат этой задачи.Результат может быть в базе данных, но задача также может ожидать выполнения в очереди.В этом случае UserThread
должен дождаться завершения задачи.
Кроме того, допустимы следующие предположения:
Кто-то еще может поставить в очередь Задача на TaskProcessor
и некоторые случайные UserThread
могут получить доступ к результату, если он знает уникальный идентификатор.
UserThread
и TaskProcess
находятся в одном приложении.TaskProcessor
содержит пул потоков, а UserThread
- просто поток сервлетов.
UserThread
должен быть заблокирован при запросе результата, и результат еще не завершен.UserThread
должен быть разблокирован сразу после TaskProcessor
завершения задачи (или задач), сгруппированных по уникальному идентификатору
Моя первая попытка (наивная) состояла в том, чтобы проверить результат взацикливайтесь и спите некоторое время:
// UserThread
while(!checkResultIsInDatabase(uniqueIdentifier))
sleep(someTime)
Но мне это не нравится.Прежде всего, я трачу соединения с базой данных.Более того, если задача будет завершена сразу после сна, то пользователь будет ждать, даже если результат только что появился.
Следующая попытка была основана на ожидании / уведомлении:
//UserThread
while (!checkResultIsInDatabase())
taskProcessor.wait()
//TaskProcessor
... some complicated calculations
this.notifyAll()
Но ятоже не нравитсяЕсли больше UserThreads
будет использовать TaskProcessor
, то они будут без необходимости просыпаться каждый раз, когда будет выполнено какое-то задание, и более того - они будут делать ненужные вызовы базы данных.
Последняя попытка была основана на чем-то, что язвонил waitingRoom
:
//UserThread
Object mutex = new Object();
taskProcessor.addToWaitingRoom(uniqueIdentifier, mutex)
while (!checkResultIsInDatabase())
mutex.wait()
//TaskProcessor
... Some complicated calculations
if (uniqueIdentifierExistInWaitingRoom(taskUniqueIdentifier))
getMutexFromWaitingRoom(taskUniqueIdentifier).notify()
Но, похоже, это небезопасно.Между проверкой базы данных и wait()
задача может быть выполнена (notify()
не будет работать, поскольку UserThread
еще не вызывал wait()
), что может привести к тупику.
Itкажется, что я должен это где-то синхронизировать.Но я боюсь, что это будет не эффективно.Есть ли способ исправить любые мои попытки, сделать их безопасными и эффективными?Или, может быть, есть какой-то другой, лучший способ сделать это?