В системе у меня есть объект - пусть назовем его TaskProcessor
. Он содержит очередь задач, которые выполняются некоторым пулом потоков (ExecutorService
+ PriorityBlockingQueue
). Результат каждой задачи сохраняется в базе данных под некоторым уникальным идентификатором.
Пользователь, который знает этот уникальный идентификатор, может проверить результат этой задачи. Результат может быть в базе данных, но задача также может ожидать выполнения в очереди. В этом случае UserThread
должен дождаться завершения задачи.
Кроме того, следующие предположения действительны:
-
Кто-то может поставить задачу в
TaskProcessor
а какой-то случайныйUserThread
может получить доступ к результату, если он знает уникальный идентификатор. -
UserThread
иTaskProcess
находятся в одном приложении.TaskProcessor
содержит пул потоков, аUserThread
- это простоUserThread
Thread сервлета. -
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
еще не UserThread
wait()
), что может привести к взаимоблокировке.
Кажется, мне нужно где-то синхронизировать. Но я боюсь, что это будет не эффективно. Есть ли способ исправить любые мои попытки, сделать их безопасными и эффективными? Или, может быть, есть какой-то другой, лучший способ сделать это?