You could try to make use of the Command pattern.
class MyServiceManager {
public void execute(MyServiceTask tasks...) {
// set up everyting
MyService service = this.acquireService();
// execute the submitted tasks
foreach (Task task : tasks)
task.executeWith(service);
// cleanup yourself
service.releaseResources();
}
}
This gives you full control over resource acquisition and release. The caller only submits tasks to your Service, and you yourself are responsible for acquiring and cleaning up resources.
There is a catch, however. The caller can still do this:
MyServiceTask t1 = // some task
manager.execute(t1);
MyServiceTask t2 = // some task
manager.execute(t2);
But you can adress this problem when it arisis. When there are performance problems and you find out that some caller do this, simply show them the proper way and resolve the issue:
MyServiceTask t1 = // some task
MyServiceTask t2 = // some task
manager.execute(t1, t2);
You can make this arbitrarly complex by implementing promises for tasks that are dependent on other tasks, but then releasing stuff also gets more complicated. This is only a starting point.
Async
As has been pointed out in the comments, the above doesn't really work with asynchronous requests. Thats correct. But this can easily be solved in Java 8 with the use of CompleteableFuture, especially CompleteableFuture#supplyAsync
to create the individual futures and CompleteableFuture#allOf
to perfom the release of the resources once all tasks have finished.
Alternatively, one can always use Threads or ExecutorServices to roll their own implementation of Futures/Promises.
AutoCloseable
was made for this exact purpose. – BgrWorker Mar 28 '17 at 14:32AutoCloseable
was made to solve basically the same issue that the OP has created, yes. But that tends to prove Pieter's point. "un-Java" may not have been the best description, however having objects that need to be explicitly closed is a problem. It's such a big problem that a major feature was added to the language to mitigate it. As Pieter suggests, it would be better to restructure the code to follow a pattern that doesn't require a call torelease()
,close()
, or the use of atry-with-resources
block. – aroth Mar 29 '17 at 14:35