Управление потоками в сервисах Grails
Итак, у меня есть служба, настроенная для импорта большого количества данных из файла, который загружает пользователь. Я хочу, чтобы пользователь мог продолжить работу над сайтом во время обработки файла. Я выполнил это, создав поток.
Thread.start {
//work done here
}
Теперь возникает проблема, что я не хочу, чтобы одновременно выполнялось несколько потоков. Вот что я пробовал:
class SomeService {
Thread thread = new Thread()
def serviceMethod() {
if (!thread?.isAlive()) {
thread.start {
//Do work here
}
}
}
}
Однако это не работает. thread.isAlive()
всегда возвращает false. Любые идеи о том, как я могу это сделать?
Ответы
Ответ 1
Вместо этого я хотел бы использовать Executor
.
import java.util.concurrent.*
import javax.annotation.*
class SomeService {
ExecutorService executor = Executors.newSingleThreadExecutor()
def serviceMethod() {
executor.execute {
//Do work here
}
}
@PreDestroy
void shutdown() {
executor.shutdownNow()
}
}
Использование newSingleThreadExecutor
гарантирует, что задачи выполняются один за другим. Если уже запущена фоновая задача, следующая задача будет поставлена в очередь и начнется, когда закончится работающая задача (serviceMethod
сама по-прежнему будет немедленно возвращаться).
Возможно, вы захотите рассмотреть плагин исполнителя, если ваш "работать здесь" включает доступ к базе данных GORM, поскольку этот плагин настроит соответствующий (например, сеанс Hibernate) для ваших фоновых задач.
Ответ 2
Другой способ сделать это - использовать аннотацию Spring @Async
.
Добавьте в resources.groovy
следующее:
beans = {
xmlns task:"http://www.springframework.org/schema/task"
task.'annotation-driven'('proxy-target-class':true, 'mode':'proxy')
}
Любой метод обслуживания, который вы теперь аннотируете с помощью @Async
, будет выполняться асинхронно, например.
@Async
def reallyLongRunningProcess() {
//do some stuff that takes ages
}
Если вам нужен только один поток для запуска импорта за раз, вы можете сделать что-то вроде этого -
class MyService {
boolean longProcessRunning = false
@Async
def reallyLongRunningProcess() {
if (longProcessRunning) return
try {
longProcessRunning = true
//do some stuff that takes ages
} finally {
longProcessRunning = false
}
}
}