Debapriyo Majumder:
requisitos
Tengo que ser capaz de desencadenar un trabajo (de larga duración) a través de una llamada POST y volver inmediatamente.
Sólo un hilo puede ejecutar la tarea a la vez.
El trabajo de ser una cara, quiero todos los disparadores futuras de este trabajo para no hacer nada si un puesto de trabajo ya está en marcha.
Código
@RestController
public class SomeTask {
private SomeService someService;
@Autowired
public SomeTask(SomeService someService) {
this.someService = someService;
}
@Async // requirement 1
@RequestMapping(method = RequestMethod.POST, path = "/triggerJob")
public void triggerJob() {
expensiveLongRunningJob();
}
/**
* Synchronized in order to restrict multiple invocations. // requirement 2
*
*/
private synchronized void expensiveLongRunningJob() {
someService.executedJob();
}
}
Pregunta
Con los requisitos de los códigos anteriores 1 y 2 son satisfechos. ¿Cuál es la mejor manera de satisfacer el requisito 3, así (que el nuevo hilo, creado como resultado de una llamada POST, saltarse el método sincronizado y volver de inmediato en caso de fallo adquirir un bloqueo)?
Matthew Timmermans:
La sincronización no es la herramienta adecuada para el trabajo. Puede hacerlo de esta manera:
@RestController
public class SomeTask {
private SomeService someService;
private final AtomicBoolean isTriggered = new AtomicBoolean();
@Autowired
public SomeTask(SomeService someService) {
this.someService = someService;
}
@Async // requirement 1
@RequestMapping(method = RequestMethod.POST, path = "/triggerJob")
public void triggerJob() {
if (!isTriggered.getAndSet(true)) {
try {
expensiveLongRunningJob();
} finally {
isTriggered.set(false);
}
}
}
/**
* only runs once at a time, in the thread that sets isTriggered to true
*/
private void expensiveLongRunningJob() {
someService.executedJob();
}
}