A colleague asked me how one could prevent the execution a long running task on some UI thread (e.g. the thread of a Servlet container or the Swing event dispatching thread) and also how one could prevent the concurrent execution of that same task. So I send him an email containing a small example and decided to place it on my blog to help others struggling with the same issue.
The long running task
The FooService is the service with the long running method ‘foo’.
interface FooService{
void foo();
}
There is no need to add threading logic to the FooService implementation. It can focus purely on the realization of the business process by implementing the business logic. The code should not be infected with concurrency control logic, because it makes testing very hard, and makes code also hard to understand, reuse or change. So this is one of the first potential refactoring I often see in code. I’ll post more about this in ‘Java Concurrency Top 10’.
The execution-service
The FooExecutionService is responsible for executing the FooService and preventing concurrent execution (if the correctly configured executor instance is injected). Personally I prefer to inject the executor instead creating one inside the FooExecutionService, because it makes it hard to test and change/configure.
class FooExecutionService{
private final FooService fooService;
private final Executor executor;
public FooExecutorService(FooService fooService, Executor executor){
this.fooService = fooService;
this.executor = executor;
}
/**
* Starts executing the FooService. This call is asynchronous, so
* won't block.
*
* @throws RejectedExecutionException if the execution
* of foo is not accepted (concurrent/shutdown).
*/
public void start(){
executor.execute(new Task());
}
class Task implements Runnable{
void run(){
try{
fooService.foo();
catch(Exception ex){
log.error("failed to ...", ex);
}
}
}
}
The FooExecutionService could be improved in different ways: it could provide information when a task already is executing. This could be realized by placing a dummy task in the executor and check if the task is rejected. A different solution would be to let the Task publish some information about the status of the current execution. If the task is very long running, and you want to be able to stop the task, you could shutdown the executor by calling the shutdownNow method. This interrupts the worker-threads and if you periodically check the interrupt status of the executing thread while doing to long running call, you can end the execution.
Some Spring configuration
The Executor is injected from the outside by some Spring configuration, i.e.:
<bean id=""fooService" class="FooServiceImpl"/>
<bean id="fooExecutionService" class="FooExecutionService">
<constructor-arg index="0"
ref="fooService"/>
<constructor-arg index="1">
<bean class="java.util.concurrent.ThreadPoolExecutor"
destroy-method="shutdownNow">
<!-- minimal poolsize (only 1 thread) -->
<constructor-arg index="0"
value="1"/>
<!-- maximum poolsize (only 1 thread)-->
<constructor-arg index="1"
value="1"/>
<!-- the timeout (we don't need it) -->
<constructor-arg index="2"
value="0"/>
<!-- the timeunit that belongs to the timeout argument (we don't need it) -->
<constructor-arg index="3">
<bean id="java.util.concurrent.TimeUnit.SECONDS"
class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean"/>
</constructor-arg>
<!-- the workqueue where unprocessed tasks get stored -->
<constructor-arg index="4">
<!-- we don't want any unprocessed work: a worker needs to be available,
or the task gets rejected. -->
<bean class="java.util.concurrent.SynchronousQueue"/>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
If there are multiple long running methods, it would be an idea to extract the creational logic of the executor to a factory method.
The UI-controller
And the FooExecutionService can be hooked up to some controller like this:
class StartFooController extends SomeController{
final FooExecutionService fooExecutionService;
StartFooController(FooExecutionService fooExecutionService){
this.fooExecutionService = fooExecuctionService;
}
String handleRequest(Request request, Response response){
try{
fooExecutionService.start();
return "success";
}catch(RejectedExecutionException ex){
return "alreadyrunningorshuttingdownview";
}
}
}
Prevention of concurrent execution of different tasks
If you want to prevent concurrent execution of different long running methods, you could create a single execution-service for all methods, and share the same executor between the execution of the different tasks: