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.
AutoCloseablewas made for this exact purpose.